gpt4 book ai didi

performance - GLSL:为什么本地数组中的随机写入比循环写入慢得多?

转载 作者:行者123 更新时间:2023-12-01 03:14:14 24 4
gpt4 key购买 nike

让我们看一下 GLSL 中的简化示例函数:

void foo() {
vec2 localData[16];
// ...
int i = ... // somehow dependent on dynamic data (not known at compile time)
localData[i] = x; // THE IMPORTANT LINE
}

它写入一些值 x到本地数组中的动态确定索引。
现在,替换行 localData[i] = x;
for( int j = 0; j < 16; ++j )
if( i == j )
localData[j] = x;

制作代码 显着快点。在几个经过测试的示例(不同的着色器)中,执行时间几乎减半,而且发生的事情比这次编写的要多得多。

例如:在一个与顺序无关的透明度着色器中,除其他外,它获取 16 个纹素,时间为 39ms直接写入和 23ms与循环写入。其他什么都没有改变!

测试硬件是 GTX1080。 glGetProgramBinary 返回的程序集还是太高级了。它在第一种情况下包含一行,在第二种情况下包含一个 loop+if 围绕相同的行。
  • 为什么会出现这个性能问题?
  • 这对所有供应商都是如此吗?


  • 猜: localData存储在 8 个 vec4 寄存器中(程序集对此没有任何说明)。我进一步假设,寄存器不能用索引来寻址。如果两者都是真的,那么最终的二进制文件必须使用一些分支结构。循环变体可能会展开并导致 switch - 更快的模式。但这对所有供应商来说都很常见吗?为什么编译器不能使用 for 的任何结果?循环作为此类写入的默认值?

    最佳答案

    进一步的实验表明原因是对数组使用不同的内存类型 . (展开的)循环变体使用寄存器,而随机访问变体切换到本地内存。

    本地内存通常放在全局内存中,但对每个线程都是私有(private)的。对此本地数组的访问很可能会被缓存(L2?)。

    验证这一推理的实验如下:

  • 展开循环的手动版本(在插入排序中测量,16 个元素超过 100 万像素):

    基线:localData[i] = x 33毫秒
    For 循环:for j + if i=j 16.8ms
    开关:switch(i) { case 0: localData[0] ... : 16.92 毫秒
    If else 树(分成两半):16.92ms
    如果列表(普通手动展开):16.8ms

    => 各种分支结构导致或多或少相同的时间。因此,正如最初猜测的那样,这并不是一个糟糕的分支行为。
  • 多对一对无随机访问(32 元素插入排序)

    2x localData[i] = x 47毫秒
    1x localData[i] = x 45毫秒
    0x localData[i] = x 16ms

    => 只要至少有一次随机访问,性能就会很差。这意味着有一个全局决策改变了 localData 的行为。 -- 很可能是使用了不同的内存。由于缓存,使用多个随机访问不会使事情变得更糟。
  • 关于performance - GLSL:为什么本地数组中的随机写入比循环写入慢得多?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49818414/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com