0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

CUDA编程分布式共享内存

冬至子 来源:指北笔记 作者:张北北 2023-05-19 15:35 次阅读

Distributed Shared Memory

计算能力9.0中引入的线程块集群为线程块集群中的线程提供了访问集群中所有参与线程块的共享内存的能力。这种分区共享内存称为 Distributed Shared Memory,对应的地址空间称为分布式共享内存地址空间。属于线程块集群的线程可以在分布式地址空间中读、写或执行原子操作,而不管该地址属于本地线程块还是远程线程块。无论内核是否使用分布式共享内存,共享内存大小规格(静态的或动态的)仍然是每个线程块。分布式共享内存的大小就是每个集群的线程块数量乘以每个线程块的共享内存大小。

访问分布式共享内存中的数据需要所有线程块存在 。用户可以使用cluster .sync()从Cluster Group API中保证所有线程块已经开始执行。用户还需要确保在线程块退出之前完成所有分布式共享内存操作。

CUDA提供了一种访问分布式共享内存的机制,应用程序可以从利用它的功能中获益。让我们看看一个简单的直方图计算,以及如何使用线程块集群在GPU上优化它。 计算直方图的标准方法是在每个线程块的共享内存中进行计算,然后执行全局内存原子

这种方法的一个限制是共享内存容量。一旦直方图容器不再适合共享内存,用户就需要直接计算直方图,从而计算全局内存中的原子。对于分布式共享内存,CUDA提供了一个中间步骤,根据直方图桶的大小,直方图可以直接在共享内存、分布式共享内存或全局内存中计算。

下面的CUDA内核示例展示了如何在共享内存或分布式共享内存中计算直方图,具体取决于直方图箱的数量。

#include 

// Distributed Shared memory histogram kernel
__global__ void clusterHist_kernel(int *bins, const int nbins, const int bins_per_block, const int *__restrict__ input,
                                   size_t array_size)
{
  extern __shared__ int smem[];
  namespace cg = cooperative_groups;
  int tid = cg::this_grid().thread_rank();

  // Cluster initialization, size and calculating local bin offsets.
  cg::cluster_group cluster = cg::this_cluster();
  unsigned int clusterBlockRank = cluster.block_rank();
  int cluster_size = cluster.dim_blocks().x;
 
  for (int i = threadIdx.x; i < bins_per_block; i += blockDim.x)
  {
    smem[i] = 0; //Initialize shared memory histogram to zeros
  }

  // cluster synchronization ensures that shared memory is initialized to zero in
  // all thread blocks in the cluster. It also ensures that all thread blocks
  // have started executing and they exist concurrently.
  cluster.sync();

  for (int i = tid; i < array_size; i += blockDim.x * gridDim.x)
  {
    int ldata = input[i];

    //Find the right histogram bin.
    int binid = ldata;
    if (ldata < 0)
      binid = 0;
    else if (ldata >= nbins)
      binid = nbins - 1;

    //Find destination block rank and offset for computing
    //distributed shared memory histogram
    int dst_block_rank = (int)(binid / bins_per_block);
    int dst_offset = binid % bins_per_block;

    //Pointer to target block shared memory
    int *dst_smem = cluster.map_shared_rank(smem, dst_block_rank);

    //Perform atomic update of the histogram bin
    atomicAdd(dst_smem + dst_offset, 1);
  }

  // cluster synchronization is required to ensure all distributed shared
  // memory operations are completed and no thread block exits while
  // other thread blocks are still accessing distributed shared memory
  cluster.sync();

  // Perform global memory histogram, using the local distributed memory histogram 
  int *lbins = bins + cluster.block_rank() * bins_per_block;
  for (int i = threadIdx.x; i < bins_per_block; i += blockDim.x)
  {
    atomicAdd(&lbins[i], smem[i]);
  }
}

上面的内核可以在运行时启动,集群大小取决于所需的分布式共享内存的数量。如果直方图足够小,可以容纳一个块的共享内存,用户可以启动集群大小为1的内核。下面的代码片段展示了如何根据共享内存需求动态启动集群内核。

// Launch via extensible launch
{
  cudaLaunchConfig_t config = {0};
  config.gridDim = array_size / threads_per_block;
  config.blockDim = threads_per_block;

  // cluster_size depends on the histogram size.
  // ( cluster_size == 1 ) implies no distributed shared memory, just thread block local shared memory
  int cluster_size = 2; // size 2 is an example here
  int nbins_per_block = nbins / cluster_size;

  //dynamic shared memory size is per block. 
  //Distributed shared memory size =  cluster_size * nbins_per_block * sizeof(int)
  config.dynamicSmemBytes = nbins_per_block * sizeof(int);

  CUDA_CHECK(::cudaFuncSetAttribute((void *)clusterHist_kernel, cudaFuncAttributeMaxDynamicSharedMemorySize, config.dynamicSmemBytes));

  cudaLaunchAttribute attribute[1];
  attribute[0].id = cudaLaunchAttributeClusterDimension;
  attribute[0].val.clusterDim.x = cluster_size; 
  attribute[0].val.clusterDim.y = 1;
  attribute[0].val.clusterDim.z = 1;

  config.numAttrs = 1;
  config.attrs = attribute;

  cudaLaunchKernelEx(&config, clusterHist_kernel, bins, nbins, nbins_per_block, input, array_size);
}
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • gpu
    gpu
    +关注

    关注

    28

    文章

    4700

    浏览量

    128677
  • CUDA
    +关注

    关注

    0

    文章

    121

    浏览量

    13597
  • API接口
    +关注

    关注

    1

    文章

    82

    浏览量

    10426
