【问题标题】:CUDA. Shared Memory vs ConstantCUDA。共享内存与常量
【发布时间】:2012-12-04 16:23:51
【问题描述】:

我需要大量的常量数据,超过 6-8 KB,最大到 16 KB。同时我不使用共享内存。现在我想将这个常量数据存储在共享内存中。这是个好主意吗?任何性能近似值?广播是否适用于共享内存和常量?

性能对应用程序至关重要。而且我认为,我的 Tesla C2075 (CUDA 2.0) 上只有 8 KB 常量内存缓存

【问题讨论】:

  • 为什么不直接使用常量内存?
  • 常量数据的访问模式是什么——所有线程是否同时访问同一个常量位置?
  • 您的机器上的恒定内存最高可达 64KB。您所指的 8KB 数字是每个 SM 硬件资源,而不是实际可映射的数量。正如@PaulR 指出的那样,访问模式将是一个考虑因素。共享内存可以很好地与广播(每个线程访问相同内存位置)或合并(每个线程访问连续/连续内存位置)内存访问模式一起工作。只有当每个线程在给定时间访问相同的内存位置时,常量内存才能真正发挥作用。
  • 感谢 cmets!我知道大约 64KB 大小,但是“硬件资源”是什么意思?我想,它只是每个 SM 的一个缓存,如果你使用超过 8 KB 的常量内存,它会很慢,对吗?关于访问模式,好吧,所有线程都不会访问相同的位置,至少并非总是如此。这是否意味着,常量内存(和未合并的共享)会很慢,对我来说最好的方法是共享合并模式?
  • 如果你有 1MB 的 CPU 缓存,是否意味着你只能访问 1MB 的数据?您可以访问超过 1MB,但缓存的有效性将取决于访问模式。对于 GPU 常量内存,最大可映射空间为 64KB。有 8KB 的硬件缓存(每个 SM)将尝试缓存该空间,具体取决于访问模式。访问超过 8KB 可能会也可能不会很慢,这取决于位置和重用。在概念上与 CPU 缓存没有什么不同。如果线程访问不同的位置(在代码中的给定点),常量 mem 不是一个好的选择。

标签: cuda


【解决方案1】:

在计算能力 2.0 中,L1 和共享内存使用相同的内存。 L1 和共享内存之间的分区可以通过cudaFuncSetCacheConfig() 调用来控制。我建议将 L1 设置为最大可能(48K)

cudaFuncSetCacheConfig(MyKernel, cudaFuncCachePreferL1);

然后,从全局内存中提取常量数据,并让 L1 处理缓存。如果您有多个 const 数组,您可以通过在内核参数列表中使用 const 限定符来指示编译器为其中一些使用常量缓存。这样,您可以同时利用 L1 和常量缓存来缓存您的常量。

广播适用于 L1 和常量缓存访问。

【讨论】:

  • 感谢您的回答!我知道 L1 设置,但是我应该如何准确地提取数据,如何确定数据始终被缓存以及访问模式如何(如果不同的线程访问不同的常量)?
  • 使用 L1 代替共享内存的缺点是你不能确定常量总是被缓存。我认为 NVIDIA 没有透露 L1 缓存是什么类型的缓存,但一致认为它是常规关联的。因此,您读取的其他数据可能会推出常量。优点是您不必使用额外的指令来手动管理缓存。
  • 至于访问模式,您只想考虑当一个warp 中的32 个线程遇到执行内存事务的指令时会发生什么。届时,GPU 将调度为所有线程提供服务所需的尽可能多的 128 字节事务。您希望通过使 warp 中的线程同时访问的值尽可能靠近,从而使所需事务的数量尽可能少。如果多个线程读取相同的值,则会自动使用广播。
  • 请记住,除非您的算法受内存限制,否则拥有完美的访问模式或手动管理缓存没有任何好处。使用计算绑定算法,您只需要保持足够好的内存访问,以便计算可以隐藏内存延迟。即使在内存绑定算法中,花费大量时间改进访问模式也可能没有太大的好处。 L1 和 L2 缓存确实有很大帮助,并且改进访问模式对于
  • 给定小于 16 KB 的问题集,您将使用 L1 获得最佳性能。如果您不使用共享,请将缓存增加到 48 KB。 Nsight Visual Studio Edition 和 Visual Profiler 可以提供 L1 缓存统计信息。如果 L1 未命中率很高,那么我会考虑在共享之前查看常量缓存。 Shared 具有必须为每个块重新加载常量数据的开销。 L1 和常量缓存将按需加载。
猜你喜欢
  • 1970-01-01
  • 2012-04-02
  • 2011-06-29
  • 1970-01-01
  • 2011-06-08
  • 2017-04-06
  • 2013-10-20
  • 1970-01-01
  • 2017-05-14
相关资源
最近更新 更多