如何优化以下常见循环?

时间:2015-12-24 14:20:37

标签: c++ loops optimization vectorization multicore

我有代码

getActivity()

你能给我一个可行的例子,以更好的性能优化它吗?任何编译器都可以,比如英特尔c ++编译器和visual c ++编译器。请建议性能良好的CPU来完成这项工作。

4 个答案:

答案 0 :(得分:2)

有问题的代码没用。它使用未初始化的变量进行大量计算,然后忽略结果。编译器越来越聪明地搞清楚这种事情并删除所有代码。因此,如果这样的代码根本不需要任何时间,请不要感到惊讶。

在C中,你会将指针声明为" const double * restrict"除了a将是double * restrict之外,告诉编译器除了第一个指针之外的所有指针都指向在循环期间不会被修改的数据;这允许编译器进行矢量化。不幸的是,不是C ++功能。

如果这是你真正的问题,你只需要交换内部和外部循环,并删除这样的循环不变量:

void foo(int iter, int n, double* a, double* b, double *c, double*d, double* e, double* f, double* g)
{
    for (int i = 0; i < n; ++i) {
        double xa = a [i];
        double xb = b [i];
        double xr = c[i] * (d[i] + e[i] + f[i] + g[i]);

        for (int j = 0; j < iter; ++j)
            xa = xb * xa + xr;

        a [i] = xa;
    }
}

您可能会并行执行四次迭代以避免延迟。

但是在现实生活中,您会发现在每次通话中,您都会读到大约40MB,超出任何缓存。所以你受RAM速度的限制。通常的解决方案是将工作分成更小的部分,例如一次500个元素,因此所有内容都适合L1缓存,然后使用相同的数据执行1000次操作。

答案 1 :(得分:1)

在Apple clang上,我试过了:

  • 在参数上使用__restict__来说服编译器没有别名。

结果:没有变化

  • foo()
  • 中分配8个线程的计算

结果:计算时间从<3秒增加到~18秒!

  • 使用#pragma omp parallel for

结果:编译器忽略了我并继续使用原始解决方案。 ~3秒。

  • 设置命令行选项-march=native以允许cpu完全出色地闪耀

结果:不同的汇编程序输出(应用矢量化),但运行时间仍然保持在~3s

初步结论:

此问题受内存访问限制,而不受CPU限制。

答案 2 :(得分:1)

您可以尝试将向量预取到缓存行中,然后以8个块为单位对它们进行操作(8个双精度数将适合每个缓存行)。

确保在x [i]到x [i + 7]上操作时,您正在预取x [i + 8]到x [i + 15]。

这可能没有帮助,因为您使用的加法和乘法速度非常快,以至于您的RAM无论如何都无法跟上。

答案 3 :(得分:0)

我认为你应该使用多线程。将foo改为fromIndex,toIndex,而不是n,并通过线程分配vectores。

void foo(int fromIndex, int toIndex, double* a, double* b, double *c, double*d, double* e, double* f, double* g)
{
    for (int i = fromIndex; i < toIndex; ++i)
        a[i] = b[i] * a[i] + c[i] * (d[i] + e[i] + f[i] + g[i]);
}