ERROR: implicit capture of 'this' is not allowed for kernel functions, SYCL, DPCPP
ERROR: implicit capture of 'this' is not allowed for kernel functions, SYCL, DPCPP
我尝试编写一种“映射”class,它通过一些指定目标类型的参数(CPU 或 GPU/Accelerator)包装 OneAPI 调用以隐藏硬件定位问题。
map,通过并行for将代码指向SYCL内核或TBB实现map操作。
它以设备类型、CPU 或 GPU 以及函数作为参数,并应用于集合中的所有项目。
但是在内核函数中,我有一个错误,不允许隐式捕获。我不明白我的错误是什么。
这是我的代码:
#include <CL/sycl.hpp>
#include <iostream>
#include <tbb/tbb.h>
#include <tbb/parallel_for.h>
#include <vector>
#include <string>
#include <queue>
#include<tbb/blocked_range.h>
#include <tbb/global_control.h>
using namespace std;
using namespace cl::sycl;
using namespace tbb;
template<typename Tin, typename Tout>
class Map {
private:
function<Tout(Tin)> fun;
string device_type;
public:
Map() {}
Map(function<Tout(Tin)> f):fun(f) {}
void f(function<Tout(Tin)> ff) {
fun = ff;
}
void set_device(string dev) {
device_type = dev;
}
vector<Tout> operator()(vector<Tin>& v) {
device *my_dev = new device();
if(device_type == "cpu"){
if(my_dev->is_cpu()) {
vector<Tout> r(0);
tbb::parallel_for(tbb::blocked_range<Tin>(0, v.size()),
[&](tbb::blocked_range<Tin> t) {
for (int index = t.begin(); index < t.end(); ++index){
r[index] = fun(v[index]);
}
});
return r;
}
}else if(device_type == "gpu"){
if(my_dev->is_gpu()) {
vector<Tout> r(v.size());
sycl::queue gpuQueue{gpu_selector()};
sycl::range<1> n_item{v.size()};
sycl::buffer<Tin, 1> in_buffer(&v[0], n_item);
sycl::buffer<Tout, 1> out_buffer(&r[0], n_item);
gpuQueue.submit([&](sycl::handler& h){
//local copy of fun
//auto f = fun;
sycl::accessor in_accessor(in_buffer, h, sycl::read_only);
sycl::accessor out_accessor(out_buffer, h, sycl::write_only);
h.parallel_for(n_item, [=](sycl::id<1> index) {
out_accessor[index] = fun(in_accessor[index]);
});
}).wait();
return r;
}
}
}
};
int main(int argc, char *argv[]) {
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();
string dev_type = argv[1];
Map <int,int> m(f);
m.set_device(dev_type);
auto r = m(v);
for(auto &e:r) {
cout << e << "\n";
}
return 0;
}
当我在 Eclipse 的控制台中检查问题时,它显示了这个错误:
1- 内核函数
不允许隐式捕获 'this'
您正在尝试访问内核中的 fun
,Map
的成员变量。在 C++ 中使用 this
指针访问成员变量。 Lambda 在 C++ 中默认不捕获 this 指针,因此出现错误消息。
然而,即使您要在内核中捕获 this
,它也不会工作,因为 this
将指向通常无法在设备上访问的主机内存。
一个非常简单的修复方法通常是在内核中使用本地副本:
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 开始,您还可以通过复制捕获 class:[*this](...){...}
.
您的代码更根本的问题是 SYCL 规范不允许在设备代码中使用 std::function
。在某些情况下,对于某些 SYCL 实现,它可能会起作用(例如,对于主机后端),但这是一个扩展。问题是 std::function
的实现通常使用设备不支持的机制来进行类型擦除,例如动态多态性。
一种解决方案可能是在 class 模板参数中包含函数类型,而不是使用 std::function
.
我尝试编写一种“映射”class,它通过一些指定目标类型的参数(CPU 或 GPU/Accelerator)包装 OneAPI 调用以隐藏硬件定位问题。 map,通过并行for将代码指向SYCL内核或TBB实现map操作。 它以设备类型、CPU 或 GPU 以及函数作为参数,并应用于集合中的所有项目。 但是在内核函数中,我有一个错误,不允许隐式捕获。我不明白我的错误是什么。 这是我的代码:
#include <CL/sycl.hpp>
#include <iostream>
#include <tbb/tbb.h>
#include <tbb/parallel_for.h>
#include <vector>
#include <string>
#include <queue>
#include<tbb/blocked_range.h>
#include <tbb/global_control.h>
using namespace std;
using namespace cl::sycl;
using namespace tbb;
template<typename Tin, typename Tout>
class Map {
private:
function<Tout(Tin)> fun;
string device_type;
public:
Map() {}
Map(function<Tout(Tin)> f):fun(f) {}
void f(function<Tout(Tin)> ff) {
fun = ff;
}
void set_device(string dev) {
device_type = dev;
}
vector<Tout> operator()(vector<Tin>& v) {
device *my_dev = new device();
if(device_type == "cpu"){
if(my_dev->is_cpu()) {
vector<Tout> r(0);
tbb::parallel_for(tbb::blocked_range<Tin>(0, v.size()),
[&](tbb::blocked_range<Tin> t) {
for (int index = t.begin(); index < t.end(); ++index){
r[index] = fun(v[index]);
}
});
return r;
}
}else if(device_type == "gpu"){
if(my_dev->is_gpu()) {
vector<Tout> r(v.size());
sycl::queue gpuQueue{gpu_selector()};
sycl::range<1> n_item{v.size()};
sycl::buffer<Tin, 1> in_buffer(&v[0], n_item);
sycl::buffer<Tout, 1> out_buffer(&r[0], n_item);
gpuQueue.submit([&](sycl::handler& h){
//local copy of fun
//auto f = fun;
sycl::accessor in_accessor(in_buffer, h, sycl::read_only);
sycl::accessor out_accessor(out_buffer, h, sycl::write_only);
h.parallel_for(n_item, [=](sycl::id<1> index) {
out_accessor[index] = fun(in_accessor[index]);
});
}).wait();
return r;
}
}
}
};
int main(int argc, char *argv[]) {
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();
string dev_type = argv[1];
Map <int,int> m(f);
m.set_device(dev_type);
auto r = m(v);
for(auto &e:r) {
cout << e << "\n";
}
return 0;
}
当我在 Eclipse 的控制台中检查问题时,它显示了这个错误:
1- 内核函数
不允许隐式捕获 'this'您正在尝试访问内核中的 fun
,Map
的成员变量。在 C++ 中使用 this
指针访问成员变量。 Lambda 在 C++ 中默认不捕获 this 指针,因此出现错误消息。
然而,即使您要在内核中捕获 this
,它也不会工作,因为 this
将指向通常无法在设备上访问的主机内存。
一个非常简单的修复方法通常是在内核中使用本地副本:
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 开始,您还可以通过复制捕获 class:[*this](...){...}
.
您的代码更根本的问题是 SYCL 规范不允许在设备代码中使用 std::function
。在某些情况下,对于某些 SYCL 实现,它可能会起作用(例如,对于主机后端),但这是一个扩展。问题是 std::function
的实现通常使用设备不支持的机制来进行类型擦除,例如动态多态性。
一种解决方案可能是在 class 模板参数中包含函数类型,而不是使用 std::function
.