0%

#include <benchmark/benchmark.h>
static inline constexpr int FIBONACCI_N = 10;

int fib(int n) { return n < 2 ? n : fib(n - 1) + fib(n - 2); }
static void BM_fib(benchmark::State &state) {
    for (auto _ : state) {
        int res = fib(FIBONACCI_N);
        benchmark::DoNotOptimize(res);
    }
}
BENCHMARK(BM_fib);

int x;  // Magic line.
        // clang does not use DP anymore: much slower.
        // gcc chooses a different optimizing approach: much faster.

int fib_x(int n) { return n < 2 ? n : fib_x(n - 1) + fib_x(n - 2) + x; }
static void BM_fib_x(benchmark::State &state) {
    for (auto _ : state) {
        int res = fib_x(FIBONACCI_N);
        benchmark::DoNotOptimize(res);
    }
}
BENCHMARK(BM_fib_x);

BENCHMARK_MAIN();

编译条件:GCC 13.2 -O2 -std=c++17

结果:因为 x 改变了 fib_x 的优化流程,fib_x 虽然看起来更复杂或者和 fib 同样复杂,但实际上比 fib 快。在编译时打开 -fno-optimize-sibling-calls 禁用这项优化,结果就正常了。

Open in Quick C++ BenchmarkOpen in Compiler Explorer

随后我又补充了对单个函数关闭 sibling 优化的补充实验,结果是 sibling 优化使得 fib 严重减速,fib_x 速度变化不大(有时候略微提速)。从 Compiler Explorer 的结果来看,这个行为是从 GCC 10.1 开始产生的。在之前 sibling 优化结果则符合预期,fibfib_x 两个函数都得到了不同程度的加速,其中 fib 因为更简单所以获得的加速比更大。