关于如何减少线程发散提高程序效率的问题

目前我对 GPU 的流处理器工作原理还不太清楚,关于 SM、block、warp、thread 实在是太绕了,有相关比较通俗易懂的资料吗?或者有通俗一点能够在 taichi 实践上好用的提升效率的技巧?

例如:当我在 taichi 顶层并行 for 内写了很多循环以及 if 来处理不同情况时,应该是会显著降低运行效率的。我的想法是把原本渲染像素的并行 for 内的大量循环提升,不需要同步每个像素的进度(不同像素的运行的循环次数、指令长度有非常大不同,如果提升肯定可以减少每个子任务实际运行指令长度的差异),这样最后结果不会有很大差异,无非是不同像素采样次数不同而已,视觉上差异不大,这样应该会显著带来性能提升?

2 个赞

如果没有理解错你的问题的话,我自己的优化经验是这样的:
比如在ray tracing里,核心的循环可能是:

film = ti.Vector.field(n=3,dtype=ti.f32,shape=(width,height))
for i, j in film:
    rgb = tm.vec3(0.0)
    for n in range(sample_per_pixel):
        rgb += trace(ray)
    rgb = rgb/sample_per_pixel
    some gamma

我的办法法是改成:

film = ti.Vector.field(n=3,dtype=ti.f32,shape=(width,height))
dummy = ti.field(dtype=ti.f32,shape=(width,height,sample_per_pixel))
for i, j, _ in dummy:
     film[i,j] += trace(ray)

for i, j in film:
     film[i,j] = film[i,j]/sample_per_pixel

自己测试下来是有性能提升的,不太清楚可不可以解决你的问题。

1 个赞

我打算把程序拆分为多段管道,把涉及循环和分支比较多的求交、光线反弹分开为多个过程,把产生一个像素的子任务再拆分为更多次小任务…

比如我需要创建一个 hit record buffer 来记录这次光子打到了哪儿,然后在下次顶层 for 继续任务,这样减少一次任务实际会运行指令长度,应该能减少线程发散?

这样的后果是某一帧每个像素的光追深度和采样次数可能不一致,不过对视觉影像应该不大,大概是这个意思,不知道我的思路是否OK(

可以看一下这个paper:

不过实际在taichi里以可跨平台地形式实现queueing还是挺困难的。
之前在taichi里试过,可以看下 https://people.eecs.berkeley.edu/~kubitron/courses/cs262a-F21/projects/reports/project16_poster.pdf (写的很烂,原谅一下xd)

2 个赞

目测dummy没用上,改成ndrange是不是更好