因此,我试图编写一些利用Nvidia的CUDA架构的代码。我注意到复制到设备和从设备复制真的伤害了我的整体性能,所以现在我试图将大量数据移动到设备上。
由于这些数据用于众多功能,我希望它是全球性的。是的,我可以传递指针,但我真的想知道在这个例子中如何使用全局变量。
所以,我有想要访问设备分配数组的设备功能。
理想情况下,我可以做类似的事情:
__device__ float* global_data;
main()
{
cudaMalloc(global_data);
kernel1<<<blah>>>(blah); //access global data
kernel2<<<blah>>>(blah); //access global data again
}
但是,我还没弄明白如何创建动态数组。我通过声明数组如下来找到了解决方法:
__device__ float global_data[REALLY_LARGE_NUMBER];
虽然这不需要cudaMalloc调用,但我更喜欢动态分配方法。
答案 0 :(得分:5)
这样的事情应该可行。
#include <algorithm>
#define NDEBUG
#define CUT_CHECK_ERROR(errorMessage) do { \
cudaThreadSynchronize(); \
cudaError_t err = cudaGetLastError(); \
if( cudaSuccess != err) { \
fprintf(stderr, "Cuda error: %s in file '%s' in line %i : %s.\n", \
errorMessage, __FILE__, __LINE__, cudaGetErrorString( err) );\
exit(EXIT_FAILURE); \
} } while (0)
__device__ float *devPtr;
__global__
void kernel1(float *some_neat_data)
{
devPtr = some_neat_data;
}
__global__
void kernel2(void)
{
devPtr[threadIdx.x] *= .3f;
}
int main(int argc, char *argv[])
{
float* otherDevPtr;
cudaMalloc((void**)&otherDevPtr, 256 * sizeof(*otherDevPtr));
cudaMemset(otherDevPtr, 0, 256 * sizeof(*otherDevPtr));
kernel1<<<1,128>>>(otherDevPtr);
CUT_CHECK_ERROR("kernel1");
kernel2<<<1,128>>>();
CUT_CHECK_ERROR("kernel2");
return 0;
}
给它一个旋转。
答案 1 :(得分:1)
花些时间专注于NVIDIA提供的大量文档。
编程指南:
float* devPtr;
cudaMalloc((void**)&devPtr, 256 * sizeof(*devPtr));
cudaMemset(devPtr, 0, 256 * sizeof(*devPtr));
这是一个如何分配内存的简单示例。现在,在你的内核中,你应该接受一个浮点指针,如下所示:
__global__
void kernel1(float *some_neat_data)
{
some_neat_data[threadIdx.x]++;
}
__global__
void kernel2(float *potentially_that_same_neat_data)
{
potentially_that_same_neat_data[threadIdx.x] *= 0.3f;
}
所以现在你可以像这样调用它们:
float* devPtr;
cudaMalloc((void**)&devPtr, 256 * sizeof(*devPtr));
cudaMemset(devPtr, 0, 256 * sizeof(*devPtr));
kernel1<<<1,128>>>(devPtr);
kernel2<<<1,128>>>(devPtr);
由于这些数据被广泛使用 功能,我希望它 全球性的。
使用全局变量的原因很少。这肯定不是一个。我将把它作为练习来扩展这个例子,包括将“devPtr”移到全局范围。
编辑:
好的,基本问题是:你的内核只能访问设备内存,他们可以使用的唯一全局范围指针是GPU。从CPU调用内核时,在幕后发生的事情是指针和基元在内核执行之前被复制到GPU寄存器和/或共享内存中。
所以我能建议的最接近的是:使用cudaMemcpyToSymbol()来实现你的目标。但是,在后台,考虑一种不同的方法可能是正确的事情。
#include <algorithm>
__constant__ float devPtr[1024];
__global__
void kernel1(float *some_neat_data)
{
some_neat_data[threadIdx.x] = devPtr[0] * devPtr[1];
}
__global__
void kernel2(float *potentially_that_same_neat_data)
{
potentially_that_same_neat_data[threadIdx.x] *= devPtr[2];
}
int main(int argc, char *argv[])
{
float some_data[256];
for (int i = 0; i < sizeof(some_data) / sizeof(some_data[0]); i++)
{
some_data[i] = i * 2;
}
cudaMemcpyToSymbol(devPtr, some_data, std::min(sizeof(some_data), sizeof(devPtr) ));
float* otherDevPtr;
cudaMalloc((void**)&otherDevPtr, 256 * sizeof(*otherDevPtr));
cudaMemset(otherDevPtr, 0, 256 * sizeof(*otherDevPtr));
kernel1<<<1,128>>>(otherDevPtr);
kernel2<<<1,128>>>(otherDevPtr);
return 0;
}
这个例子不要忘记'--host-compilation = c ++'。
答案 2 :(得分:1)
我继续尝试分配临时指针并将其传递给类似于kernel1的简单全局函数的解决方案。
好消息是它确实有效:)
然而,我认为它混淆了编译器,因为我现在得到“咨询:无论什么指针指向,假设全局内存空间”,每当我尝试访问全局数据时。幸运的是,这个假设恰好是正确的,但警告很烦人。
无论如何,为了记录 - 我已经查看了很多例子,并且确实贯穿了nvidia练习,其中的重点是让输出说“正确!”。但是,我还没有看过所有。如果有人知道他们做动态全局设备内存分配的sdk示例,我仍然想知道。
答案 3 :(得分:0)
我有一个实现就是这样,两个内核都有一个指向传入数据的指针。我显然不希望传入这些指针。
我已经非常仔细地阅读了文档,并且点击了nvidia论坛(并且google搜索了一个小时左右),但是我还没有找到实际运行的全局动态设备数组的实现(我试过了几个编译然后以新的和有趣的方式失败。)
答案 4 :(得分:0)
查看SDK附带的示例。许多样本项目都是一个体面的学习方式。
答案 5 :(得分:0)
由于这些数据用于众多功能,我希望它是全球性的。
-
使用全局变量的原因很少。这肯定不是一个。我会留下它 练习扩展此示例以包括将“devPtr”移动到全局范围。
如果内核在由数组组成的大型const结构上运行怎么办?使用所谓的常量内存不是一个选项,因为它的大小非常有限..那么你必须将它放在全局内存中。?