GPGPU OpenCL/CUDA 高性能编程的10大注意事项
当前位置:以往代写 > C/C++ 教程 >GPGPU OpenCL/CUDA 高性能编程的10大注意事项
2019-06-13

GPGPU OpenCL/CUDA 高性能编程的10大注意事项

GPGPU OpenCL/CUDA 高性能编程的10大注意事项

副标题#e#

1.展开轮回

假如提前知道了轮回的次数,可以举办轮回展开,这样省去了轮回条件的较量次数。可是同时也不能使得kernel代码太大。

轮回展开代码例子:

#include<iostream>
using namespace std;
    
int main(){
    int sum=0;
    for(int i=1;i<=100;i++){
        sum+=i;
    }
    
    sum=0;
    for(int i=1;i<=100;i=i+5){
        sum+=i;
        sum+=i+1;
        sum+=i+2;
        sum+=i+3;
        sum+=i+4;
    }
    return 0;
}

2.制止处理惩罚非尺度化数字

OpenCL中非尺度化数字,是指数值小于最小能暗示的正常值。由于计较机的位数有限,暗示数据的范畴和精度都不行能是无限的。(详细可以查察IEEE 754尺度,http://zh.wikipedia.org/zh-cn/IEEE_754)

在OpenCL中利用非尺度化数字,大概会呈现“除0操纵”,处理惩罚很耗时间。

假如在kernel中“除0”操纵影响不大的话,可以在编译选项中插手-cl-denorms-are-zero,如:

clBuildProgram(program, 0, NULL, "-cl-denorms-are-zero", NULL, NULL);

3.通过编译器选项传输常量根基范例数据到kernel,而不是利用private memory

假如措施中需要给kernel 传输常量根基范例数据,最好是利用编译器选项,好比宏界说。而不是,每个work-item都界说一个private memory变量。这样编译器在编译时,会直接举办变量替换,不会界说新的变量,节减空间。

如下面代码所示(Dmacro.cpp):

#include<stdio.h>
int main()
{
    int a=SIZE;
    printf("a=%d, SIZE=%d\n",a,SIZE);
    return 0;
}

编译:

g++ -DSIZE=128 -o A Dmacro.cpp

4.假如共享不重要的话,生存一部门变量在private memory而不是local memory

work-item会见private memory速度快于local memory,因此可以把一部门变量数据生存在private memory中。虽然,当private memory容量满时,GPU硬件会自动将数据转存到local memory中。

5.会见local memory应制止bank conflicts

local memory被组织为一个一个的只能被单独会见的bank,bank之间交错存储数据,以便持续的32bit被生存在持续的bank中。如下图所示:

GPGPU OpenCL/CUDA 高机能编程的10大留意事项

(1)假如多个work-item会见持续的local memory数据,他们就能最大限度的实现并行读写。

(2)假如多个work-item会见同一个bank中的数据,他们就必需顺序执行,严重低落数据读取的并行性。因此,要公道布置数据在local memory中的机关。

(3)非凡环境,假如一个wave/warp中的线程同时读取一个local memory中的一个地点,这时将举办广播,不属于bank 斗嘴。


#p#副标题#e#

6.制止利用”%“操纵

"%"操纵在GPU可能其他OpenCL设备上需要大量的处理惩罚时间,假如大概的话只管制止利用模操纵。

7.kernel中重用(Reuse) private memory,为同一变量界说差异的宏

假如kernel中有两个可能以上的private variable在代码中利用(好比一个在代码段A,一个在代码段B中),可是他们可以被数值沟通。

也就是当一个变量用作差异的目标时,为了制止代码中的定名狐疑,可以利用宏。在一个变量上界说差异的宏。

如下面代码所示:

#include<stdio.h>
int main(){
    int i=4;
    #define EXP i
            printf("EXP=%d\n",EXP);
        
    #define COUNT i
            printf("COUNT=%d\n",COUNT);
    getchar();
    return 0;
}

8.对付(a*b+c)操纵,只管利用 fma function

假如界说了“FP_FAST_FMAF”宏,就可以利用函数fma(a,b,c)准确的计较a*b+c。函数fma(a,b,c)的执行时间小于或便是计较a*b+c。

9.在program file 文件中对非kernel的函数利用inline

inline修饰符汇报编译器在挪用inline函数的处所,利用函数体替换函数挪用。固然会使得编译后的代码占用memory增加,可是省去了函数挪用时上下、函数挪用栈的切换操纵,节减时间。

10.制止分支预测处罚,应该只管使得条件判定为真的大概性大

现代处理惩罚器一般城市举办“分支预测”,以便更好的提前“预取”下一条要执行的指令,使得“取指令、译码阐明、执行、生存”尽大概的并行。

在“分支预测”堕落时,提前取到的指令,不是要执行的指令,就需要按照跳转指令,举办从头取指令,就是“分支预测处罚”。

看如下的代码:

#include<stdio.h>
int main()
{
   int i=1;
   int b=0;
   if(i == 1)
           b=1;
    else
        b=0;
    return 1;
}

对应的汇编代码:

GPGPU OpenCL/CUDA 高机能编程的10大留意事项

(movl 赋值,cmpl 较量,jne 不便是跳转,jmp 无条件跳转)

#p#分页标题#e#

从上面的汇编指令代码看出,假如较量(<main+24>)功效相等,则执行<main+26>也就是较量指令的下一条指令,对应b=1顺序执行;假如较量(<main+24>)功效不相等,则执行跳转到<main+35>,不是顺序执行。

虽然,有的处理惩罚器大概会按照以往“顺序执行”与“跳转执行”的比例来举办分支预测,可是这也是需要积聚的进程。何况并不是,每个处理惩罚器多能这样只能。

本文:http://www.cnblogs.com/xudong-bupt/p/3630952.html

    关键字:

在线提交作业