Compare()
次のような関数があります。
inline bool Compare(bool greater, int p1, int p2) {
if (greater) return p1>=p2;
else return p1<=p2;
}
分岐を避けるために最適化することにしました。
inline bool Compare2(bool greater, int p1, int p2) {
bool ret[2] = {p1<=p2,p1>=p2};
return ret[greater];
}
次に、これを実行してテストしました:
bool x = true;
int M = 100000;
int N = 100;
bool a[N];
int b[N];
int c[N];
for (int i=0;i<N; ++i) {
a[i] = rand()%2;
b[i] = rand()%128;
c[i] = rand()%128;
}
// Timed the below loop with both Compare() and Compare2()
for (int j=0; j<M; ++j) {
for (int i=0; i<N; ++i) {
x ^= Compare(a[i],b[i],c[i]);
}
}
結果:
Compare(): 3.14ns avg
Compare2(): 1.61ns avg
私はケースクローズドと言います.FTWの分岐は避けてください. しかし、完全を期すために、私は置き換えました
a[i] = rand()%2;
と:
a[i] = true;
〜3.14nsのまったく同じ測定値を得ました。おそらく、その時点で分岐は行われておらず、コンパイラーは実際にステートメントCompare()
を回避するために書き直しています。if
しかし、なぜCompare2()
速いのでしょうか?
残念ながら、私はアセンブリ コードの知識がありません。そうでなければ、自分でこれに答えようとしたでしょう。
編集:以下はいくつかのアセンブリです:
_Z7Comparebii:
.LFB4:
.cfi_startproc
.cfi_personality 0x3,__gxx_personality_v0
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
movl %edi, %eax
movl %esi, -8(%rbp)
movl %edx, -12(%rbp)
movb %al, -4(%rbp)
cmpb $0, -4(%rbp)
je .L2
movl -8(%rbp), %eax
cmpl -12(%rbp), %eax
setge %al
jmp .L3
.L2:
movl -8(%rbp), %eax
cmpl -12(%rbp), %eax
setle %al
.L3:
leave
ret
.cfi_endproc
.LFE4:
.size _Z7Comparebii, .-_Z7Comparebii
.section .text._Z8Compare2bii,"axG",@progbits,_Z8Compare2bii,comdat
.weak _Z8Compare2bii
.type _Z8Compare2bii, @function
_Z8Compare2bii:
.LFB5:
.cfi_startproc
.cfi_personality 0x3,__gxx_personality_v0
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
movl %edi, %eax
movl %esi, -24(%rbp)
movl %edx, -28(%rbp)
movb %al, -20(%rbp)
movw $0, -16(%rbp)
movl -24(%rbp), %eax
cmpl -28(%rbp), %eax
setle %al
movb %al, -16(%rbp)
movl -24(%rbp), %eax
cmpl -28(%rbp), %eax
setge %al
movb %al, -15(%rbp)
movzbl -20(%rbp), %eax
cltq
movzbl -16(%rbp,%rax), %eax
leave
ret
.cfi_endproc
.LFE5:
.size _Z8Compare2bii, .-_Z8Compare2bii
.text
現在、テストを実行する実際のコードは、上記の 2 つの関数のインライン バージョンを使用している可能性があるため、これが分析するコードとして間違っている可能性があります。jmp
そういえば にコマンドが見えますCompare()
ので、分岐しているということだと思います。もしそうなら、この質問は次のようになると思います:なぜ分岐予測子は、からにCompare()
変更したときのパフォーマンスを改善しないのですか?a[i]
rand()%2
true
false
EDIT2:投稿をより賢明にするために、「分岐予測」を「分岐」に置き換えました。