1

据我所知,当扭曲的线程访问全局内存中的相同地址时,请求会被序列化,因此最好使用常量内存。当 GPU 配备 L1 和 L2 缓存级别(在 Fermi 和 Kepler 架构中)时,是否会同时进行全局内存访问的序列化?换句话说,当一个warp的线程访问相同的全局内存地址时,一个warp的31个线程是否会从缓存的存在中受益,因为1个线程已经请求了该地址?当访问是读取以及访问是写入时会发生什么?

4

1 回答 1

3

Fermi 和 Kepler 中同一 warp 中的线程对同一地址的同时全局访问不会被序列化。warp 读取具有广播机制,可以满足来自单个缓存行读取的所有此类读取,而不会影响性能。性能与完全合并读取相同。无论缓存细节如何,这都是正确的,例如,即使 L1 缓存被禁用也是如此。

未指定同时写入的性能(AFAIK),但在行为上,同时写入总是被序列化,并且顺序未定义。

编辑回答以下其他问题:

  1. 即使经线中的所有线程都将相同的值写入相同的地址,它是否会被序列化?难道没有一种可以识别这种情况的写广播机制吗?

没有一种写入广播机制可以查看所有同时写入以查看它们是否都相同,然后基于此采取一些行动。正确的答案是写入以未指定的顺序发生,并且性能特征未定义。显然,如果写入的所有值都相同,则可以确保最终在该位置的值就是那个值。但是,如果您询问写入活动是折叠到单个周期还是需要多个周期才能完成,那么实际行为是未定义的(未记录),实际上可能从一种架构到另一种架构有所不同(例如,cc1.x 可能以所有写入都执行的方式进行序列化,而 cc2.x 可能以一种写入“获胜”而其他所有写入的方式“序列化”丢弃,不消耗实际周期。)同样,性能是未记录/未指定的,但定义了程序可观察的行为。

2 使用您解释的这种广播机制,恒定内存广播访问和全局内存广播访问之间的唯一区别是第一个可以将访问一直路由到全局内存,但后者具有专用硬件并且速度更快,对吗?

__constant__内存使用常量缓存,它是一个专用硬件,可在每个 SM 基础上使用,并以只读方式缓存全局内存的特定部分时尚。此硬件缓存在物理上和逻辑上与 L1 缓存(如果存在并启用)和 L2 缓存是分开的。对于 Fermi 及更高版本,两种机制都支持读取时广播,对于常量缓存,这是首选的访问模式,因为常量缓存每个周期只能服务一次读取访问(即不支持 warp 读取整个缓存行。)任何一种机制都可能在缓存中“命中”(如果存在)或“未命中”并触发全局读取。在第一次读取给定位置(或缓存行)时,缓存都不会有请求的数据,因此它将“错过”并触发全局内存读取,以服务访问。此后,在任何一种情况下,后续读取都将从缓存中取出,假设相关数据在此期间没有被驱逐。对于早期的 cc1.x 设备,恒定内存缓存非常有价值,因为那些早期的设备没有 L1 缓存。对于 Fermi 及其他用户而言,使用常量缓存的主要原因是,如果可识别数据(即只读)和访问模式(每个 warp 的地址相同)可用,那么使用常量缓存将阻止这些读取通过 L1 并可能驱逐其他数据。实际上,您正在稍微增加可缓存的占用空间,而不是 L1 可以单独支持的内容。然后使用常量缓存将阻止这些读取通过 L1 并可能驱逐其他数据。实际上,您正在稍微增加可缓存的占用空间,而不是 L1 可以单独支持的内容。然后使用常量缓存将阻止这些读取通过 L1 并可能驱逐其他数据。实际上,您正在稍微增加可缓存的占用空间,而不是 L1 可以单独支持的内容。

于 2013-11-16T03:38:26.797 回答