早上在修改一些 c++ 的東西,發現一個有趣的現象
下面是測試碼:
#include <iostream>
#include "microtime.h"
void swap(int &x, int &y) {
int tmp(x);
x = y;
y = tmp;
}
const int loopMax = 50000001;
int main() {
int x = 24578, y = 2982;
double t1 = microtime();
for (int idx=0; idx<loopMax; ++idx) {
swap(x, y);
}
t1 = microtime(t1);
std::cout << "x, y = " << x << ", " << y
<< " [" << t1*1000 << "ms]\n";
return 0;
}
本來是用 clang++ -O3 編譯,發現跑出來的時間怪怪的
於是就加 -S 看一下編出來的 asm code
fdivs .LCPI1_0(%rip)
movl $50000002, %ecx # imm = 0x2FAF082
.align 16, 0x90
.LBB1_1: # =>This Inner Loop Header: Depth=1
addl $-26, %ecx
jne .LBB1_1
# BB#2:
哈~~~~~ 原來是騙局啦~~~
迴圈數還會偷偷加1呢~ ^_^
然後 cout 的地方
就直接將編譯器預估的結果印出來
movl $2982, %esi # imm = 0xBA6
callq _ZNSolsEi
movq %rax, %rbx
movl $.L.str1, %esi
movl $2, %edx
movq %rbx, %rdi
callq _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
movl $24578, %esi # imm = 0x6002
movq %rbx, %rdi
callq _ZNSolsEi
所以根本就沒有真的跑 swap
連迴圈也是偷工減料來跑 XD
後來我改用 -O1 來編譯看看,另外也用 g++ 編
clang -O1:
movl $50000001, %ebp # imm = 0x2FAF081
callq _Z9microtimee
fstpt 16(%rsp) # 10-byte Folded Spill
leaq 60(%rsp), %r14
leaq 56(%rsp), %rbx
.align 16, 0x90
.LBB2_1: # =>This Inner Loop Header: Depth=1
movq %r14, %rdi
movq %rbx, %rsi
callq _Z4swapRiS_
decl %ebp
jne .LBB2_1
# BB#2:
clang -O1 就有正常跑迴圈和呼叫 swap()
不過卻沒有自動將 swap() 編成 inline
g++ -O1:
movl $50000001, %eax
movl $24578, %ebx
movl $2982, %ebp
jmp .L12
.L13:
movl %ebp, %edx
movl %ebx, %ebp
movl %edx, %ebx
.L12:
subl $1, %eax
jne .L13
.L13 ~ .L12 之間這3行就是實際執行 swap() 的動作
g++ -O3:
movl $50000001, %eax
fldl 40(%rsp)
popq %rcx
.c 72
popq %rsi
.cfi_def_cfa_offset 64
jmp .L14
.p2align 4,,10
.p2align 3
.L15:
movl %ebp, %edx
movl %ebx, %ebp
movl %edx, %ebx
.L14:
subl $1, %eax
jne .L15
swap() 的動作是在 .L15 ~ .L14
g++ -O1 或 -O3 都會正常編出迴圈
而且也會自動將 swap 編成 inline
下面是跑出來的結果
$ ./ex044-clang++O1 && ./ex044-clang++O3 && ./ex044-g++O1 && ./ex044-g++O3
x, y = 2982, 24578 [1081.17ms]
x, y = 2982, 24578 [3.09399ms]
x, y = 2982, 24578 [402.601ms]
x, y = 2982, 24578 [339.092ms]
g++ 將 swap() 編成 inline
執行時就減少函數呼叫動作
因此會比 clang++ -O1 的碼快