Program Listing for File sycl.hpp

Return to documentation for file (camp/resource/sycl.hpp)

/*
Copyright (c) 2016-18, Lawrence Livermore National Security, LLC.
Produced at the Lawrence Livermore National Laboratory
Maintained by Tom Scogland <scogland1@llnl.gov>
CODE-756261, All rights reserved.
This file is part of camp.
For details about use and distribution, please read LICENSE and NOTICE from
http://github.com/llnl/camp
*/

#ifndef __CAMP_SYCL_HPP
#define __CAMP_SYCL_HPP

#include "camp/config.hpp"

#ifdef CAMP_ENABLE_SYCL

#include "camp/defines.hpp"
#include "camp/resource/event.hpp"
#include "camp/resource/platform.hpp"

#include <CL/sycl.hpp>

#include <map>
#include <array>
#include <mutex>

using namespace cl;

namespace camp
{
namespace resources
{
  inline namespace v1
  {

    class SyclEvent
    {
    public:
      SyclEvent(sycl::queue *qu) { m_event = sycl::event(); }
      bool check() const { return true; }
      void wait() const { getSyclEvent_t().wait(); }
      sycl::event getSyclEvent_t() const { return m_event; }

    private:
      sycl::event m_event;
    };

    class Sycl
    {
      static sycl::queue *get_a_queue(sycl::context &syclContext,
                                      int num,
                                      bool useContext)
      {
        static sycl::gpu_selector gpuSelector;
        static sycl::property_list propertyList =
            sycl::property_list(sycl::property::queue::in_order());
        static sycl::context privateContext;
        static sycl::context *contextInUse = NULL;
        static std::map<sycl::context *, std::array<sycl::queue, 16>> queueMap;


        static std::mutex m_mtx;
        m_mtx.lock();

        // User passed a context, use it
        if (useContext) {
          contextInUse = &syclContext;

          if (queueMap.find(contextInUse) == queueMap.end()) {
            queueMap[contextInUse] = {
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList)};
          }
        } else {  // User did not pass context, use last used or private one
          if (contextInUse == NULL) {
            contextInUse = &privateContext;
            queueMap[contextInUse] = {
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList),
                sycl::queue(*contextInUse, gpuSelector, propertyList)};
          }
        }
        m_mtx.unlock();

        static int previous = 0;

        static std::once_flag m_onceFlag;
        if (num < 0) {
          m_mtx.lock();
          previous = (previous + 1) % 16;
          m_mtx.unlock();
          return &queueMap[contextInUse][previous];
        }

        return &queueMap[contextInUse][num % 16];
      }

    public:
      Sycl(int group = -1)
      {
        sycl::context temp;
        qu = get_a_queue(temp, group, false);
      }

      Sycl(sycl::context &syclContext, int group = -1)
          : qu(get_a_queue(syclContext, group, true))
      {
      }

      // Methods
      Platform get_platform() const { return Platform::sycl; }
      static Sycl get_default()
      {
        static Sycl h;
        return h;
      }
      SyclEvent get_event() { return SyclEvent(get_queue()); }
      Event get_event_erased() { return Event{SyclEvent(get_queue())}; }
      void wait() { qu->wait(); }
      void wait_for(Event *e)
      {
        auto *sycl_event = e->try_get<SyclEvent>();
        if (sycl_event) {
          (sycl_event->getSyclEvent_t()).wait();
        } else {
          e->wait();
        }
      }

      // Memory
      template <typename T>
      T *allocate(size_t size, MemoryAccess ma = MemoryAccess::Device)
      {
        T *ret = nullptr;
        if (size > 0) {
          ret = sycl::malloc_shared<T>(size, *qu);
          switch (ma) {
            case MemoryAccess::Unknown:
            case MemoryAccess::Device:
              ret = sycl::malloc_device<T>(size, *qu);
              break;
            case MemoryAccess::Pinned:
              ret = sycl::malloc_host<T>(size, *qu);
              break;
            case MemoryAccess::Managed:
              ret = sycl::malloc_shared<T>(size, *qu);
              break;
          }
        }
        return ret;
      }
      void *calloc(size_t size, MemoryAccess ma = MemoryAccess::Device)
      {
        void *p = allocate<char>(size, ma);
        this->memset(p, 0, size);
        return p;
      }
      void deallocate(void *p, MemoryAccess ma = MemoryAccess::Device) { sycl::free(p, *qu); }
      void memcpy(void *dst, const void *src, size_t size)
      {
        if (size > 0) {
          qu->memcpy(dst, src, size).wait();
        }
      }
      void memset(void *p, int val, size_t size)
      {
        if (size > 0) {
          qu->memset(p, val, size).wait();
        }
      }

      sycl::queue *get_queue() { return qu; }

    private:
      sycl::queue *qu;
    };

  }  // namespace v1
}  // namespace resources
}  // namespace camp
#endif  //#ifdef CAMP_ENABLE_SYCL

#endif /* __CAMP_SYCL_HPP */