インライン展開はどのくらい速い?

執筆動機

インライン展開が速いものという知識はあったが,具体的にどのくらい速いか計測したことが無かったので,計測してみた.

対象読者

「インライン化するとどのくらい早くなるの?」にうまく答えられない方.

コード

カウンタをインクリメントする関数をインラインとそうでないものを実装した.

#include <chrono>
#include <cstdint>
#include <iostream>

#define GIGA 1000000000

using namespace std;

__attribute__((always_inline)) void inline_add_one(uint64_t& ctr) 
{
  ++ctr;
}

void add_one(uint64_t& ctr) 
{
  ++ctr;
}

int main()
{
  chrono::system_clock::time_point start,end;
  uint64_t sum(0);

  start = chrono::system_clock::now();
  for (auto i = 0; i < GIGA; ++i) {
    inline_add_one(sum);
  }
  end = chrono::system_clock::now();
  cout << "inline function :\t" 
    << sum << " :\t"
    <<  chrono::duration_cast<chrono::milliseconds>(end-start).count() 
    << " [ms]" << endl;
  sum = 0;

  start = chrono::system_clock::now();
  for (auto i = 0; i < GIGA; ++i) {
    add_one(sum);
  }
  end = chrono::system_clock::now();
  cout << "normal function :\t" 
    << sum << " :\t"
    <<  chrono::duration_cast<chrono::milliseconds>(end-start).count() 
    << " [ms]" << endl;

  return 0;
}

アセンブリコードの確認

g++ -S -O0 -std=c++17 inline.cc

以下, inline 化されていた関数. 確かにインライン化されている.

## %bb.2:                               ##   in Loop: Header=BB2_1 Depth=1
        leaq    -40(%rbp), %rax
        movq    %rax, -8(%rbp)
        movq    -8(%rbp), %rax
        movq    (%rax), %rcx
        addq    $1, %rcx
        movq    %rcx, (%rax)
## %bb.3:                               ##   in Loop: Header=BB2_1 Depth=1

以下,inline 化されていなかった関数. 確かにインライ化されていない. add_one を call している.

## %bb.6:                               ##   in Loop: Header=BB2_5 Depth=1
        leaq    -40(%rbp), %rdi
        callq   __Z7add_oneRy
## %bb.7:                               ##   in Loop: Header=BB2_5 Depth=1

実行結果

$ g++ -O0 -std=c++17 inline.cc $ ./a.out inline function : 1000000000 : 1414 [ms] normal function : 1000000000 : 1760 [ms]

結果,無視できない性能差分を観測できた. 本実験では 1.24 倍程度である. 関数の長さ,中での処理によって,更に性能差が発生することは考えられる.