CUDA:__ sattrict__标签用法

时间:2017-04-05 15:45:10

标签: pointers memory memory-management cuda

我不太了解CUDA中__restrict__标记的概念。

我已经读过使用__restrict__避免了指针别名,特别是如果指向的变量是只读的,那么变量的读取就会被优化,因为它已被缓存。

这是代码的简化版本:

__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);

}

我是否以正确的方式使用N上的__restrict__标记,这是只读的? 此外,我已经读过M上的关键字__constant__意味着它是只读的和常量的,那么它们之间的差异是什么,分配的类型是什么?

1 个答案:

答案 0 :(得分:5)

__restrict__使用的

nvcc已记录为here。 (请注意,包括gnu编译器在内的各种c ++编译器也支持这个确切的关​​键字,并且类似地使用它。)

它与C99 restrict关键字具有基本相同的语义,即an official part of that language standard

简而言之,__restrict__是您作为程序员使用编译器创建的合同,其中粗略,&#34;我将仅使用此指针来引用基础数据&#34;。从编译器的角度来看,这取消了表格的一个关键因素是指针别名,它可以阻止编译器进行各种优化。

如果您想要对restrict__restrict__的确切定义进行更长时间的正式论述,请参阅我已经给出的其中一个链接,或进行一些研究。

因此,出于优化目的,__restrict__通常对支持它的编译器很有用。

对于3.5或更高版本的计算能力,这些设备有一个名为read only cache的独立缓存,它独立于普通的L1类型缓存。

如果同时使用__restrict__const来装饰传递给内核的全局指针,那么在为cc3.5及更高版本的设备生成代码时,这也是编译器的强烈提示,导致这些全局内存负载流过只读缓存。这可以提供应用程序性能优势,通常只需很少的其他代码重构。这并不保证使用只读缓存,并且编译器通常会尝试积极地使用只读缓存(如果它可以满足必要条件),即使您没有这样做也是如此。使用这些装饰器。

__constant__指的是不同 hardware resource on the GPU。有很多不同之处:

  • __constant__适用于所有GPU,只有cc3.5及更高版本的只读缓存
  • 使用__constant__标记分配的内存(包含在指定内存分配的行中)限制为最大64KB。只读缓存没有这样的限制。我们不会将__restrict__放在分配内存的行上;它用于装饰指针。
  • 在只读缓存中缓存的数据具有典型的全局内存访问注意事项 - 通常我们需要相邻和连续访问,以便通过只读缓存最佳地合并全局内存读取。 __constant__机制OTOH期望所谓的统一访问以获得最快的性能。统一访问本质上意味着warp中的每个线程都在从相同的位置/地址/索引请求数据。

从内核代码的角度来看,__constant__内存和在传递给内核代码的指针上标有const装饰器的全局内存都是只读的。

我不会在您显示的代码中看到任何明显的问题,无论是使用__restrict__还是其他任何问题。我唯一的评论是,为了获得最大的好处,您可能希望使用N来装饰内核声明/原型中的P__restrict__指针,以获得最大的好处,如果是你的意图。 (显然,你不会用P装饰const。)