在 Cuda 内核中使用 C++ 对象和 class 成员
Using c++ objects and class members inside a Cuda kernel
我是 C++ 新手,尤其是 Cuda 计算工具。我正在尝试使用 Cuda 在 GPU 上并行化我的代码,出于我的目的,有必要能够从 class 创建对象或至少从内核调用它们的成员。
首先是我的 class:
的定义
//Header
#pragma once
#include<cuda.h>
#include<cuda_runtime.h>
#include<cuda_runtime_api.h>
#include<stdio.h>
#include<iostream>
class Ding
{
private:
int index;
double vector_1[100];
double vector_2[100];
double prop;
public:
__host__ __device__ Ding(int);
__host__ __device__ ~Ding();
__device__ void calculate_stuff(double, int);
__device__ double get_prop();
};
//Source
#include "Ding.h"
#include <math.h>
__host__ __device__ Ding::Ding(int ind) {
index = ind;
prop = 1;
for (int ii = 0; ii < 100; ii++) {
vector_1[ii] = (4 * ii + ind) / (ind + ii + 1);
vector_2[ii] = (-2.14 * ii + ind) / (2*ind + ii + 1);
}
}
__host__ __device__ Ding::~Ding() {};
__device__ void Ding::calculate_stuff(double coeff, int N) {
prop = 1;
for (int ii = 0; ii < N; ii++) {
for (int jj = 0; jj < 100; jj++) {
prop += pow(-1, ii) * vector_1[jj] * vector_2[jj]*coeff;
}
}
}
__device__ double Ding::get_prop() {
return prop;
}
如您所见,除了进行了一些无意义的计算外,没有什么特别的,因为这只能作为我如何使用 Cuda 获得此代码 运行 的示例。
现在这是主要的源文件:
#include<cuda.h>
#include<cuda_runtime.h>
#include<cuda_runtime_api.h>
#include "device_launch_parameters.h"
#include<stdio.h>
#include<iostream>
#include "Ding.h"
using namespace std;
__global__ void some_kernel(double *vec_a, Ding* teil, int size) {
int ii = blockIdx.x * blockDim.x + threadIdx.x;
if (ii < size) {
vec_a[ii] += teil[ii].get_prop();
vec_a[ii] += ii;
}
}
int main() {
double* vec_1, * d_vec_1;
int N = 300;
double result = 0;
Ding* teil;
Ding* d_teil;
vec_1 = (double*)malloc(N * sizeof(double));
teil = (Ding*)malloc(N * sizeof(Ding));
for (int ii = 0; ii < N; ii++) {
vec_1[ii] = 0;
teil[ii] = Ding::Ding(ii);
}
cudaMalloc(&d_vec_1, N * sizeof(double));
cudaMalloc(&d_teil, N * sizeof(Ding));
cudaMemcpy(d_vec_1, vec_1, N * sizeof(double), cudaMemcpyHostToDevice);
cudaMemcpy(d_teil, teil, N * sizeof(Ding), cudaMemcpyHostToDevice);
some_kernel <<< 256/N + 1, 256 >>> (d_vec_1, d_teil, N);
for (int ii = 0; ii < N; ii++) {
result += vec_1[ii];
}
cout << "Old result: " << result << endl;
cudaMemcpy(vec_1, d_vec_1, N * sizeof(double), cudaMemcpyDeviceToHost);
result = 0;
for (int ii = 0; ii < N; ii++) {
result += vec_1[ii];
}
cout << "New result: " << result << endl;
}
我从主机创建了一个对象数组并将其复制到设备。在设备上,仅调用参数“prop”的 getter,并将值添加到向量 vec_a。所以基本上当没有 class 成员从设备调用时代码工作。所以如果我注释掉这一行:
vec_a[ii] += teil[ii].get_prop();
代码有效,但一旦任何 class 成员开始发挥作用,我就会收到以下错误,不幸的是我无法理解:
Fehler MSB3721 Der Befehl ""C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\bin\nvcc.exe" -gencode=arch=compute_52,code=sm_52 --use-local-env -ccbin "C:\Program Files (x86)\Microsoft Visual Studio19\Community\VC\Tools\MSVC.29.30133\bin\HostX86\x64" -x cu -I"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\include" -I"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\include" -G --keep-dir x64\Debug -maxrregcount=0 --machine 64 -cuda -cudart static -g -D_DEBUG -D_CONSOLE -D_UNICODE -DUNICODE -Xcompiler "/EHsc /W3 /nologo /Od /Fdx64\Debug\vc142.pdb /FS /Zi /RTC1 /MDd " -o x64\Debug\File.cu.obj "C:\Users\ronal\source\repos\Basic_Cuda_Test\Basic_Cuda_Test\File.cu"" wurde mit Code 255 beendet. Basic_Cuda_Test C:\Program Files (x86)\Microsoft Visual Studio19\Community\MSBuild\Microsoft\VC\v160\BuildCustomizations\CUDA 11.4.targets 785
从这条消息中可以看出,我使用的是 Cuda v11.4 和 Microsoft Visual Studio 2019。在不访问 class 成员的情况下,计算已成功执行,因此 Cuda 的东西似乎工作一般。这就是为什么我假设到目前为止一切都已正确安装和配置。最好的情况是我也可以在设备上创建对象,但现在如果我可以以某种方式在设备上使用 class 成员,我会非常高兴。可能问题很简单。
期待您的回答和解决方案。
根据给出的代码判断,我假设您有一些文件 Ding.cu
,其中包含 Ding
的实现。
为了能够从不同的翻译单元调用设备功能(内核在 main.cu
中实现),必须生成可重定位的设备代码。使用编译器标志 --rdc=true
我是 C++ 新手,尤其是 Cuda 计算工具。我正在尝试使用 Cuda 在 GPU 上并行化我的代码,出于我的目的,有必要能够从 class 创建对象或至少从内核调用它们的成员。
首先是我的 class:
的定义//Header
#pragma once
#include<cuda.h>
#include<cuda_runtime.h>
#include<cuda_runtime_api.h>
#include<stdio.h>
#include<iostream>
class Ding
{
private:
int index;
double vector_1[100];
double vector_2[100];
double prop;
public:
__host__ __device__ Ding(int);
__host__ __device__ ~Ding();
__device__ void calculate_stuff(double, int);
__device__ double get_prop();
};
//Source
#include "Ding.h"
#include <math.h>
__host__ __device__ Ding::Ding(int ind) {
index = ind;
prop = 1;
for (int ii = 0; ii < 100; ii++) {
vector_1[ii] = (4 * ii + ind) / (ind + ii + 1);
vector_2[ii] = (-2.14 * ii + ind) / (2*ind + ii + 1);
}
}
__host__ __device__ Ding::~Ding() {};
__device__ void Ding::calculate_stuff(double coeff, int N) {
prop = 1;
for (int ii = 0; ii < N; ii++) {
for (int jj = 0; jj < 100; jj++) {
prop += pow(-1, ii) * vector_1[jj] * vector_2[jj]*coeff;
}
}
}
__device__ double Ding::get_prop() {
return prop;
}
如您所见,除了进行了一些无意义的计算外,没有什么特别的,因为这只能作为我如何使用 Cuda 获得此代码 运行 的示例。
现在这是主要的源文件:
#include<cuda.h>
#include<cuda_runtime.h>
#include<cuda_runtime_api.h>
#include "device_launch_parameters.h"
#include<stdio.h>
#include<iostream>
#include "Ding.h"
using namespace std;
__global__ void some_kernel(double *vec_a, Ding* teil, int size) {
int ii = blockIdx.x * blockDim.x + threadIdx.x;
if (ii < size) {
vec_a[ii] += teil[ii].get_prop();
vec_a[ii] += ii;
}
}
int main() {
double* vec_1, * d_vec_1;
int N = 300;
double result = 0;
Ding* teil;
Ding* d_teil;
vec_1 = (double*)malloc(N * sizeof(double));
teil = (Ding*)malloc(N * sizeof(Ding));
for (int ii = 0; ii < N; ii++) {
vec_1[ii] = 0;
teil[ii] = Ding::Ding(ii);
}
cudaMalloc(&d_vec_1, N * sizeof(double));
cudaMalloc(&d_teil, N * sizeof(Ding));
cudaMemcpy(d_vec_1, vec_1, N * sizeof(double), cudaMemcpyHostToDevice);
cudaMemcpy(d_teil, teil, N * sizeof(Ding), cudaMemcpyHostToDevice);
some_kernel <<< 256/N + 1, 256 >>> (d_vec_1, d_teil, N);
for (int ii = 0; ii < N; ii++) {
result += vec_1[ii];
}
cout << "Old result: " << result << endl;
cudaMemcpy(vec_1, d_vec_1, N * sizeof(double), cudaMemcpyDeviceToHost);
result = 0;
for (int ii = 0; ii < N; ii++) {
result += vec_1[ii];
}
cout << "New result: " << result << endl;
}
我从主机创建了一个对象数组并将其复制到设备。在设备上,仅调用参数“prop”的 getter,并将值添加到向量 vec_a。所以基本上当没有 class 成员从设备调用时代码工作。所以如果我注释掉这一行:
vec_a[ii] += teil[ii].get_prop();
代码有效,但一旦任何 class 成员开始发挥作用,我就会收到以下错误,不幸的是我无法理解:
Fehler MSB3721 Der Befehl ""C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\bin\nvcc.exe" -gencode=arch=compute_52,code=sm_52 --use-local-env -ccbin "C:\Program Files (x86)\Microsoft Visual Studio19\Community\VC\Tools\MSVC.29.30133\bin\HostX86\x64" -x cu -I"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\include" -I"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\include" -G --keep-dir x64\Debug -maxrregcount=0 --machine 64 -cuda -cudart static -g -D_DEBUG -D_CONSOLE -D_UNICODE -DUNICODE -Xcompiler "/EHsc /W3 /nologo /Od /Fdx64\Debug\vc142.pdb /FS /Zi /RTC1 /MDd " -o x64\Debug\File.cu.obj "C:\Users\ronal\source\repos\Basic_Cuda_Test\Basic_Cuda_Test\File.cu"" wurde mit Code 255 beendet. Basic_Cuda_Test C:\Program Files (x86)\Microsoft Visual Studio19\Community\MSBuild\Microsoft\VC\v160\BuildCustomizations\CUDA 11.4.targets 785
从这条消息中可以看出,我使用的是 Cuda v11.4 和 Microsoft Visual Studio 2019。在不访问 class 成员的情况下,计算已成功执行,因此 Cuda 的东西似乎工作一般。这就是为什么我假设到目前为止一切都已正确安装和配置。最好的情况是我也可以在设备上创建对象,但现在如果我可以以某种方式在设备上使用 class 成员,我会非常高兴。可能问题很简单。
期待您的回答和解决方案。
根据给出的代码判断,我假设您有一些文件 Ding.cu
,其中包含 Ding
的实现。
为了能够从不同的翻译单元调用设备功能(内核在 main.cu
中实现),必须生成可重定位的设备代码。使用编译器标志 --rdc=true