我正在尝试为我正在从事的 SYCL 项目采用 OOP 软件设计策略。
我让我的代码在其 C++ 版本中运行,然后我尝试将其转换为 SYCL,同时尝试使代码可维护和可重用。
我将代码转换为 SYCL,并删除了 C++ 中所有不支持的功能,例如堆内存分配、递归和虚函数。
在编译代码时,遇到以下错误消息:
In file included from sycl_class_test.cpp:1:
In file included from /opt/intel/oneapi/compiler/2023.1.0/linux/bin-llvm/../include/sycl/sycl.hpp:11:
In file included from /opt/intel/oneapi/compiler/2023.1.0/linux/bin-llvm/../include/sycl/accessor.hpp:28:
In file included from /opt/intel/oneapi/compiler/2023.1.0/linux/bin-llvm/../include/sycl/image.hpp:18:
/opt/intel/oneapi/compiler/2023.1.0/linux/bin-llvm/../include/sycl/types.hpp:2443:3: error: static assertion failed due to requirement 'is_device_copyable<MyClass<10>, void>::value || detail::IsDeprecatedDeviceCopyable<MyClass<10>, void>::value': The specified type is not device copyable
static_assert(is_device_copyable<FieldT>::value ||
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
错误信息对于定位问题的作用不大,所以不知道需要修改什么。
我使用一个简单的类示例重现了该错误:
在代码中,我的目标是维护以下功能:
对其内在成员变量执行操作的类。
能够操作不同大小的对象,这就是我在课堂上使用模板的原因。
代码附在下面。
#include <iostream>
#include <vector>
#include <array>
template <std::size_t N>
class MyClass {
public:
MyClass(std::array<float,N> a, std::array<float,N> b)
{
for (std::size_t i = 0; i < N; i++) {
_a[i] = a[i];
_b[i] = b[i];
}
}
float addValue(int i) const {
if(i >= N || i >= N)
//throw std::runtime_error("Index out of bounds");
return 0;
return _a[i] + _b[i];
}
void modifyAValue(int i, float b) {
if(i>=N)
return;
_a[i] = b;
}
void modifyBValue(int i, float b) {
if(i>=N)
return;
_b[i] = b;
}
MyClass(const MyClass& other) {
for (std::size_t i = 0; i < N; i++) {
_a[i] = other._a[i];
_b[i] = other._b[i];
}
}
private:
std::array<float, N> _a;
std::array<float, N> _b;
//size_t _sizeA;
//size_t _sizeB;
};
int main() {
// Create a SYCL queue
sycl::queue myQueue;
// Create an instance of MyClass
int N = 10;
std::array<float,10> a {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::array<float,10> b {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
MyClass<10> myObject(a, b);
std::vector<int> input = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
std::vector<float> result(input.size());
// Create a SYCL buffer to hold the result
sycl::buffer<float, 1> resultBuffer(result.data(), sycl::range<1>(input.size()));
sycl::buffer<int, 1> inputBuffer(input.data(), sycl::range<1>(input.size()));
// Submit a SYCL kernel
myQueue.submit([&](sycl::handler& cgh) {
auto resultAcc = resultBuffer.template get_access<sycl::access::mode::write>(cgh);
auto inputAcc = inputBuffer.template get_access<sycl::access::mode::read>(cgh);
cgh.parallel_for<class MyKernel>(
sycl::range<1>(input.size()),
[=](sycl::id<1> idx) {
// Call a member function on the instance of MyClass
resultAcc[idx] = myObject.addValue(inputAcc[idx]);
}
);
});
// Wait for the kernel to complete and get the result
myQueue.wait();
// Print the result (accumulated sum)
float sum = 0.0f;
for (float val : result) {
std::cout << val << std::endl;
sum += val;
}
std::cout << "Result: " << sum << std::endl;
return 0;
} ```cpp
SYCL 对放入缓冲区的类型非常严格,因为它们可能需要复制到设备。一旦您创建了非 Pod 类型,您就必须考虑3.13.1 设备可复制,它规定了可以复制到设备的内容。要实现设备可复制,您的课程必须满足一组要求:
- 应用程序将特征 is_device_copyable_v 定义为 true;
- 类型 T 至少有一个符合条件的复制构造函数、移动构造函数、复制赋值运算符或移动赋值运算符;
- 每个符合条件的复制构造函数、移动构造函数、复制赋值运算符和移动赋值运算符都是公共的;
- 在对 T 类型的对象进行设备间传输时,每个符合条件的复制构造函数、移动构造函数、复制赋值运算符和移动赋值运算符的效果与对象的按位复制相同;
- T 类型有一个公共的非删除析构函数;
- 析构函数在设备上执行时没有任何效果。
您的班级似乎满足除第一个要求之外的所有要求:
应用程序将特征 is_device_copyable_v 定义为 true;
由于这是自定义类型,因此您必须手动指定。这如4.12.3 所示。 is_device_copyable 类型 Trait 部分。你必须做:
template<>
struct sycl::is_device_copyable<MyClass> : std::true_type {};
为您的自定义类别专门化此特征。在同一个文件中执行此操作,以便人们可以包含它并在任何地方使用它。