调度开销是否比实际的线程工作更昂贵?

时间:2017-03-01 16:16:50

标签: metal

最近我在考虑硬优化的可能性。我的意思是那种优化,当你有时从3次迭代硬编码循环只是为了得到一些东西。

所以我想到了一个想法。想象一下,我们有1024个元素的缓冲区。我们希望将它的每个元素乘以2.然后我们创建一个简单的内核,我们传递一个缓冲区,outBuffer,它们的大小(检查我们是否超出边界)和[[thread_position_in_grid]]。然后我们只做一个简单的多重操作并将该数字写入另一个缓冲区。

看起来有点像:

kernel void multiplyBy2(constant float* in [[buffer(0)]],
                            device float* out [[buffer(1)]],
                            constant Uniforms& uniforms [[buffer(2)]],
                            uint gid [[thread_position_in_grid]])
{

    if (gid >= uniforms.buffer_size) { return; }
    out[gid] = in[gid] * 2.0;
}

我关心的是,如果实际的线程工作仍然值得它的调度产生的开销吗?

例如,调度4次线程,做类似的事情会更有效吗

    out[gid * 4 + 0] = in[gid + 0] * 2.0;
    out[gid * 4 + 1] = in[gid + 1] * 2.0;
    out[gid * 4 + 2] = in[gid + 2] * 2.0;
    out[gid * 4 + 3] = in[gid + 3] * 2.0;

这样线程可以工作一段时间吗?或者最好让线程尽可能薄?

1 个答案:

答案 0 :(得分:2)

是的,这不仅仅是在人为的例子中,而且在某些现实场景中也是如此。

对于像你这样极其简单的内核,调度开销可能会影响要完成的工作,但还有另一个因素可能对性能产生更大的影响:共享获取的数据和中间结果。

如果您有一个内核,例如,从输入纹理读取像素的3x3邻域并将平均值写入输出纹理,您可以通过操作更多来共享所获取的纹理数据和相邻像素之间的部分和比你的内核函数中的一个像素多,减少了你发送的线程总数。

也许这就满足了你的好奇心。对于任何实际应用,Scott Hunter都是正确的,您应该在优化之前和之后对所有目标设备进行分析。