内核块执行之间GPU多处理器的共享内存会发生什么变化?

 帅帅考拉_955 发布于 2023-02-10 15:02

假设我有一堆带有一堆块的CUDA内核,并假设在同一个对称多处理器上的另一个块之后安排了一个块(也就是说,所有warp的共享内存区域相同的单元).目前,NVIDIA没有在API或每GPU文档中指定执行之间共享内存会发生什么.但实际上,关于块的共享内存内容,下列哪一项呢?:

它处于同一状态,最后一个预定的块留下了它.

这是空白的.

它包含不可预见的垃圾.

为了缩小可能出现的情况的变化,请具体参考每个块使用最大可能共享内存量的情况 - 在Kepler GPU上为48 KB.

1 个回答
  • NVIDIA不公布此级别的硬件行为,因此您应该将其视为未定义(如@datenwolf所述).当然,虽然给定块看到的共享内存的内容不是随机的.并且硬件没有必要花时间清理内存.

    GPU可以在每个SM上同时运行多个块.同时为给定内核运行的块数取决于各种因素.因此,例如,如果共享内存是限制因素,则每个SM将运行尽可能多的块以适应共享内存.因此,如果共享内存为48K且块需要10K,则可以使用40K同时运行4个块.所以,如果你有一个带有8个SM的设备,我的猜测是给定块的共享内存将有32(4*8)个可能的固定位置.因此,当计划新块时,它将被分配给其中一个位置,并查看在该位置运行的前一个块所留下的共享内存.

    API无法阻止块检测它在哪个位置运行.块的调度是动态确定的,可能很难预测.

    如果GPU用于显示,它可能同时运行其他内核(着色器),可能以奇怪和奇妙的方式覆盖CUDA内核中的块之间的共享内存.甚至CUDA也可能在幕后运行其他内核.

    编辑:

    我写了一个小程序来测试(包含在下面).程序将一个块应存储在共享内存中的整数数作为参数.然后它启动100,000个块,每个块有一个线程.每个块检查其共享内存是否已初始化.如果它已初始化,则该块不再执行任何操作.如果未初始化,则块初始化内存并增加全局计数.初始化模式是一个递增的数字序列,以避免部分重叠的初始化共享内存缓冲区似乎是有效的.

    在GTX660(Kepler,CC 3.0,5个SM)上配置了48K共享内存,CC 3.0 Release版本,我得到了以下结果:

    C:\rd\projects\cpp\test_cuda\Release>test_cuda.exe 10000
    Shared memory initializations: 5
    

    我跑了几次,每次都得到相同的结果.这与我最初的猜测相匹配,因为10000个整数占用~40K,因此每个SM可以有一个并发块的空间,并且该设备有5个SM.

    但是,当我将共享内存减少到2500个整数(~10K),期望获得20次初始化并运行几次时,我得到了不同的高数字:

    Shared memory initializations: 32,822
    Shared memory initializations: 99,996
    Shared memory initializations: 35,281
    Shared memory initializations: 30,748
    

    因此,在这种情况下,我对固定位置的猜测完全无效.

    然后我尝试将共享内存减少到100个整数(在48K中可以容纳122个块)并且始终如一:

    Shared memory initializations: 480
    

    因此,再次,不是预期的数字,并且令人惊讶的是,即使每个块使用的共享内存量较小,但可能的变化明显较少.

    看起来,如果你决定用脚射击自己,你可以使用一个大的共享内存块来保持一致:)此外,这是在一个也用于显示的GPU上运行,Windows 7带有Aero(A GPU加速主题)并且看起来渲染不会干扰因为桌面在内核运行时冻结.

    程序:

    #include "cuda_runtime.h"
    
    #include <iostream>
    #include <sstream>
    using namespace std;
    
    #define assertCudaSuccess(ans) { _assertCudaSuccess((ans), __FILE__, __LINE__); }
    inline void _assertCudaSuccess(cudaError_t code, char *file, int line)
    {
      if (code != cudaSuccess) {
        fprintf(stderr,"CUDA Error: %s %s %d\n", cudaGetErrorString(code), file, line);
        exit(code);
      }
    }
    
    __global__ void shared_memory_persistence_test(int n_shared_ints);
    __device__ int init_cnt_d(0);
    
    int main(int argc, char* argv[])
    {
      cout.imbue(locale(""));
      int n_shared_ints;
      stringstream(string(argv[1])) >> n_shared_ints;
      shared_memory_persistence_test<<<dim3(100, 1000), 1, n_shared_ints * sizeof(int)>>>(n_shared_ints);
      assertCudaSuccess(cudaPeekAtLastError());
      assertCudaSuccess(cudaDeviceSynchronize());
      int init_cnt_h;
      assertCudaSuccess(cudaMemcpyFromSymbol(&init_cnt_h, init_cnt_d, sizeof(int), 0, cudaMemcpyDeviceToHost));
      cout << "Shared memory initializations: " << init_cnt_h << endl;
      return 0;
    }
    
    __global__ void shared_memory_persistence_test(int n_shared_ints)
    {
      extern __shared__ int shared[];
    
      for (int i(0); i < n_shared_ints; ++i) {
        if (shared[i] != i) {
          for (int i(0); i < n_shared_ints; ++i) {
            shared[i] = i;
          }
          atomicAdd(&init_cnt_d, 1);
          break;
        }
      }
    }
    

    2023-02-10 15:05 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有