Pointers CUDA:\uuuuu限制\uuuu标签使用
我不太理解CUDA中Pointers CUDA:\uuuuu限制\uuuu标签使用,pointers,memory,memory-management,cuda,Pointers,Memory,Memory Management,Cuda,我不太理解CUDA中\uuuuu restrict\uuuu标记的概念 我已经读到,使用\uuuuuu restrict\uuuuu可以避免指针别名,特别是,如果指向的变量是只读的,则会优化变量的读取,因为它是缓存的 这是代码的简化版本: __constant__ float M[M_DIM1][M_DIM2]; __host__ void function(float N[][DIM2], float h_M[][M_DIM2], float P[][DIM2]); __global__
\uuuuu restrict\uuuu
标记的概念
我已经读到,使用\uuuuuu restrict\uuuuu
可以避免指针别名,特别是,如果指向的变量是只读的,则会优化变量的读取,因为它是缓存的
这是代码的简化版本:
__constant__ float M[M_DIM1][M_DIM2];
__host__ void function(float N[][DIM2], float h_M[][M_DIM2], float P[][DIM2]);
__global__ void kernel_function(const float* __restrict__ N, float *P);
__host__ void function(float N[][DIM2], float h_M[][M_DIM2], float P[][DIM2]) {
int IOSize = DIM1 * DIM2 * sizeof(float);
int ConstSize = M_DIM1* M_DIM2* sizeof(float);
float* dN, *dP;
cudaMalloc((void**)&dN, IOSize);
cudaMemcpy(dN, N, IOSize, cudaMemcpyHostToDevice);
cudaMemcpyToSymbol(M, h_M, ConstSize);
cudaMalloc((void**)&dP, IOSize);
dim3 dimBlock(DIM1, DIM2);
dim3 dimGrid(1, 1);
kernel_function << <dimGrid, dimBlock >> >(dN, dP);
cudaMemcpy(P, dP, IOSize, cudaMemcpyDeviceToHost);
cudaFree(dN);
cudaFree(dP);
}
uuu常量uuu浮点M[M_DIM1][M_DIM2];
__主机无效函数(浮点N[][DIM2],浮点h_M[][M_DIM2],浮点P[][DIM2]);
__全局无效核函数(常数浮点*限制,浮点*P);
__主机无效函数(浮点N[][DIM2],浮点h_M[][M_DIM2],浮点P[][DIM2]){
int IOSize=DIM1*DIM2*sizeof(浮点);
int ConstSize=M_DIM1*M_DIM2*sizeof(浮点);
浮点数*dN,*dP;
Cudamaloc((无效**)和dN,IOSize);
cudaMemcpy(dN、N、IOSize、cudaMemcpyHostToDevice);
cudaMemcpyToSymbol(M,hm,ConstSize);
Cudamaloc((无效**)和dP,IOSize);
dim3 dimBlock(DIM1、DIM2);
dim3 dimGrid(1,1);
核函数>(dN,dP);
cudaMemcpy(P、dP、IOSize、cudaMemcpyDeviceToHost);
cudaFree(dN);
cudaFree(dP);
}
我是否以正确的方式在N上使用了只读的\uuuu restrict\uuu
标记?
此外,我还了解到,M上的关键字
\uuuuu constant\uuuu
表示只读和常量,因此这两者之间的区别是什么,nvcc使用的分配类型?\uuuu restrict\uuu
。(注意,包括GNU编译器在内的各种C++编译器也支持这个精确的关键字,并同样使用它)。
它的语义基本上与C99restrict
关键字相同,即
简而言之,\uuuuu restrict\uuuuu
是程序员与编译器签订的一份合同,上面说,大致上是,“我将仅使用此指针引用底层数据”。从编译器的角度来看,这使表脱离的一个关键因素是指针别名,这会阻止编译器进行各种优化
如果您想要一篇关于restrict
或\uuu restrict\uuuu
确切定义的较长正式论文,请参考我已经给出的链接之一,或进行一些研究
因此,\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
通常对支持它的编译器非常有用,用于优化目的
对于compute capability 3.5或更高版本的设备,这些设备有一个称为的独立缓存,它独立于普通的一级缓存
如果同时使用\uuuu restrict\uuuu
和const
来修饰传递给内核的全局指针,那么在为cc3.5和更高版本的设备生成代码时,这也是编译器的一个强烈提示,以使这些全局内存负载流经只读缓存。这可以提供应用程序性能方面的好处,通常很少进行其他代码重构。这并不能保证只读缓存的使用,如果只读缓存能够满足必要的条件,编译器通常会尝试积极使用只读缓存,即使您不使用这些修饰符
\uuuu常量\uuuu
指的是不同的。有许多不同之处:
在所有GPU上都可用,只读缓存仅在cc3.5及更高版本上可用\uuuu常量\uuuu
- 使用
标记分配的内存(包括在指定内存分配的行中)最大限制为64KB。只读缓存没有这样的限制。我们不把\uuuu constant\uuuu
放在分配内存的行上;它用于装饰指针\uuuu restrict\uuuu
- 只读缓存中缓存的数据具有典型的全局内存访问注意事项-通常我们希望通过只读缓存进行相邻和连续访问,以实现全局内存读取的最佳合并。
机制oth期望所谓的统一访问以获得最快的性能。统一访问本质上意味着warp中的每个线程都从相同的位置/地址/索引请求数据\uuuu常量
\uuu常量\uuu
内存和在传递给内核代码的指针上标记有const
decorator的全局内存都是只读的
我看不出您所展示的代码中有任何明显的问题,无论是使用
\uuuuuuuuuuuuuu限制\uuuuuuuuuuuuuuuuu
还是其他什么。我唯一的意见是,为了获得最大的好处,您可能希望在内核声明/原型中用\uuuu restrict\uuuu
修饰N
和P
指针,以获得最大的好处,如果这是您的意图的话。(显然,您不会用const
装饰P
。是否适用于引用,就像它适用于原始指针一样?在中的示例中,void foo(const float*\uuuuu restrict\a,const float*\uu restrict\uuuu\b,float*\uu restrict\uu\c)之间是否有任何区别
和无效foo(常量浮点*\uuuuu限制\uuuuuua,常量浮点*\uuuu限制\uuuuuuuub,浮点*c)
?后者有意义吗?没有指定编译器的行为。我建议在所有指针上使用\uuuuuu restrict\uuuuu
(如果适用),因为这将完全消除表中的别名。编程指南中也包括了这一点:“请注意,所有指针参数都需要进行限制,编译器优化器才能获得任何好处。”这实际上是对\uuuuuuu restrict\uuuuuu
语义的精确描述,我在这个问题中并不打算涉及到这一点。你可能想问一个新问题。我不太可能回应关于一个3年前问题的评论中的长时间讨论。