使用SSE优化有限差分

3

我想知道是否有可能使用SSE(1,2,3,4,...)来优化以下循环:

// u and v are allocated through new double[size*size]
for (int j = l; j < size-1; ++j)
{
    for (int k = 1; k < size-1; ++k)
    {
        v[j*size + k] = (u[j*size + k-1] + u[j*size + k+1] 
                       + u[(j-1)*size + k]+ u[(j+1)*size + k]) / 4.0;
    }
}

这个习惯用法[j*size + k]被用来将内存块视为多维数组。

可悲的是,对于GCC(4.5)的-ftree-vectorize标志并不认为循环适合进行SIMD类型的优化。 (尽管我从未见过-ftree-vectorize优化除最简单的循环外的任何东西。)

虽然我知道有许多其他方法可以提高循环性能(OpenMP、展开、原地算法等),但我特别想知道是否可以使用SIMD。 我可能更感兴趣的是如何(如果有的话)转换这样一个循环的一般轮廓,而不是具体实现。


你尝试过使用-ftree-vectorizer-verbose=n吗?gcc会给出有关为什么进行/不进行向量化的提示。需要注意的一点是,如果没有使用restrict关键字,它将假定v可能与u别名,这将阻止许多SSE(在最好的情况下,它将制作两个版本,并在运行时决定)。 - Ben Jackson
@Ben Jackson - 是的,我使用了-verbose选项来得出结论,它没有将我的代码向量化。我曾经尝试过'restrict'(实际上是'restrict',因为我是C++),但是没有任何区别,因为GCC正在内联(并确定'u'和'v'不重叠)。 - Freddie Witherden
1个回答

0

看起来应该是可能的,但由于(a)您正在使用双精度,(b)相对于I/O,您做的计算非常少,(c)大多数现代x86-64 CPU都有两个FPUs,因此您在SIMD编码投资上可能不会得到太多回报。


我主要出于习惯使用双精度浮点数。但是,在我的双核系统上,当使用OpenMP时,我几乎可以获得线性加速,因此我不确定它是否受到I/O限制。 - Freddie Witherden
@Freddie:关于上面的标量循环,I/O绑定的评论是针对它的 - 你只有3个FP加法和1个FP乘法来处理4个加载+1个存储 - 执行时间可能会被加载和存储的延迟所主导,因此通过SIMD使计算更快可能不会带来任何收益。 - Paul R
@Freddie:如果你的算法可以使用浮点数而不会出现任何数值精度或稳定性问题,那么在这种情况下考虑SIMD可能是值得的(尽管请注意上面评论中关于计算与加载/存储的警告)。 - Paul R

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接