C++ 使用OpenCL的英特尔HD 6000本地内存带宽
我正在OpenCL中进行一些局部/全局内存优化;从两年前的情况来看,我认为我做错了什么,因为本地内存IO似乎比它应该的慢很多。我的GPU是Intel HD 6000 这是我的测试设置,内核源代码:C++ 使用OpenCL的英特尔HD 6000本地内存带宽,c++,c,memory-management,opencl,gpgpu,C++,C,Memory Management,Opencl,Gpgpu,我正在OpenCL中进行一些局部/全局内存优化;从两年前的情况来看,我认为我做错了什么,因为本地内存IO似乎比它应该的慢很多。我的GPU是Intel HD 6000 这是我的测试设置,内核源代码: __kernel void vecAdd(__global float* results, const unsigned int n, __local float* loc) { int id = get_global_id(0); if(id < n) { float
__kernel void vecAdd(__global float* results, const unsigned int n, __local float* loc)
{
int id = get_global_id(0);
if(id < n) {
float rtemp = 0;
loc[23] = 34;
for(int i = 0; i < 1024; i ++) {
rtemp += loc[(i * 445) % 1024];
}
results[id] = rtemp;
}
}
\uuuuu内核void vecAdd(\uuuu全局浮点*结果,常量unsigned int n,\uuuuu局部浮点*loc)
{
int id=获取全局id(0);
if(id
内核所做的就是获取本地浮点数组loc并将其随机值添加到全局输出向量中。片段“(i*445)%1024”用于确保随机访问本地内存;性能比最后提到的没有随机化的数字稍微好一点(加速约30%)
- 我将内核排队等待16777216/16M次迭代,工作组大小为256,本地缓冲区为1024个浮点数,除l[23]外都是零
- 总的来说,这使得对本地内存的总写入量为16M*1=16M,读取量为16M*1024=16G
- 还有大约16M*1024*2的浮点运算,可能更多地取决于模的计算方式,但HD 6000的浮点性能大约为768千兆次,这不应该成为瓶颈
- 16G浮点值读取导致64G内存被读取;内核的执行耗时453945μs,估计本地内存带宽151gb/s
是否有任何可能的方法从本地内存中挤出更多的性能,或者我是否尽可能有效地利用本地内存?答案位于edit2答案末尾的部分 如果专用gpu计时不好,您可以尝试流水线读取+计算+写入操作,如 从左到右,它在第二步开始重叠操作,因此计算延迟被隐藏,然后第三步也隐藏写入延迟。这是一个将独立作品分成4部分的示例。也许更多的部件会产生较慢的结果,每个设备都应该进行基准测试。内核执行只是一个“添加”,所以它总是隐藏的,但较重的可能不是。如果图形卡可以同时执行读写操作,这将减少I/O延迟。图中还显示了空闲(垂直空)的时间线,因为冗余的同步使其比打包但更快的版本更可读 您的igpu 151 GB/s带宽可能是cpu缓存。它没有可寻址的寄存器空间,所以即使使用_私有寄存器也可以使它从缓存中获取。每个cpu或gpu的缓存线宽度也不同 loc[23]=34 具有多个线程的争用条件并被序列化 而且有可能 对于(int i=0;i<1024;i++){ rtemp+=loc[(i*445)%1024]; } 自动展开并对指令缓存和缓存/内存施加压力。您可以尝试不同级别的展开 您确定每个igpu执行单元使用8个内核吗?可能每个EU只使用1个内核,这可能不足以充分强调缓存/内存(例如,使用所有第一个内核而不使用其他内核导致缓存线冲突)?尝试使用float8版本,而不是仅仅使用float。最新的英特尔CPU每秒超过1 TB GFLOPS限值很少接近。大约有%50个代码经过优化,75个代码无法读取,90个代码没有意义
编辑:下面的代码是在AMD-R7-240卡上以900MHz(不超过30Gb/s内存和600GFLOPS)运行的,用于16M个结果元素
__kernel void vecAdd(__global float* results )
{
int id = get_global_id(0);
__local float loc[1024]; // some devices may slow with this
if(id < (4096*4096)) {
float rtemp = 0;
loc[23] = 34;
for(int i = 0; i < 1024; i ++) {
rtemp += loc[(i * 445) % 1024];
}
results[id] = rtemp;
}
}
\uuuuu内核void vecAdd(\uuuu全局浮点*结果)
{
int id=获取全局id(0);
__本地浮点loc[1024];//某些设备可能会因此而变慢
如果(id<(4096*4096)){
浮动rtemp=0;
loc[23]=34;
对于(int i=0;i<1024;i++){
rtemp+=loc[(i*445)%1024];
}
结果[id]=rtemp;
}
}
花了
- 写入+计算+读取575毫秒(无管道)
- 写入+计算+读取530毫秒(两部分流水线)
- 写入+计算+读取510毫秒(8部分流水线)
- 计算时间为455毫秒(140 GB/s本地内存带宽)
__kernel void vecAdd(__global float* results )
{
int id = get_global_id(0);
int idL = get_local_id(0);
__local float loc[1024];
float rtemp = 0;
if(id < (4096*4096)) {
loc[23] = 34;
}
barrier (CLK_LOCAL_MEM_FENCE);
if(id < (4096*4096)) {
for(int i = 0; i < 1024; i ++) {
rtemp += loc[(i * 445+ idL) & 1023];
}
results[id] = rtemp;
}
}
\uuuuu内核void vecAdd(\uuuu全局浮点*结果)
{
int id=获取全局id(0);
int idL=获取本地id(0);
__本地浮点数[1024];
浮动rtemp=0;
如果(id<(4096*4096)){
loc[23]=34;
}
屏障(CLK_本地_MEM_围栏);
如果(id<(4096*4096)){
对于(int i=0;i<1024;i++){
rtemp+=loc[(i*445+idL)和1023];
}
结果[id]=rtemp;
}
}
- 写入+计算+读取325毫秒(16部分流水线)
- 270mil
__kernel void vecAdd(__global float* results ) { int id = get_global_id(0); int idL = get_local_id(0); __local float loc[1024]; float rtemp = 0; float rtemp2 = 0; float rtemp3 = 0; float rtemp4 = 0; if(id < (4096*4096)) { loc[23] = 34; } barrier (CLK_LOCAL_MEM_FENCE); if(id < (4096*4096)) { int higherLimitOfI=1024*445+idL; int lowerLimitOfI=idL; int stepSize=445*4; for(int i = lowerLimitOfI; i < higherLimitOfI; i+=stepSize) { rtemp += loc[i & 1023]; rtemp2 += loc[(i+445) & 1023]; rtemp3 += loc[(i+445*2) & 1023]; rtemp4 += loc[(i+445*3) & 1023]; } results[id] = rtemp+rtemp2+rtemp3+rtemp4; } }