我有一个__constant__
内存数组,其中包含许多内核所需的信息,这些内核放在不同的源文件中。此常量内存数组在标头GlobalParameters.h
中定义,所有包含需要访问此数组的内核的文件都为#included
。
我just discovered(看看talonmies'回答)__constant memory__
仅在定义它的翻译单元中可用,除非您打开单独的编译(使用CUDA 5.0
或后来)。
我仍然没有完全了解这对我的情况意味着什么。
假设我无法启用单独的编译,是否有办法处理我的需求?我应该在哪里放置我的常量内存数组的定义?如果我将它放在我的标题中,在许多翻译单元中#included
怎么办?
假设我可以打开单独的编译,我应该将标头中的__constant__
内存数组声明为extern
并将定义放在源文件中(例如GlobalParameters.cu
)?
答案 0 :(得分:2)
使常量内存可用于除声明它之外的转换单元的一种方法是调用cudaGetSymbolAddress()
并使指针可用于其他函数。
这种技术在某种程度上起了作用,因为如果你使用指针在没有适当的障碍和同步的情况下写入内存,你可能会因常量内存和全局内存之间缺乏一致性而受到冲击。
此外,如果使用此方法,则可能无法获得常量内存的全部性能优势。在SM 2.x和更高版本的硬件上应该不那么真实 - 反汇编目标代码并确保编译器正在发出"加载均匀"指令。
答案 1 :(得分:1)
以下示例假定使用单独编译的可能性。在这种情况下,下面的示例显示了如何使用#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;
}
在不同的编译单元中使用常量内存。
FILE kernel.cu
#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);
}
FILE otherCompilationUnit.cu
display:inline-block
答案 2 :(得分:0)
不,如果不使用单独的编译,就不可能在几个.cu文件中使用相同的常量内存,即一次声明。
在我的观点中,有两种解决方法。
第一个是在一个.cu文件中实现所有内核。因此,您将会遇到这样一个缺点:这个文件会因为概览错误而变得非常大。
第二种方法是在每个.cu文件中再次声明常量内存。然后,使用包装器将值复制到每个.cu文件的常量内存中 - 就像我在回答here中所描述的那样。缺点是您必须确保不要忘记在单个.cu文件中复制值,并且必须检查您是否不会在总可用常量内存的限制中运行。
答案 3 :(得分:0)
是的。后来的CUDA文档说: 在单独的编译模式下编译时(有关此模式的说明,请参见nvcc用户手册),设备,共享,托管和 constant 变量定义为外部变量。如果nvlink找不到外部变量的定义(除非它是动态分配的 shared 变量),它将生成错误。