预编译的多维数组访问
Precompiled Multi-Dimensional Array Access
想象一下像这样计算一个三维数组:
for (int i = 0; i < I; i++)
{
for (int j = 0; j < J; j++)
{
for (int k = 0; k < K; k++)
{
array[k + j * K + i * K * J] = someValue(i, j, k);
}
}
}
但是 k + j * K + i * K * J
部分有点贵。是否可以告诉编译器将循环转换成这样的形式?
array[0] = someValue(0, 0, 0);
array[1] = someValue(0, 0, 1);
array[2] = someValue(0, 0, 2);
array[3] = someValue(0, 1, 0);
...
这当然会使二进制文件更大,但如果此代码被执行很多,也会加快性能。是否有可能做到这一点?还是我必须自己生成代码并将其粘贴到源文件中?
我相信在你的特殊情况下,我们可以 re-write 循环为:
auto* scan = array;
for (int i = 0; i < I; i++)
{
for (int j = 0; j < J; j++)
{
for (int k = 0; k < K; k++)
{
*scan++ = someValue(i, j, k);
}
}
}
这是一个 micro-optimization,不是您通常需要担心的事情。原因如下。
原因 1: 整数乘法非常便宜。计算 k + j * K + i * K * J
比从计算机的 RAM 中检索一个值更便宜,而且它与从 CPU 的最快缓存中检索它一样便宜(如果不便宜的话)。
原因 2: 编译器非常聪明。他们可以识别哪些值发生变化,哪些值保持不变,并优化 common sub-expressions 循环外(这样他们就不会多次执行相同的计算)。
原因 3: 编译器能够利用矢量化指令。根据 someValue
的作用,它可以利用这一点在同一个内核上并行计算多个值。对于索引到 array
的任何一种方法都是如此。
C++ 代码不是严格强制的。编译器可以并且确实进行了重大而复杂的优化以使代码更高效,并且像您示例中的代码这样的代码很容易优化。
想象一下像这样计算一个三维数组:
for (int i = 0; i < I; i++)
{
for (int j = 0; j < J; j++)
{
for (int k = 0; k < K; k++)
{
array[k + j * K + i * K * J] = someValue(i, j, k);
}
}
}
但是 k + j * K + i * K * J
部分有点贵。是否可以告诉编译器将循环转换成这样的形式?
array[0] = someValue(0, 0, 0);
array[1] = someValue(0, 0, 1);
array[2] = someValue(0, 0, 2);
array[3] = someValue(0, 1, 0);
...
这当然会使二进制文件更大,但如果此代码被执行很多,也会加快性能。是否有可能做到这一点?还是我必须自己生成代码并将其粘贴到源文件中?
我相信在你的特殊情况下,我们可以 re-write 循环为:
auto* scan = array;
for (int i = 0; i < I; i++)
{
for (int j = 0; j < J; j++)
{
for (int k = 0; k < K; k++)
{
*scan++ = someValue(i, j, k);
}
}
}
这是一个 micro-optimization,不是您通常需要担心的事情。原因如下。
原因 1: 整数乘法非常便宜。计算 k + j * K + i * K * J
比从计算机的 RAM 中检索一个值更便宜,而且它与从 CPU 的最快缓存中检索它一样便宜(如果不便宜的话)。
原因 2: 编译器非常聪明。他们可以识别哪些值发生变化,哪些值保持不变,并优化 common sub-expressions 循环外(这样他们就不会多次执行相同的计算)。
原因 3: 编译器能够利用矢量化指令。根据 someValue
的作用,它可以利用这一点在同一个内核上并行计算多个值。对于索引到 array
的任何一种方法都是如此。
C++ 代码不是严格强制的。编译器可以并且确实进行了重大而复杂的优化以使代码更高效,并且像您示例中的代码这样的代码很容易优化。