CUDA主机和设备使用相同的__constant__内存

时间:2012-02-26 21:59:44

标签: cuda

我有使用常量内存的设备/主机功能。它在设备上运行正常,但在主机上,这个内存似乎仍然没有初始化。

#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

问题是什么?如何同时初始化设备和主机内存常量?

4 个答案:

答案 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();
}