针对交叉模式访问的 SIMD 优化
SIMD optimisation for cross-pattern access
我正在尝试编写 Ising 模型的蒙特卡洛模拟,我想知道是否可以使用 SIMD 优化来以交叉模式访问数据。
我基本上想知道是否有任何加速此功能的方法。
//up/down/left/right stencil accumulation
float lattice::compute_point_energy(int row, int col) {
int accumulator=0;
accumulator+= get(row? row-1: size_-1, col);
accumulator+= get((row+1)%size_, col);
accumulator+= get(row, col? col-1: size_-1);
accumulator+= get(row, (col+1)%size_) ;
return -get(row, col) * (accumulator * J_ + H_);
}
get(i, j)
是一种访问 short
的平面 std::vector
的方法。我看到可能存在一些问题:访问有很多三元逻辑正在进行(对于周期性边界条件),并且向量元素的 none 是相邻的。是要对这个块进行 SIMD
优化,还是应该继续挖掘?使用不同的容器(例如数组或不同类型的向量)重新实现邻接矩阵 and/or 是一种选择。
SIMD 是您最不想尝试使用此功能的东西。
我 认为 您正在尝试使用 up/down/left/right 4-stencil 进行计算。如果是这样,您的代码应该有注释说明这一点。
由于在三元运算符处可能发生分支并且模数相对较慢,因此您在该函数中损失了很多速度。
您最好将正在操作的二维 space 包围起来,将一圈单元格设置为适合处理边缘效应的值。这允许您消除对边缘效应的检查。
为了访问您的模板,我发现使用类似以下内容通常很有效:
const int width = 10;
const int height = 10;
const int offset[4] = {-1,1,-width,width};
double accumulator=0;
for(int i=0;i<4;i++)
accumulator += get(current_loc+offset[i]);
请注意,迷你阵列已预先计算出您域中相邻单元格的偏移量。一个好的编译器可能会展开上述循环。
完成所有这些操作后,选择适当的优化标志可能会导致自动矢量化。
实际上,代码中的分支和 mod 可能会阻止自动矢量化。您可以通过启用适当的标志来检查这一点。对于英特尔编译器集合 (icc),您需要:
-qopt-report=5 -qopt-report-phase:vec
对于 GCC,您需要(如果我没记错的话):
-fopt-info-vec -fopt-info-missed
我正在尝试编写 Ising 模型的蒙特卡洛模拟,我想知道是否可以使用 SIMD 优化来以交叉模式访问数据。
我基本上想知道是否有任何加速此功能的方法。
//up/down/left/right stencil accumulation
float lattice::compute_point_energy(int row, int col) {
int accumulator=0;
accumulator+= get(row? row-1: size_-1, col);
accumulator+= get((row+1)%size_, col);
accumulator+= get(row, col? col-1: size_-1);
accumulator+= get(row, (col+1)%size_) ;
return -get(row, col) * (accumulator * J_ + H_);
}
get(i, j)
是一种访问 short
的平面 std::vector
的方法。我看到可能存在一些问题:访问有很多三元逻辑正在进行(对于周期性边界条件),并且向量元素的 none 是相邻的。是要对这个块进行 SIMD
优化,还是应该继续挖掘?使用不同的容器(例如数组或不同类型的向量)重新实现邻接矩阵 and/or 是一种选择。
SIMD 是您最不想尝试使用此功能的东西。
我 认为 您正在尝试使用 up/down/left/right 4-stencil 进行计算。如果是这样,您的代码应该有注释说明这一点。
由于在三元运算符处可能发生分支并且模数相对较慢,因此您在该函数中损失了很多速度。
您最好将正在操作的二维 space 包围起来,将一圈单元格设置为适合处理边缘效应的值。这允许您消除对边缘效应的检查。
为了访问您的模板,我发现使用类似以下内容通常很有效:
const int width = 10;
const int height = 10;
const int offset[4] = {-1,1,-width,width};
double accumulator=0;
for(int i=0;i<4;i++)
accumulator += get(current_loc+offset[i]);
请注意,迷你阵列已预先计算出您域中相邻单元格的偏移量。一个好的编译器可能会展开上述循环。
完成所有这些操作后,选择适当的优化标志可能会导致自动矢量化。
实际上,代码中的分支和 mod 可能会阻止自动矢量化。您可以通过启用适当的标志来检查这一点。对于英特尔编译器集合 (icc),您需要:
-qopt-report=5 -qopt-report-phase:vec
对于 GCC,您需要(如果我没记错的话):
-fopt-info-vec -fopt-info-missed