【问题标题】:Portable loop unrolling with template parameter in C++ with GCC/ICC使用 GCC/ICC 在 C++ 中使用模板参数展开可移植循环
【发布时间】:2020-08-13 23:29:11
【问题描述】:

我正在开发一个high-performance parallel computational fluid dynamics code,它涉及很多轻量级循环,因此如果所有重要循环都完全展开,性能会提高大约 30%。

这可以通过使用编译器指令轻松地为固定数量的循环完成:#pragma GCC unroll (16) 被我的目标编译器识别,英特尔 C++ 编译器 ICC 和 GCC,而 @987654323 @ 遗憾地被 GCC 忽略了。例如,我还可以将 模板参数或预处理器指令作为限制与 ICC (similar to what you can do with nvcc) 一起使用

template <int N>
// ...
#pragma unroll (N)
for (int i = 0; i < N; ++i) {
// ...
}

#define N 16

#pragma unroll (N)
for (int i = 0; i < N; ++i) {
// ...
}

使用 ICC 编译时使用 -Wall -w2 -w3 不会引发错误或警告,而使用 GCC (-Wall -pedantic) 的补充语法 #pragma GCC unroll (N) 在 Ubuntu 18.04 中的 GCC 9.2.1 20191102 中会引发错误:

error: ‘#pragma GCC unroll’ requires an assignment-expression that evaluates to a non-negative integral constant less than 65535
#pragma GCC unroll (N)

有人知道基于模板参数和编译器指令的循环展开以可移植的方式工作(至少与 GCC 和 ICC 一起工作)的方法吗?我实际上只需要完全展开整个循环,所以像#pragma GCC unroll (all) 这样的东西已经对我有很大帮助了。

我知道unroll loops with template meta-programming 存在或多或少复杂的策略,但在我的应用程序中,循环可能是嵌套的并且可以包含更复杂的循环体,我觉得这样的策略会使我的代码过于复杂并减少可读性。

【问题讨论】:

  • 用于完全展开给定循环的惯用 GCC 方法,不幸的是,afaik 是一种推送/弹出选项方法,#pragma GCC push_options#pragma GCC optimize ("unroll-loops")for ... #pragma GCC pop_options,这将但是,不能与 ICC 一起移植。

标签: c++ gcc hpc icc loop-unrolling


【解决方案1】:

遗憾的是,目前似乎没有一致的方法来做到这一点。

我最终将 预处理器宏_Pragma(string-literal)stringification macro(类似于 this)结合使用,如果 Intel可以使用 C++ 编译器 ICC 或 Clang,使用常量因子来展开 GCC,而对于任何其他编译器都忽略它。这里是一个小例子:

/// Helper macros for stringification
#define TO_STRING_HELPER(X)   #X
#define TO_STRING(X)          TO_STRING_HELPER(X)

// Define loop unrolling depending on the compiler
#if defined(__ICC) || defined(__ICL)
  #define UNROLL_LOOP(n)      _Pragma(TO_STRING(unroll (n)))
#elif defined(__clang__)
  #define UNROLL_LOOP(n)      _Pragma(TO_STRING(unroll (n)))
#elif defined(__GNUC__) && !defined(__clang__)
  #define UNROLL_LOOP(n)      _Pragma(TO_STRING(GCC unroll (16)))
#elif defined(_MSC_BUILD)
  #pragma message ("Microsoft Visual C++ (MSVC) detected: Loop unrolling not supported!")
  #define UNROLL_LOOP(n)
#else
  #warning "Unknown compiler: Loop unrolling not supported!"
  #define UNROLL_LOOP(n)
#endif

/// Example usage
template <int N>
void exampleContainingLoop() {
  UNROLL_LOOP(N)
  for (int i = 0; i < N; ++i) {
    // ...
  }
    
  return;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-24
    相关资源
    最近更新 更多