whoimi

A geek blog

View on GitHub

下面就是一组线程同时执行,*表示空跑,=表示执行。可以看到他们是同时完成的。一个计算单元的所有线程结束以后,可以开始下一组。

线程A:  =========if==============else**********endif===========
线程B:  =========if**************else==========endif===========

就可以理解为判断只会产生一个遮罩,这个遮罩会决定我这段代码是不是空跑。GPU的计算资源十分紧俏,空跑越多就是我们说的开销大。例如32个线程,每一个都跑不通的分支,那么就相当于性能下降到了1/32。这里的开销是利用率降低而不是时间变长。

关于跑完会等待的。。。GPU一般不会阻塞等待别的线程的(有例外),假如w表示等待。下面的状态是不对的

线程A:  =========if==============else endif===========

线程B:  =========if else=======endif===========wwwwwww

也就是说不存在按照时间最长的分支算开销。

什么情况下会发生优化?那就是下面

线程A:  =========if else======endif===========

线程B:  =========if else======endif===========

下面的状态不会发生:

线程A:  =========if **********************else======endif===========

线程B:  =========if **********************else======endif===========

另外if本身是有开销的。就是下面:

线程A:  =========ifififif **********************elseelse======endif===========

线程B:  =========ifififif **********************elseelse======endif===========

如果我们用了if去切换了很短的语句就是浪费,想下面这种if就没有存在的必要,改成别的方式比较好。

线程A:  =========ifififif elseelse=endif===========

线程B:  =========ifififif elseelse=endif===========

重头戏来了,什么时候if很有用?超高的计算是一种,例如:光追,因为光追的特性可以保证线程成批的走同一个分支,平型光。这个没有研究过就是个大概。

线程A:  =========ifififif 光追左边一点的位置-》》》》》》》》elseelse  ******** endif===========

线程B:  =========ifififif 光追右边一点的位置-》》》》》》》》elseelse  ******** endif===========

另一个就是显存访问。这样走相同的分支,效率更高。

线程A:  =========ifififif  读取纹理 ~~~~~~~~~~~~~~~~ elseelse  endif===========

线程B:  =========ifififif  读取纹理 ~~~~~~~~~~~~~~~~ elseelse  endif===========

可能会存在.

线程A:  =========ifififif  读取纹理 A~~~~~~~~~elseelse  ********************endif==========

线程B:  =========ifififif  *********************elseelse读取纹理 B~~~~~~~~~endif===========

但是GPU有很多个CU,如果大量的CU可以节省一个分支只有少部分会两部分都跑那么这个分支就是有意义的。剩下的时间可以处理别的任务。

上面不是很准确,只是用比较好理解的方式解释一下。不同的GPU架构,都是有自己的特性的。