我有使用常量内存的设备/主机功能。它在设备上运行正常,但在主机上,这个内存似乎仍然没有初始化。
#include <iostream>
#include <stdio.h>
const __constant__ double vals[2] = { 0.0, 1000.0 };
__device__ __host__ double f(size_t i)
{
return vals[i];
}
__global__ void kern()
{
printf("vals[%d] = %lf\n", threadIdx.x, vals[threadIdx.x]);
}
int main() {
std::cerr << f(0) << " " << f(1) << std::endl;
kern<<<1, 2>>>();
cudaThreadSynchronize();
}
此打印(需要CC 2.0或更高版本)
0 0
vals[0] = 0.000000
vals[1] = 1000.000000
问题是什么?如何同时初始化设备和主机内存常量?
答案 0 :(得分:13)
由于CygnusX1误解了我对MurphEngineer回答的评论意思,也许我应该发表自己的答案。我意味着什么是这样的:
__constant__ double dc_vals[2] = { 0.0, 1000.0 };
const double hc_vals[2] = { 0.0, 1000.0 };
__device__ __host__ double f(size_t i)
{
#ifdef __CUDA_ARCH__
return dc_vals[i];
#else
return hc_vals[i];
#endif
}
这与Cygnus具有相同的结果,但它在实际代码中更灵活:例如,它允许您在常量数组中使用运行时定义的值,并允许您使用CUDA API函数,如{ {1}}数组上的{1}} / cudaMemcpyToSymbol
。
一个更现实的完整例子:
cudsaMemcpyFromSymbol
答案 1 :(得分:4)
使用__constant__限定符在设备上显式分配该内存。无法从主机访问该内存 - 即使使用新的CUDA统一寻址(仅适用于使用cudaMalloc()及其朋友分配的内存)。使用const限定变量只是说“这是一个指向(...)的常量指针”。
实际上,正确的方法是拥有两个阵列:一个在主机上,一个在设备上。初始化主机阵列,然后使用cudaMemcpyToSymbol()在运行时将数据复制到设备阵列。有关如何执行此操作的详细信息,请参阅此主题:http://forums.nvidia.com/index.php?showtopic=69724
答案 2 :(得分:3)
我认为MurphEngineer很好地解释了为什么它不起作用。
要快速解决这个问题,你可以遵循哈里斯的想法,如下所示:
#ifdef __CUDA_ARCH__
#define CONSTANT __constant__
#else
#define CONSTANT
#endif
const CONSTANT double vals[2] = { 0.0, 1000.0 };
这样主机编译将创建一个普通的主机const数组,而设备编译将创建一个设备__constant__
编译。
请注意,如果您决定这样做,使用CUDA API访问具有cudaMemcpyToSymbol()
等功能的设备阵列可能会更难。
答案 3 :(得分:1)
非常棒。我正在努力解决同样的问题,这提供了一个解决方案。但是,harrism建议的代码会给编译带来错误。以下是使用nvcc
正确编译的固定代码:
#include <iostream>
#include <stdio.h>
__constant__ double dc_vals[2];
const double hc_vals[2] = {0.0, 1000.0};
__device__ __host__ double f(size_t i)
{
#ifdef __CUDA_ARCH__
return dc_vals[i];
#else
return hc_vals[i];
#endif
}
__global__ void kern()
{
printf("Device: vals[%d] = %lf\n", threadIdx.x, f(threadIdx.x));
}
int main() {
cudaMemcpyToSymbol(dc_vals, hc_vals, 2 * sizeof(double), 0, cudaMemcpyHostToDevice);
std::cerr << "Host: " << f(0) << " " << f(1) << std::endl;
kern<<<1, 2>>>();
cudaThreadSynchronize();
}