Cuda 在不同源文件上使用相同的常量内存数组

Cuda 在不同源文件上使用相同的常量内存数组,cuda,Cuda,我有一个\uuuuu常量内存数组,其中包含许多内核所需的信息,这些内核放在不同的源文件中。此常量内存数组在头文件GlobalParameters.h中定义,它由包含需要访问此数组的内核的所有文件#包含 我(看看Talonmes的答案)认为\uuuu常量内存\uuuu仅在定义它的翻译单元中可用,除非您启用单独编译(使用CUDA 5.0或更高版本) 我仍然不完全明白这对我的案件意味着什么 假设我不能打开单独的编译,有没有办法满足我的需求?我应该将常量内存数组的定义放在哪里?如果我把它放在我的标题中会

我有一个
\uuuuu常量
内存数组,其中包含许多内核所需的信息,这些内核放在不同的源文件中。此常量内存数组在头文件
GlobalParameters.h
中定义,它由包含需要访问此数组的内核的所有文件
#包含

我(看看Talonmes的答案)认为
\uuuu常量内存\uuuu
仅在定义它的翻译单元中可用,除非您启用单独编译(使用
CUDA 5.0
或更高版本)

我仍然不完全明白这对我的案件意味着什么

假设我不能打开单独的编译,有没有办法满足我的需求?我应该将常量内存数组的定义放在哪里?如果我把它放在我的标题中会怎么样?标题包含在许多翻译单元中


假设我可以打开单独编译,我是否应该在头文件中将我的
\uuu constant\uuuu
内存数组声明为
extern
,并将定义放在源文件中(例如
GlobalParameters.cu
)?

否,如果不使用单独编译,就不可能使用相同的常量内存,在几个.cu文件上声明一次

在我看来,有两种解决方法
第一个是在一个.cu文件中实现所有内核。因此,您将得到一个缺点,即该文件将变得非常大,但概述不好


第二种方法是在每个.cu文件中再次声明常量内存。然后使用包装器将每个.cu文件的值复制到常量内存中,就像我在回答中描述的那样。缺点是,您必须确保不会忘记复制单个.cu文件中的值,并且必须检查您不会在总可用恒定内存的限制下运行。

一种使恒定内存可用于除声明恒定内存的转换单元之外的其他转换单元的方法,调用
cudaGetSymbolAddress()
,并使指针可用于其他函数

这种技术在某种程度上是在玩火,因为如果使用指针写入内存而没有适当的障碍和同步,那么可能会与常量内存和全局内存之间缺乏一致性相冲突


此外,如果使用此方法,您可能无法获得恒定内存的全部性能优势。这在SM 2.x和更高版本的硬件上应该不太正确-反汇编目标代码并确保编译器发出“统一加载”指令。

下面的示例假设可以使用单独的编译。在本例中,下面的示例演示如何使用
extern
跨不同的编译单元处理常量内存

文件kernel.cu

#include "cuda_runtime.h"
#include "device_launch_parameters.h"

#include <stdio.h>

#include "Utilities.cuh"

__constant__ int    N_GPU;
__constant__ float  a_GPU;

__global__ void printKernel();

int main()
{
    const int       N = 5;

    const float     a = 10.466;

    gpuErrchk(cudaMemcpyToSymbol(N_GPU, &N, sizeof(int)));
    gpuErrchk(cudaMemcpyToSymbol(a_GPU, &a, sizeof(float)));

    printKernel << <1, 1 >> > ();
    gpuErrchk(cudaPeekAtLastError());
    gpuErrchk(cudaDeviceSynchronize());

    return 0;
}
#include <stdio.h>

extern __constant__ int     N_GPU;
extern __constant__ float   a_GPU;

__global__ void printKernel() {

    printf("N = %i; a = %f\n", N_GPU, a_GPU);

}
#包括“cuda_runtime.h”
#包括“设备启动参数.h”
#包括
#包括“Utilities.cuh”
__常数μint NμGPU;
__恒定浮点数;
__全局_uuu无效打印内核();
int main()
{
常数int N=5;
常数浮点a=10.466;
gpuerchk(cudaMemcpyToSymbol(nu GPU,&N,sizeof(int));
gpuerchk(cudaMemcpyToSymbol(au GPU和a,sizeof(float));
打印内核>();
gpuerchk(cudaPeekAtLastError());
gpuErrchk(cudaDeviceSynchronize());
返回0;
}
文件otherCompilationUnit.cu

#include "cuda_runtime.h"
#include "device_launch_parameters.h"

#include <stdio.h>

#include "Utilities.cuh"

__constant__ int    N_GPU;
__constant__ float  a_GPU;

__global__ void printKernel();

int main()
{
    const int       N = 5;

    const float     a = 10.466;

    gpuErrchk(cudaMemcpyToSymbol(N_GPU, &N, sizeof(int)));
    gpuErrchk(cudaMemcpyToSymbol(a_GPU, &a, sizeof(float)));

    printKernel << <1, 1 >> > ();
    gpuErrchk(cudaPeekAtLastError());
    gpuErrchk(cudaDeviceSynchronize());

    return 0;
}
#include <stdio.h>

extern __constant__ int     N_GPU;
extern __constant__ float   a_GPU;

__global__ void printKernel() {

    printf("N = %i; a = %f\n", N_GPU, a_GPU);

}
#包括
外部常量内部GPU;
外部uuu常量uuu浮点a_ugpu;
__全局_uu_u;void printKernel(){
printf(“N=%i;a=%f\N”,N\u GPU,a\u GPU);
}

是。后来的CUDA文件说:
在单独编译模式下编译时(有关此模式的说明,请参阅nvcc用户手册),设备共享托管常量变量可以使用extern关键字定义为外部变量。nvlink在找不到外部变量的定义时会生成错误(除非它是动态分配的共享变量)。

如您所想,第一种解决方案不适用。我们已经有很多内核,如果只修改一个内核,将它们放在一个翻译单元中将极大地增加编译时间。我不知道我是否完全理解第二种选择。这基本上意味着使用多个具有相同值的常量内存数组(每个转换单元一个)吗?这很有趣。这意味着我应该调用这个函数,给出我的数组的名称,因为除了它在其中定义的转换单元之外,我在其他转换单元上没有该数组的任何声明,对吗?对。您需要向声明常量数组的转换单元添加一个函数,然后调用该函数从其他转换单元查询指针。YMMV-这是CUDA land楼梯下的一个黑暗角落。