2015/2/1
算法背景:sharpness算法
问题情况:对于upscale的center处理,将原来每个线程处理四个,改为只处理一个,运行时间降为原来的13%,本来预计的是每个线程处理四个数据可以合并部分数据访问,可以减少数据重复读取,但是事实是,向量化性能反而不好。upscale访问如下所示。
原因分析:对于减少相邻数据读取量这点儿,对于现代的GPU几乎是没有什么影响的,因为现代的GPU的cache已经做得很好的,能保证较高的命中率(在较老的卡上进行Sobel的向量化,性能有提升,因为老卡的cache做的不好。Sobel数据访问如上图所示,据上图可知,Sobel的性能瓶颈为数据读过程。向量化后,数据读取量降为原来的1/2,Sobel也大概获得两倍的性能提升,所以更进一步验证了数据读过程为性能瓶颈)。在这个算法实现过程中,比较耗时的是数据写过程,这个是性能瓶颈。一次处理要写16*4的数据,容易产生channel冲突(么?),造成写效率下降,使算法效率降低。
越简单,越高效。
每个线程处理的数据太多,线程间,数据访问区域间隔大,不利于让多个线程共用一个cache line.
2015/8/17
在调试多卡多线程pdf程序时,多卡未获得线性性能加速比。
多卡多线程pdf程序实现:通过为每个device设置单独的线程,enqueue独立的kernel执行。
问题分析:pdf的kernel执行时间非常,但是线程间很多需要barrier的地方(单卡单线程时不存在这个问题),而且barrier还有一定的工作需要完成(不重要,主要还是barrier),造成CPU部分占时较多,barrier的大量同步,使得线程间相互等待,导致多卡多线程无法获得线性加速比。
解决方案:通过增加每次kernel调用是kernel的任务量(workgroup per cu),提高加速比。随着任务量的增加,线程间执行时间趋向于基本同步,所以需要互相等待的时间会缩短(maybe),或者相互等待的时间不变或稍微增加,但是因为每次等待的时间倍相应次kernel的大量任务所均摊,最后使得等待时间所占比重减少,so使得最后程序获得了接近线性的加速比。
多卡单线程RAR程序时,8卡只获得了6倍的加速比。
实现:一个线程用for循环为每个设备enqueue相同的kernel,最后在for循环finish。其中,相对cpu执行时间,kernel执行的时间很长,所以cpu时间可以忽略不计。
尝试:同样尝试通过将单次kernel执行任务执行,但是只有单卡的性能有少量提升,多卡的性能没有提升,
准备尝试:也按照多卡多线程来实现。
2015/8/18
在S9000上,把一个kernel中的寄存器数组和local memory数组分配成最大的数组大小,而不是根据不同输入设置不同的数组大小,以节省寄存器。这个改动在W8000上会引起性能下降,而在S9000上却没有什么变化。
得出结论:gpu代码在换了设备之后,有些之前得到的结论可能就不成立了,需要测试,所以要明确地明白之前性能结论的原因,而不是仅仅通过测试结果得出结论。
2015/8/18
今天解决了一个问题,就是rar_head_check算法的异常退出,是因为有一个“死循环”,while(len--),当系统发现死循环之后就会直接退出,和exit(1)似得但是不会报任何错误。
2015/8/31
问题:OepnCL性能调优,8卡却一直是4倍加速比,而且总是会使其中两个卡的问题,和RAR的情况一样,对于RAR是将THREADS_PER_WKGROUP改为64就ok了,但是这个改过后brute没有问题了,dic却还是有问题。
原因:data数组的大小是性能瓶颈。在dic的kernel代码里,data数组(local)被开辟为固定大小的,按照每个WORKGROUP里有256个线程开的,将THREADS_PER_WKGROUP改为64后这个data数组还是这么大,所以性能就没有改善。
体会:当时其实是看到这个问题了的,但是就觉得是人家的kernel代码,自己没有必要再去看,再改的,也觉得怕给改坏了,有失正确性。其实就是懒,但是要是好好看看人家的代码,试着给改改,问题就早解决了。
体会就是遇到觉得有问题的地方,一定要追根究底,把他给解决好。
2015/10/28
在TK1上调试cuda程序性能
问题: 一样的代码一样的机子,程序性能不佳(GPU频率也一样)
解决:重启电脑
2015、11、6
屡次经验证明(sharpness的upscale,当时采用向量化优化,性能下降,可能是因为算法复杂度增大,访存粒度太大; RAR用shared memory,缓存全局数据,性能没有提升; warp_affine使用shared memory缓存数据,以减少重复的全局数据访问,但是由于算法复杂度增加太多,程序性能也是下降了),如果是因为在全局访存中存在冗余访问,而且数据局部性很好,就用shared memory或者向量化进行访存优化的,以减少全局内存访问量,一般是没有优化效果,相反,由于优化后的算法要么算法实现更加复杂,要么线程粒度增大,反而导致优化后的算法性能下降。
性能没有提升的原因是,冗余访存这点,不用担心,因为现在的GPU架构已经将访存合并,以及缓存做的很好了,cache命中率应该也是很不错了,所以如果数据局部性好,冗余的访存基本也是很少存在的。
对于矩阵转置那种,数据访问局部性太差,缓存一下效果,重组数据访问,性能提升会很明显~~~
对于访存优化需要注意的就是访存的单位,访存int4,float4一般都是很好的~
性能实现的比较好的是计算的优化,计算上面的优化包括:计算本身的优化,冗余计算换为避免,换成访存的优化。计算优化感觉是无法被硬件优化掉的吧,否则感觉以后我就得失业了。
还需要注意的是,寄存器优化,寄存器使用超过256,会导致部分寄存器中的数据转存至全局内存。