【问题标题】:Poor _rotl performance under minGWminGW 下 _rotl 性能不佳
【发布时间】:2013-06-01 11:27:13
【问题描述】:

我有一个程序,它依赖于左旋转指令的性能。

在 MSVC 下,它工作得相当好,只需将 _rotl() 内部函数定义为向左旋转的目标。

在 GCC for Linux 下,它也运行良好。在这里定义等效的软件构造 rotl32(x,r) = ((x << r) | (x >> (32 - r))) 就足够了,编译器足够聪明地识别出这是一个 32 位左移,并自动将其替换为其内在等效项(公平地说,MSVC 也能够使检测)。

在 MinGW 下,没有那么多。当 MinGW 使用 GCC 作为其核心时,这一点就更加有趣了。 MinGW 可以编译 windows 内在函数_rotl,但不会明显触发相应的内在函数。软件版本似乎也未被检测到,但公平地说,它仍然比_rotl 快。最终结果是性能降低了 10 倍,所以这绝对是显着的。

注意:测试 MinGW 的 GCC 版本是 4.6.2

【问题讨论】:

  • 您能否发布一个示例以及生成的程序集(使用-S-O2 选项)?我对 MinGW 4.6.1 和 4.7.2 的测试表明它将使用 rol(或有时是 ror)指令来实现对内联 rotl32() 函数的调用,该函数仅返回您给出的表达式 - 只要因为所涉及的论点是unsigned。这似乎是一个明智的要求,因为您的表达式对于负值(以及使用有符号类型时的一些非负值)具有未定义的行为。
  • 然而,_rotl() 'intrinsic' 显然是作为对 MinGW 中库函数的非内联函数调用实现的。
  • 所有输入都是uint32_t
  • 请注意,虽然微型计算机的编译器过去的设计方式总是将rotl32 的给定定义视为评估x|0x|x(可能是任意选择)以防万一r 为 0,无论选择哪个值都无关紧要,因为两者都会评估为 x,这样的处理方式不再流行。相反,有必要将| 右侧的部分替换为(x >> (31-r) >> 1)(x >> ((-r) & 31)) 等替代结构,以使程序可以安全地用于优化编译器,即使后一种形式可能...
  • ...在许多编译器上速度较慢且难以阅读。

标签: c gcc mingw


【解决方案1】:

以防万一您在 Windows 上遇到了内在函数,这里有一种在 x86 上使用内联汇编器的方法;

uint32_t rotl32_2(uint32_t x, uint8_t r) {
  asm("roll %1,%0" : "+r" (x) : "c" (r));
  return x;
}

在 Ubuntu 的 gcc 上测试过,但应该在 mingw 上运行良好。

【讨论】:

  • 谢谢,由于缺乏知识,我通常不喜欢汇编代码,而且还有可移植性问题。 MinGW 只是一个目标,甚至不是主要目标。尽管如此,这是一个有趣的输入。 +1。
【解决方案2】:

只需包含 intrin.h 标头。

它是特定于 Windows 的标头,因此如果您正在开发跨平台软件,请不要忘记用这样的条件包装它:

#ifdef _WIN32
# include <intrin.h>
#endif

基准测试

Run on (4 X 3310 MHz CPU s)
09/07/16 23:29:35
Benchmark                    Time           CPU Iterations
----------------------------------------------------------
BM_rotl/8                   19 ns         18 ns   37392923
BM_rotl/64                 156 ns        149 ns    4487151
BM_rotl/512               1148 ns       1144 ns     641022
BM_rotl/4k                9286 ns       9178 ns      74786
BM_rotl/32k              71575 ns      69535 ns       8974
BM_rotl/256k            583148 ns     577204 ns       1000
BM_rotl/2M             4769689 ns    4830999 ns        155
BM_rotl/8M            19997537 ns   18720120 ns         35
BM_rotl_intrin/8             6 ns          6 ns  112178768
BM_rotl_intrin/64           55 ns         53 ns   14022346
BM_rotl_intrin/512         431 ns        407 ns    1725827
BM_rotl_intrin/4k         3327 ns       3338 ns     224358
BM_rotl_intrin/32k       27093 ns      26596 ns      26395
BM_rotl_intrin/256k     217633 ns     214167 ns       3205
BM_rotl_intrin/2M      1885492 ns    1853925 ns        345
BM_rotl_intrin/8M      8015337 ns    7626716 ns         90

基准代码

#include <benchmark/benchmark.h>

#define MAKE_ROTL_BENCHMARK(name) \
  static void name(benchmark::State& state) { \
    auto arr = new uint32_t[state.range(0)]; \
    while (state.KeepRunning()) { \
      for (int i = 0; i < state.range(0); ++i) { \
        arr[i] = _rotl(arr[i], 16); \
      } \
    } \
    delete [] arr; \
  } \
  /**/

MAKE_ROTL_BENCHMARK(BM_rotl)
#include <intrin.h>
MAKE_ROTL_BENCHMARK(BM_rotl_intrin)

#undef MAKE_ROTL_BENCHMARK

BENCHMARK(BM_rotl)->Range(8, 8<<20);
BENCHMARK(BM_rotl_intrin)->Range(8, 8<<20);

BENCHMARK_MAIN()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-12
    • 2011-01-03
    • 2016-11-06
    • 2019-06-15
    • 2013-06-11
    • 2010-12-31
    • 2012-01-25
    相关资源
    最近更新 更多