CUDA学习(九):共享内存


博主CUDA学习系列汇总传送门(持续更新):编程语言|CUDA入门


转自 CUDA学习笔记(6) 共享内存与全局内存

  共享内存(Shared memory)是位于每个流处理器组(SM)中的高速内存空间,主要作用是存放一个线程块(Block)中所有线程都会频繁访问的数据。流处理器(SP)访问它的速度仅比寄存器(Register)慢,它的速度远比全局显存快。但是他也是相当宝贵的资源,一般只有几十KByte,

  这里以我电脑上的“Quadro K620”为例:

硬件资源参数
流处理器(SP)128 * 3 = 384
流处理器组(SM/SMM)3
全局显存(Global memory)2048MByte
每个SM中的共享内存(Shared memory)64KByte
每个SM中的寄存器(Register)65536个32bit寄存器


  可以看到全局显存(Global memory)的大小比共享显存(Shared memory)大了几个数量级。当然,共享显存的访问速度也一定比全局显存快。再从硬件上看:

这里写图片描述

  每个流处理器组(SM)都拥有属于自己的共享显存(Shared memory)且大小只有64KByte,而这些流处理器组(SM)都位于同一块芯片上(on the same chip),这块芯片又通过PCB电路连接内存芯片(DRAM)。

  • 流处理器(SP)共享显存(Shared memory)上数据的访问属于片上访问,可以立刻取得数据。
  • 流处理器(SP)内存芯片(DRAM)的访问要通过请求内存控制器等一系列操作,然后才能得到数据。

  为了能够明显的看到共享显存(Shared memory)的速度优势,我们就需要把那些被频繁访问的数据直接放到共享显存(Shared memory)中,这样我们的程序在执行时就可以避免频繁访问全局显存(Global memory),导致时间浪费在数据的传输和访问上。

  举个例子,我们需要统计一张超高清图片或者20Mbyte大小的一维数组中每个数值的个数,也就是做直方图统计,结合前面的原子操作(Atomic functions)可以将计算时间至少减半,当然不同架构的GPU会有不同程度的优化。

*注4:直方图统计用于记录一组数据中的数值分布情况,即每个数值出现了多少次,统计数值的分布。

  方案一:

  1. 统计数值分布的数组直接放在全局显存(Global memory)中,每个线程依次读取全局显存中的待统计数据。
  2. 然后使用原子操作对统计数组(Global)中与源数据中数值所对应的元素执行“++”。

  方案二:

  1. 统计数值分布的数组放在全局显存(Global memory)中,每个线程块拥有一个自己的统计数组(Shared)放在共享显存(Shared memory)中。
  2. 线程块中的每个线程依次读取全局显存中的待统计数据,然后使用原子操作对统计数组(Shared)中与源数据中数值所对应的元素执行“++”。
  3. 对线程块中的线程同步,以保证该线程块中的所有线程都已经完成原子操作。
  4. 将当前线程块中的统计数组(Shared)加到统计数组(Global)中。

  这样,方案二就通过使用共享显存(Shared memory)避免了对全局显存(Global memory)的频繁访问,以达到提高程序运行速度的效果。

  方案一核函数的实现:

结果是:方案而统计10MByte大小数据的直方图使用了7.33毫秒

  这里我使用了两个寄存器“counter_1, counter_2”来保证记录时间的准确性,通过实验,流处理器(SP)访问寄存器的时间只有6个时钟周期(大约6纳秒),而单个线程耗时越3000个时钟周期,有较高的可信度。

  就结果而言,加速比达到了160%160%甚至更多。



  下面补充一个SMM的结构,SMM是SM的改良变种,与SM的功能完全相同。区别在于它的内部将流处理器(SP)以及寄存器(Register)等区域分成了4块,主要目的是获取更大的带宽。

这里写图片描述

  我认为只要原因是我的“Quadro K620”显卡专门对此做过硬件改良,使用SMM的结构代替原来传统的SM结构,大大增加了带宽。同时也拥有2MByte之大的二级缓存,大大增加了访问全局显存(Global memory)的速度,因此使用共享显存(Shared memory)加速比不如其他游戏型显卡高。这些可以在 参考文献5 中查证。

参考:

1.《CUDA并行程序设计》机械工业出版社

2.NVIDIA官方原子操作说明文档

3.CUDA Toolkit Documation

4.CUDA Toolkit Documation Shared memory篇

5.GM107芯片白皮书 NVIDIA GeForce GTX 750 Ti Whitepaper

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用 CUDA 加速深度学习训练时,共享GPU内存是一种常见的技术,它可以有效地减少显存的使用,提高GPU利用率。下面是使用共享GPU内存的一些方法: 1. 使用 PyTorch 中的 `pin_memory` 和 `DataLoader` 函数:在 PyTorch 中,可以使用 `pin_memory` 函数将数据加载到主机内存中,然后使用 `DataLoader` 函数将数据加载到 GPU 内存中,并使用 `num_workers` 参数指定共享的 CPU 内存数。 ```python import torch.utils.data as data train_dataset = MyDataset() train_loader = data.DataLoader(train_dataset, batch_size=64, shuffle=True, num_workers=4, pin_memory=True) ``` 2. 使用 PyTorch 中的 `SharedMemory` 函数:在 PyTorch 中,可以使用 `SharedMemory` 函数创建共享内存,并将数据加载到共享内存中,然后使用 `DataLoader` 函数将数据加载到 GPU 内存中。 ```python import torch.multiprocessing as mp def load_data_to_shared_memory(): shared_memory = mp.shared_memory.SharedMemory(size=10000) data = torch.zeros(100, dtype=torch.float32, pin_memory=True) data_ptr = data.storage().data_ptr() shared_memory_ptr = shared_memory.buf shared_data = torch.tensor(shared_memory_ptr, size=(100,), dtype=torch.float32) shared_data.copy_(data) train_dataset = MyDataset() load_data_to_shared_memory() train_loader = data.DataLoader(train_dataset, batch_size=64, shuffle=True, num_workers=4, pin_memory=True) ``` 3. 使用 TensorFlow 中的 `tf.data` 函数:在 TensorFlow 中,可以使用 `tf.data` 函数将数据加载到 CPU 内存中,并使用 `map` 函数将数据加载到 GPU 内存中。 ```python import tensorflow as tf def preprocess(image, label): # 在 GPU 内存中处理数据 return image, label train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(64) train_dataset = train_dataset.map(preprocess).shuffle(10000).repeat() ``` 总的来说,共享GPU内存是一种有效的技术,可以提高GPU利用率,减少显存的使用。在实际应用中,可以根据具体情况选择合适的方法,以便更好地利用GPU资源。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值