首页 > 解决方案 > OpenMP 中的独立循环崩溃

问题描述

我有一个嵌套循环,如下所示 -

for(int i=0; i<limit1; i++)
{
    for(int j=0; j<limit2; j++){
       /*
          Code with Custom function calls, branching etc etc.

      */
  }
}

内循环和外循环迭代相互独立。由于这个循环不能简单地向量化,我想将它折叠到一个巨大的迭代空间中,以便可以更有效地展开它,从某种意义上说,不是只展开内部循环,而是可以展开组合的迭代空间。

我不想并行化它。根据我的理解,我不认为 openmp 提供了一个独立的 collapsing pragma like - #pragma omp collapse(2),而是将 collapse 子句与其他 pragma (如simdor )结合使用for

可以通过 OpenMP 或其他方法来实现这一点。

PS - 我不确定这种方法的优缺点,是否会显着提高性能等等。如果有人解释理论上(即在基准测试之前)如何(或就此而言)确定这一点, 那会很好。

TIA

标签: c++openmpvectorizationloop-unrolling

解决方案


首先,OpenMP 是“一种可在不同供应商的体系结构之间移植的并行编程模型”(来源: OpenMP 5.1 规范)。因此,如果您不想并行化循环,那么它可能不是正确的工具。

但是,请注意 OpenMP 提供了unroll完全或部分展开循环嵌套的最外层循环的指令。完全展开循环的full子句要求迭代计数(例如limit1)是编译时常量(否则理论上是不可能的)。该partial子句可以通过整数参数化,以控制展开多少次迭代。截至目前,GCC、ICC 和 Clang 都不支持这两个子句。

还有一个tile指令可以重新排序两个嵌套循环的迭代,以便获得 2D 固定大小的图块。它没有向编译器指定应该展开循环。然而,一个积极优化的编译器可能会展开固定大小的循环嵌套,如果它不包含许多分支或函数调用(因为它通常不利于性能)。该指令不能unroll(因为 tile 循环没有规范的循环嵌套形式)结合使用。

请注意,如果迭代计数不是compile-time constants并且通常不是 if limit2is not a power of two ,那么折叠(手动或使用工具自动)两个嵌套循环肯定不会帮助编译器。实际上,在这种情况下,肯定需要通过变量使用慢速模数或相当慢的无分支条件移动。对于编译器来说,展开这样的循环将非常困难(如果可能的话)。


推荐阅读