收藏 人收藏

    评论

    相关推荐

    分布式软件系统

    。更重要的是,NI LabVIEW 8的分布式智能提供的解决方案不仅令这些挑战迎刃而解,且易于实施。LabVIEW 8的分布式智能具体包括: 可对分布式系统中的所有结点编程——包括主机
    发表于 07-22 14:53

    使用分布式I/O进行实时部署系统的设计

    这篇文章讨论了使用分布式I/O进行实时部署系统的设计。美国国家仪器公司推出了NI 9144扩展机箱,用于确定性以太网中的NI CompactRIO和可编程自动化控制器(PAC)系统。用于C系列模块
    发表于 03-12 17:47

    在NI分布式管理器创建共享变量失败,想请教各位原因

    在NI分布式管理器创建共享变量失败:在这里创建了一个变量炉批次号但现实质量是进程失败 并且关闭了NI分布式管理器后就没有这个变量了,请问这是什么情况?
    发表于 11-06 13:27

    利用NI VeriStand 2010特性创建分布式系统

    要素。通常可以使用反射内存接口实现。  反射内存网络是实时本地局域网(LAN),每个计算机总是拥有共享内存集合的最新本地复本。这些专用网络是为了提供高确定性的数据通信而专门设计的。可以
    发表于 04-08 09:42

    分布式系统的优势是什么?

    当讨论分布式系统时,我们面临许多以下这些形容词所描述的 同类型: 分布式的、删络的、并行的、并发的和分散的。分布式处理是一个相对较新的领域,所以还没有‘致的定义。与顺序计算相比、并行的、并发的和
    发表于 03-31 09:01

    HarmonyOS应用开发-分布式设计

    不同终端设备之间的极速连接、硬件协同、资源共享,为用户提供最佳的场景体验。分布式设计指南可以帮助应用开发者了解如何充分发挥“One Super Device”的能力,提供独特的跨设备交互体验。说明:本设计指南后续举例中将包括手机、智慧屏、手表等多种设备,其中手机均指 EM
    发表于 09-22 17:11

    分布式软总线实现近场设备间统一的分布式通信管理能力如何?

    现实中多设备间通信方式多种多样(WIFI、蓝牙等),不同的通信方式使用差异大,导致通信问题多;同时还面临设备间通信链路的融合共享和冲突无法处理等挑战。那么分布式软总线实现近场设备间统一的分布式通信管理能力如何呢?
    发表于 03-16 11:03

    vxworks驱动及分布式编程

    本书在内容上分为两部分:驱动篇和分布式编程篇。驱动篇主要介绍了字符设备驱动、增强型网络设备驱动(ENI)以及WindML中文字库的设计和MicroWindows向VxWorks平台上的移植过程;分布式
    发表于 08-26 14:20 0次下载
    vxworks驱动及<b class='flag-5'>分布式</b><b class='flag-5'>编程</b>

    CUDA 6中的统一内存模型

    的,并通过PCI-Express总线相连。在CUDA6之前, 这是程序员最需要注意的地方。CPU和GPU之间共享的数据必须在两个内存中都分配,并由程序直接地在两个内存之间来回复制。这给
    的头像 发表于 07-02 14:08 2766次阅读

    欧拉(openEuler)Summit2021:基于分布式内存池的分布式应用数据交换与共享

    欧拉(openEuler)Summit 2021分布式&多样性计算分论坛上,介绍了基于分布式内存池的分布式应用数据交换与共享,能使全栈性能倍
    的头像 发表于 11-10 15:48 2322次阅读
    欧拉(openEuler)Summit2021:基于<b class='flag-5'>分布式</b><b class='flag-5'>内存</b>池的<b class='flag-5'>分布式</b>应用数据交换与<b class='flag-5'>共享</b>

    通过使用CUDA GPU共享内存

    共享内存是编写优化良好的 CUDA 代码的一个强大功能。共享内存的访问比全局内存访问快得多,因为
    的头像 发表于 04-11 10:03 7320次阅读

    CUDA简介: CUDA编程模型概述

    CUDA 编程模型中,线程是进行计算或内存操作的最低抽象级别。 从基于 NVIDIA Ampere GPU 架构的设备开始,CUDA 编程
    的头像 发表于 04-20 17:16 2970次阅读
    <b class='flag-5'>CUDA</b>简介: <b class='flag-5'>CUDA</b><b class='flag-5'>编程</b>模型概述

    介绍CUDA编程模型及CUDA线程体系

    CUDA 编程模型主要有三个关键抽象:层级的线程组,共享内存和栅同步(barrier synchronization)。
    的头像 发表于 05-19 11:32 1813次阅读
    介绍<b class='flag-5'>CUDA</b><b class='flag-5'>编程</b>模型及<b class='flag-5'>CUDA</b>线程体系

    CUDA编程共享内存

    共享内存是使用__shared__内存空间说明符分配的。
    的头像 发表于 05-19 15:32 1124次阅读
    <b class='flag-5'>CUDA</b><b class='flag-5'>编程</b><b class='flag-5'>共享</b><b class='flag-5'>内存</b>

    如何实现Redis分布式

    Redis是一个开源的内存数据存储系统,可用于高速读写操作。在分布式系统中,为了保证数据的一致性和避免竞态条件,常常需要使用分布式锁来对共享资源进行加锁操作。Redis提供了一种简单而
    的头像 发表于 12-04 11:24 659次阅读