https://crates.io/crates/cargo-show-asm 이 크레이트 사용해 어셈블리 코드를 봤다. 환경은 맥북 M2air 이다.
➜ parallel git:(main) ✗ cargo asm --lib --release calculation git:(main) ✗
Compiling parallel v0.1.0 (/Users/Taery/Collatz_Conjecture/parallel)
Finished `release` profile [optimized] target(s) in 0.44s
Can't find any items matching "calculation"
calculation함수의 어셈블리가 없다고 한다. main함수에 calculation이 인라인되어 최적화되었다.
#[inline(never)] 속성을 썼다. 인라인하지 말고 함수를 호출하라는 뜻이다.
#[inline(never)]
pub fn calculation(i: u128) ->bool{
let mut n = i;
while n >= i{
if n % 2 == 0 {
n = n >> 1;
} else {
n = (n << 1) + n + 1;
}
}
true
}
➜ parallel git:(main) ✗ cargo asm --lib --release parallel::calculation git:(main) ✗
Finished `release` profile [optimized] target(s) in 0.03s
.globl parallel::calculation
.p2align 2
parallel::calculation:
Lfunc_begin48:
.cfi_startproc
mov w8, #3
mov x9, x0
mov x10, x1
LBB48_1:
extr x11, x10, x9, #1
lsr x12, x10, #1
umulh x13, x9, x8
add x10, x10, x10, lsl #1
add x14, x9, x9, lsl #1
adds x14, x14, #1
adc x10, x13, x10
tst x9, #0x1
csel x10, x12, x10, eq
csel x9, x11, x14, eq
cmp x9, x0
sbcs xzr, x10, x1
b.hs LBB48_1
mov w0, #1
ret
어셈블리어에서 계산 코드가 나왔다.
제대로 벤치마크 해보겠다.
➜ parallel git:(main) ✗ cargo run -- para git:(main) ✗
Compiling parallel v0.1.0 (/Users/Taery/Collatz_Conjecture/parallel)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.19s
Running `target/debug/parallel para`
parallel start
end 1073741824 numbers
걸린 시간: 18.664080333s
➜ parallel git:(main) ✗ cargo run -- nopara git:(main) ✗
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.07s
Running `target/debug/parallel nopara`
not parallel start
end 1073741824 numbers
걸린 시간: 77.317914666s
2^30까지 병렬은 18초, no병렬은 77초 나온다.
➜ parallel git:(main) ✗ cargo run -- para git:(main) ✗
Compiling parallel v0.1.0 (/Users/Taery/Collatz_Conjecture/parallel)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.44s
Running `target/debug/parallel para`
parallel start
end 33554432 numbers
걸린 시간: 593.148042ms
근데 이전(인라인제한 안할때)과 비교할 때, 2^25계산 해보니 비슷하게 나온다.
인라인과 dead code는 큰 관계가 없다고 한다.
인라인은 함수를 호출하지 않고 호출되는 부분에 함수 코드를 집어넣어서 시간을 줄이는 것이고, 그 함수의 동작에는 차이가 없다.
그러면, 인라인되었을 때는 main코드에 calculation의 계산부분이 들어있을 것이다.
➜ parallel git:(main) ✗ cargo asm --bin parallel --release parallel::main
Finished `release` profile [optimized] target(s) in 0.03s
.section __TEXT,__text,regular,pure_instructions
.private_extern std::rt::lang_start
.globl std::rt::lang_start
.p2align 2
std::rt::lang_start:
Lfunc_begin0:
.cfi_startproc
sub sp, sp, #32
.cfi_def_cfa_offset 32
stp x29, x30, [sp, #16]
add x29, sp, #16
.cfi_def_cfa w29, 16
.cfi_offset w30, -8
.cfi_offset w29, -16
mov x4, x3
mov x3, x2
mov x2, x1
str x0, [sp, #8]
Lloh0:
adrp x1, l_anon.6b773ecf7d3b3c2973f09b328b36d062.0@PAGE
Lloh1:
add x1, x1, l_anon.6b773ecf7d3b3c2973f09b328b36d062.0@PAGEOFF
add x0, sp, #8
bl std::rt::lang_start_internal
.cfi_def_cfa wsp, 32
ldp x29, x30, [sp, #16]
add sp, sp, #32
.....
.....
.loh AdrpAdd Lloh16, Lloh17
.loh AdrpLdrGot Lloh14, Lloh15
.loh AdrpAdd Lloh18, Lloh19
어셈블리에 calculation의 계산 과정이 포함되어 있다. lib.rs ->main.rs로 코드가 이동했고, 동작에는 차이가 없다.
dead code가 아니었다.
➜ parallel git:(main) ✗ cargo run -- para git:(main) ✗
Compiling parallel v0.1.0 (/Users/Taery/Collatz_Conjecture/parallel)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.58s
Running `target/debug/parallel para`
parallel start
end 1073741824 numbers
걸린 시간: 18.677820042s
➜ parallel git:(main) ✗ cargo run --release -- para git:(main) ✗
Compiling parallel v0.1.0 (/Users/Taery/Collatz_Conjecture/parallel)
Finished `release` profile [optimized] target(s) in 0.56s
Running `target/release/parallel para`
parallel start
end 1073741824 numbers
걸린 시간: 1.568064583s
같은 연산을 dev/release 모드로 돌렸을 때 10배 이상 차이난다.
dev는 release보다 느린 대신 디버깅을 잘 할 수 있다.