我使用的是NVidia视觉分析器(基于eclipse的CUDA 5.0 beta版本)和Fermi电路板,我对两个性能指标有些不了解:
全局加载/存储效率表示实际内存事务数与请求的事务数之比。
全局内存指令重放,表示由于次优内存合并导致重放而发出的指令百分比。
我的印象是,如果加载/存储效率为100%(即完美合并),则全局存储器指令重放应为0,但我已经看到了具有100%效率和非零全局存储器指令重放的示例。怎么样?
THX
答案 0 :(得分:2)
据我所知,全局加载/存储效率由全局内存访问模式决定,而全局内存指令重放主要由分支发散引起。因此,即使所有内存访问都已合并但存在一些分歧,您所描述的情况也可能发生。
P.S。您能否举一些例子,其中次优内存合并访问会导致全局内存指令重放?
答案 1 :(得分:2)
简短的回答是单个warp事务的大小有128 B限制(由于我认为总线宽度)。因此,如果您的warp需要需要256 B的合并数据,那么您必须重播第二个128 B的指令。
通常,事务仅在32B,64B和128B段中移动数据。如果你的warp事务不符合其中一个,那么你将至少重放一次指令。合并模式不能避免这种情况,但它们确实有助于最小化事务。例如,在warp中合并访问字节会获得32B事务。经线内的合并4B访问(int或浮点数)可以获得单个128B事务。
考虑以下内核:
__global__ void
gmemtest(const double* const src, double* const dest, const int size,
const int eleMoved){
int block_fst = blockIdx.x*blockDim.x*eleMoved;
size_t thread_fst = block_fst + threadIdx.x*eleMoved;
#pragma unroll
for(size_t i = 0; i < eleMoved; i++){
if( thread_fst + i < size )
dest[thread_fst + i] = src[thread_fst + i];
}
现在使用大小为1,2,4和8的elemoved
运行它。您会发现随着elemoved
变大,内核的重放会增加。以下主机端循环将以128和256的块大小命中所有这些循环。
for(size_t j = 1; j<3; j++){
for(size_t i = 1; i<=8; i *= 2){
size_t n_threads = j*128;
size_t ele_per_thread = i;
size_t tot_threads = ((SIZE-1)/ele_per_thread)+1;
size_t n_blocks = ((tot_threads - 1)/n_threads)+1;
gmemtest<<<n_blocks,n_threads>>>(d_src,d_dest,SIZE,ele_per_thread);
}
}
正在运行nvprof --print-gpu-trace --metrics inst_replay_overhead
:
==22053== Profiling result:
Device Context Stream Kernel Instruction Replay Overhead
Tesla K20c (0) 1 2 gmemtest(double cons 0.191697
Tesla K20c (0) 1 2 gmemtest(double cons 0.866548
Tesla K20c (0) 1 2 gmemtest(double cons 3.472359
Tesla K20c (0) 1 2 gmemtest(double cons 7.444514
Tesla K20c (0) 1 2 gmemtest(double cons 0.175090
Tesla K20c (0) 1 2 gmemtest(double cons 0.912531
Tesla K20c (0) 1 2 gmemtest(double cons 4.067719
Tesla K20c (0) 1 2 gmemtest(double cons 7.576686
在实践中,如果您正在移动类似于double2
数据的经线,您可能会遇到此问题。
如果你真的想涉及与绩效相关的问题,我不能推荐这个话题:Micikevicius - "Performance Optimization: Programming Guidelines and GPU Architecture Details Behind Them"