我使用了两个内核,我们称之为A
和B
。
我运行CUDA探查器,这就是它返回的内容:
第一个内核有44%的开销,而第二个内核有20%。
但是,如果我决定按照这个逻辑找出实际执行时间:
timeval tim;
gettimeofday(&tim, NULL);
double before = tim.tv_sec+(tim.tv_usec/1000000.0);
runKernel<<<...>>>(...)
gettimeofday(&tim, NULL);
double after=tim.tv_sec+(tim.tv_usec/1000000.0);
totalTime = totalTime + after - before;
totalTime
非常小,约为0.0001秒。
我是CUDA的新手,我并不清楚究竟发生了什么。我应该尝试使内核更有效率还是已经有效?
答案 0 :(得分:3)
从CPU的角度来看,内核调用是异步的(参见this answer)。如果你按照你没有任何同步的方式计算你的内核(即没有调用cudaDeviceSynchronize()
),你的计时并不意味着什么,因为GPU上的计算仍在进行中。
在计算内核时,您可以信任NVIDIA的分析器(nvprof
/ nvvp
)。 NVIDIA Visual Profiler还可以分析您的程序并提供有关内核可能出错的一些建议:uncoalesced memory accesses,分配的线程/块数量不足等。您还需要在发布模式下编译代码优化标志(例如-O3
)以获得一些相关的时间。
关于内核优化,您需要找到瓶颈(例如您的44%内核),分析它并应用通常的optimization techniques:
- 使用设备的有效带宽来确定内核的性能上限应该是什么
- 最大限度地减少主机和设备之间的内存传输 - 即使这意味着在设备上进行无效的计算
- 合并所有内存访问
- 首选共享内存访问全局内存访问
- 避免代码执行在单个warp中分支,因为这会序列化线程
您也可以使用指令级并行(您应该阅读these slides)。
然而,很难知道何时无法再优化内核。说内核的执行时间很短并不意味着:与什么相比较小?你想做一些实时计算吗?可伸缩性是一个问题吗?这些是在尝试优化内核之前需要回答的一些问题。
另外,您还应广泛使用error checking,并依靠cuda-memcheck
/ cuda-gdb
来调试您的代码。