ОШИБКА: неявный захват this недопустим для функций ядра, SYCL, DPCPP

Я пытаюсь написать своего рода класс «карты», который обертывает вызовы OneAPI, скрывая проблемы с аппаратным нацеливанием, с помощью некоторого параметра, указывающего тип цели (ЦП или графический процессор / ускоритель). Карта направляет код в ядро ​​SYCL или в TBB для реализации операции сопоставления через параллельный для. Он принимает в качестве параметров тип устройства, CPU или GPU, а также функцию и применяется ко всем элементам в коллекции. Но в функции ядра у меня есть ошибка, неявный захват которой недопустим. Я не могу понять, в чем моя ошибка. это мой код:

      #include <CL/sycl.hpp>
#include <iostream>
#include <tbb/tbb.h>
#include <tbb/parallel_for.h>
#include <vector>
#include <string>
#include <queue>
#include <CL/sycl/handler.hpp>

using namespace std;
using namespace cl::sycl;
using namespace tbb;

template<typename Tin, typename Tout>
class Map {
private:
    function<Tout(Tin)> fun;
    //cl::sycl::device device_type;
public:
    Map() {}
    Map(function<Tout(Tin)> f):fun(f) {}
    //Map(cl::sycl::device d): device_type(d){}
    cl::sycl::device device_type;
    void f(function<Tout(Tin)> ff) {
        fun = ff;
       }
    void d(cl::sycl::device dd){
        device_type = dd;
    }


    vector<Tout> operator()(vector<Tin>& v) {
        cl::sycl::device my_dev = cl::sycl::device(device_type.get());
        //my_dev->is_cpu()
        if(my_dev.is_cpu()) {
            vector<Tout> r(0);
            tbb::parallel_for(tbb::blocked_range<Tin>(0, v.size()), [&](Tin &t) {
                r.push_back(fun(t));
            });
           return r;
         }
        if(my_dev.is_gpu()) {
            //
            vector<Tout> r(v.size());
            cl::sycl::queue gpuQueue{cl::sycl::device(cl::sycl::gpu_selector())};
            //sycl::range<1> n_item{v.size()};
            //cl::sycl::buffer<Tin, 1> in_buffer(&v[0], range<1>(v.size()));
            cl::sycl::buffer<Tin, 1> in_buffer(&v[0], range<1>(v.size()));
            cl::sycl::buffer<Tout, 1> out_buffer(&r[0], range<1>(v.size()));
            gpuQueue.submit([&](sycl::handler &h){
                constexpr auto sycl_read = cl::sycl::access::mode::read;
                constexpr auto sycl_write = cl::sycl::access::mode::write;
                auto in_accessor = in_buffer.template get_access<sycl_read>(h);
                auto out_accessor = out_buffer.template get_access<sycl_write>(h);
                h.parallel_for(range<1>(v.size()), [=](id<1> index) {
                    out_accessor[index]= fun(in_accessor[index]);
                }
                );
            });
            return r;
         }

    }
};

int main() {

    cout << "success\n";
    vector<int> v = {1,2,3,4,5,6,7,8};
    auto f = [](int x){return (++x);};
    sycl::device dev = sycl::cpu_selector().select_device();
    Map <int,int> m(f);
    m.device_type = dev;
    auto r = m(v);
    for(auto &e:r) {
        cout << e << "\n";
    }

  return 0;
}

Когда я проверяю Проблемы в консоли Eclipse, он показывает мне эти три ошибки:

1- неявный захват 'this' не разрешен для функций ядра
2- make: *** [subdir.mk:20: main.o] Ошибка 13- нет функции сопоставления для вызова объекта типа 'const (lambda at ../main.cpp:37:60)'

1 ответ

Вы пытаетесь получить доступ в вашем ядре переменная-член . Доступ к переменным-членам в C++ осуществляется с помощью указателя. Лямбды не захватывают указатель this по умолчанию в C++, отсюда и сообщение об ошибке.

Однако, даже если бы вы выполняли захват в своем ядре, это не сработало бы, потому что будет указывать на память хоста, которая обычно недоступна на устройстве.

Одно очень простое решение для этого обычно - просто использовать локальные копии в вашем ядре:

      class X {
  void run(sycl::queue& q){
    q.submit([&](sycl::handler& cgh){
      int local_var = var; // Note: This can also be expressed using the lambda capture list
      cgh.parallel_for(..., [=](...){ /* use local_var here*/});
    });
  }

  int var;
};

Начиная с C++ 17, вы также можете просто скопировать класс: .

Более фундаментальная проблема с вашим кодом заключается в том, что спецификация SYCL не позволяет использовать внутренний код устройства. В некоторых случаях и для некоторых реализаций SYCL это может работать (например, для серверных модулей хоста), но это расширение. Проблема в том, что реализация обычно использует механизмы, которые не могут поддерживаться устройством для стирания типов, такие как динамический полиморфизм.

Одним из решений может быть включение типа функции в аргументы шаблона класса вместо использования .

Другие вопросы по тегам