近一年来,学习CUDA也算是有苦有甜,苦的是遇到问题时的无助、苦恼和迷茫,甜的是问题解决时的兴奋,今天就利用这五一的假期把自己的经验结合CUDA优化的内容写下来,希望对于那些依旧在其中挣扎的同学有所帮助。
一、 测时
判断程序优劣的最简单方式就是计算程序的运行时间,在同一台机器上,运行时间短的程序一般来说是更优的,当然不能一概而论,毕竟决定程序运行速度的因素很多,比如算法,机器的指令集,使用的语言等等。
我们的目的是要设计一个既能够在windows上运行,又能够在linux上运行,既可以用于C,又可以用于CUDA的计时器,同时最好便于扩展。计时的方法很多,如标准C库的time、clock系列函数,CUDA的事件,linux下的gettimeofday,windows下的GetTickCount。
本计时器系列采用C++的面向对象设计方法,基本的思路是设计一个父类,然后再从父类创造子类。这样要建造一个新计时器,只要继承父类就行了。
父类代码如下:
protected :
clock_t startp,endp;
public :
TimeCounter():startp(-1),endp(-1){}
void start(){//设置计时起点
#ifdef __CUDACC__
cudaThreadSynchronize();
#endif
startp=clock();
}
void stop(){//设置计时终点
if(-1==startp){
perror("you must set start point at first");
}else{
#ifdef __CUDACC__
cudaThreadSynchronize();
#endif
endp=clock();
}
}
virtual long getTimeDiff()=0;//返回时间差滴答数
virtual void printTimeDiff()=0;//打印出时间差
};
子类秒计时器代码如下:
public :
long getTimeDiff(){
if(-1==endp){
perror("you must set stop point before invoke this function");
exit(1);
}else{
return (endp-startp)/CLOCKS_PER_SEC;
}
}
void printTimeDiff(){
long temp=getTimeDiff();
printf("use time :%lds/n",temp);
}
};
子类毫秒计时器代码如下:
public :
long getTimeDiff(){
if(-1==endp){
perror("you must set stop point before invoke this function");
exit(1);
}else{
return 1.0f*(endp-startp)/CLOCKS_PER_SEC*1000;
}
}
void printTimeDiff(){
long temp=getTimeDiff();
printf("use time :%ldms/n",temp);
}
};
子类微秒计时器代码如下:
class MicrosecondCounter:public TimeCounter{
public:
long getTimeDiff(){
if(-1==endp){
printf("please set start point or end point/n");
exit(1);
}else{
return 1.0f*(endp-startp)/CLOCKS_PER_SEC*1000000;
}
}
void printTimeDiff(){
long temp=getTimeDiff();
printf("use time:%ld us/n",temp);
}
};
#endif
这种设计使得我们可以声明一个计时器父类引用,而让其实际指向子类,这样,如果精度小了的话,就可以只更改一处,而不用更改其它的内容了。在我的实践中,这种基于对象的多态设计的计时器工作得很好。在开始计时处调用start方法,在计时终点调用stop方法,调用getTimeDiff方法返回经过的时间数,但是这个方法有个问题就是如果两个不同的子类的计时器,其用此函数获得的值不能直接相加减,由于这个问题我本来想将其设置private,但是最终还是让其保持public,因为这符合C/C++的设计思想:程序员是最聪明的,他们应当知道会发生什么,一切由他们来决定。函数printTimeDiff打印计时时间。
如果有一天C语言的clock函数精度达到了微秒,我们只用将包围MicrosecondCounter类的条件编译语句去掉就行了。如果有一天其精度达到了纳秒,我们只用再写一个类继承TimeCounter类就行了,不用改写任何代码。
int main(int argc,char *argv[]){
MicrosecondCounter mc;
TimeCounter& tc = mc;
tc.start();
int a = 0;
for(int i = 0; i < 10000000; i++){
a += 5;
}
tc.stop();
tc.printTimeDiff();
return 0;
}