[[likely]]が役立った話
この記事はstackoverflowで質問した内容の結論をまとめたものです.
正直, [[likely]]
attribute なんて今まで一度も使ったことなかったです.
こんなコードを書いた
#include <stdio.h> #define N 19 int main(void){ int a[N]; int ans = 0; for(int i = 0; i < N; ++i){ a[i] = 0; } for(;;){ int i; ++ans; for(i = N - 1; a[i] == 2; --i){ if(i == 0){ printf("%d\n", ans); return 0; }else{ a[i] = 0; } } ++a[i]; } }
これは, 0 以上 3 未満の整数から重複を許して 19 個選ぶやり方 通りを,ループで数え上げて出力するコードです.
これを, gcc でコンパイルして実行時間をはかります.このとき, -O1 オプションを付けた場合と, -O2 オプションを付けた場合の 2 通りためしてみます.
すると,結果は次のようになりました(単位はすべて秒):
オプション | 1回目 | 2回目 | 3回目 | 4回目 | 5回目 | 平均 |
-O1 | 0.70 | 0.71 | 0.69 | 0.71 | 0.68 | 0.70 |
-O2 | 1.13 | 1.11 | 1.10 | 1.11 | 1.09 | 1.11 |
-O2 の方が遅い!!びっくりして stackoverflow で質問を投げたら, -O2 で有効になる最適化のうち,-falign-functions -falign-jumps -falign-labels -falign-loops
がどうやら悪い方に働いていると言われました.さらに [[likely]]
attribute を付けることも提案されました.
[[likely]]
[[unlikely]]
って?
[[likely]]
は,実行される確率の高い文に付けます.[[unlikely]]
は,実行される確率の低い文に付けます.
付けてみた
今回,for(;;)
文で無限ループを書いていて, 回はループが回ります. break されるのは最後の一回だけなので,この for 文は「ループが終了する確率より,続く確率の方がはるかに高い」ということになります.
そこで,次のように[[likely]]
を付けてみます.
#include <stdio.h> #define N 19 int main(void){ int a[N]; int ans = 0; for(int i = 0; i < N; ++i){ a[i] = 0; } for(;;) [[likely]] { int i; ++ans; for(i = N - 1; a[i] == 2; --i){ if(i == 0){ printf("%d\n", ans); return 0; }else{ a[i] = 0; } } ++a[i]; } }
すると……
オプション | 1回目 | 2回目 | 3回目 | 4回目 | 5回目 | 平均 |
-O1 | 0.65 | 0.65 | 0.66 | 0.66 | 0.66 | 0.66 |
-O2 | 0.66 | 0.65 | 0.66 | 0.65 | 0.66 | 0.66 |
おお! -O2 も速くなった!!
結論
[[likely]]
でこんな影響が出ることも,あるんだなぁ