我正在研究Kepler GPU K40m上随机内存访问的性能。我使用的内核非常简单,如下所示,
__global__ void scatter(int *in1, int *out1, int * loc, const size_t n) {
int globalSize = gridDim.x * blockDim.x;
int globalId = blockDim.x * blockIdx.x + threadIdx.x;
for (unsigned int i = globalId; i < n; i += globalSize) {
int pos = loc[i];
out1[pos] = in1[i];
}
}
也就是说,我将读取一个数组in1以及一个位置数组loc。然后我根据loc置换in1并输出到数组out1。通常,out1 [loc [i]] = in1 [i]。请注意,位置数组已经充分洗牌,每个元素都是唯一的。
我只使用默认的nvcc编译设置并打开-O3标志。 L1 dcache已禁用。另外,我将#块修复为8192,块大小为1024。
我使用nvprof来配置我的程序。很容易知道内核中的大多数指令都应该是内存访问。对于warp的指令,由于每个线程需要一个离散的4字节数据,因此应该多次重放指令(最多31次?)并发出多个内存事务以满足warp中所有线程的需要。但是,度量“inst_replay_overhead”似乎令人困惑:当#tuples n = 16M时,重放开销为13.97,这对我来说很有意义。但是当n = 600M时,重放开销变为34.68。即使是较大的数据,比如700M和800M,重播开销也将达到85.38和126.87。
根据文档,“inst_replay_overhead”的含义是“每条指令执行的平均重放次数”。这意味着当n = 800M时,平均每条指令被重放127次?怎么回放时间比31大得多?我是否误解了某些内容,或者我错过了其他因素,这些因素也会对重播时间产生重大影响?非常感谢!
答案 0 :(得分:1)
您可能误解了指令重播的基本含义。
inst_replay_overhead
包括发出指令的次数,但无法完成。这可能由于各种原因而发生,this answer中对此进行了解释。相关摘录摘自答案:
如果SM由于
而无法完成发出的指令
- 常量高速缓存未命中立即常量(指令中引用的常量),
- 在索引常量负载中解决分歧,
- 解决全局/本地内存加载或存储中的分歧,
- 银行冲突 共享内存加载或存储,
- 解决原子或原子的冲突 减少操作,
- 加载或存储操作需要数据 写入装载存储单元或从超出的装置读取 读/写总线宽度(例如128位加载或存储)或
- 加载缓存未命中 (当数据在缓存中就绪时,会发生重放以获取数据)
醇>然后 SM调度程序必须多次发出指令。这是 称为重播指令。
我猜这是因为您的案例中有分散的读取。这种指令重放的概念也存在于CPU方面。维基百科文章here。