gpt4 book ai didi

c++ - 为什么我不是分支预测的受害者?

转载 作者:行者123 更新时间:2023-11-30 02:34:50 26 4
gpt4 key购买 nike

我正在编写一个函数来创建高斯滤波器(使用 Armadillo 库),它可以是 2D 或 3D,具体取决于它接收到的输入的维数。这是代码:

template <class ty>
ty gaussianFilter(const ty& input, double sigma)
{
// Our filter will be initialized to the same size as our input.
ty filter = ty(input); // Copy constructor.

uword nRows = filter.n_rows;
uword nCols = filter.n_cols;
uword nSlic = filter.n_elem / (nRows*nCols); // If 2D, nSlic == 1.

// Offsets with respect to the middle.
double rowOffset = static_cast<double>(nRows/2);
double colOffset = static_cast<double>(nCols/2);
double sliceOffset = static_cast<double>(nSlic/2);

// Counters.
double x = 0 , y = 0, z = 0;

for (uword rowIndex = 0; rowIndex < nRows; rowIndex++) {
x = static_cast<double>(rowIndex) - rowOffset;
for (uword colIndex = 0; colIndex < nCols; colIndex++) {
y = static_cast<double>(colIndex) - colOffset;
for (uword sliIndex = 0; sliIndex < nSlic; sliIndex++) {
z = static_cast<double>(sliIndex) - sliceOffset;
// If-statement inside for-loop looks terribly inefficient
// but the compiler should take care of this.
if (nSlic == 1){ // If 2D, Gauss filter for 2D.
filter(rowIndex*nCols + colIndex) = ...
}
else
{ // Gauss filter for 3D.
filter((rowIndex*nCols + colIndex)*nSlic + sliIndex) = ...
}
}
}
}

如我们所见,在最内层的循环中有一个 if 语句,它检查第三维(nSlic)的大小是否等于 1。一旦在函数的开头计算,nSlic 将不会改变它的值,所以编译器应该足够聪明来优化条件分支,我不应该损失任何性能。

但是...如果我从循环中删除 if 语句,我将获得性能提升。

if (nSlic == 1)
{ // Gauss filter for 2D.
for (uword rowIndex = 0; rowIndex < nRows; rowIndex++) {
x = static_cast<double>(rowIndex) - rowOffset;
for (uword colIndex = 0; colIndex < nCols; colIndex++) {
y = static_cast<double>(colIndex) - colOffset;
for (uword sliIndex = 0; sliIndex < nSlic; sliIndex++) {
z = static_cast<double>(sliIndex) - sliceOffset;
{filter(rowIndex*nCols + colIndex) = ...
}
}
}
}
else
{
for (uword rowIndex = 0; rowIndex < nRows; rowIndex++) {
x = static_cast<double>(rowIndex) - rowOffset;
for (uword colIndex = 0; colIndex < nCols; colIndex++) {
y = static_cast<double>(colIndex) - colOffset;
for (uword sliIndex = 0; sliIndex < nSlic; sliIndex++) {
z = static_cast<double>(sliIndex) - sliceOffset;
{filter((rowIndex*nCols + colIndex)*nSlic + sliIndex) = ...
}
}
}
}

在使用 g++ -O3 -c -o main.o main.cpp 编译并测量两种代码变体的执行时间后,我得到以下结果:
(1000 次重复,大小为 2048 的二维矩阵)

如果在里面:

  • 66.0453 秒
  • 64.7701 秒

如果在外面:

  • 64.0148 秒
  • 63.6808 秒

如果 nSlic 的值甚至没有改变,为什么编译器不优化分支?我必须重组代码以避免 for 循环中的 if 语句?

最佳答案

在循环中有一个额外的变量会影响寄存器的使用,这可能会影响时序,即使分支预测工作正常。您需要查看生成的程序集才能知道。它还可能影响难以检测的缓存命中率。

关于c++ - 为什么我不是分支预测的受害者?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34278437/

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