我在使用的時候有注意到在參數化型別中使用值的方式與傳統封裝的方式有效能上的差異。

所以我就做了一些測試。

在參數化型別中使用值:

1
2
3
struct A{T}

end

傳統型別封裝:

1
2
3
struct B
x::Int64
end

全文出現的程式碼為實際測試程式碼

因為 Julia 有提供好用的 @code_llvm@code_native 來觀察一行程式碼實際被轉換成 LLVM 或是組合語言的時候會產生多少行的程式碼,藉此我們可以用低階程式碼來評估是否有效率。程式碼的行數愈少是越有效率的。

建立

我們來測試一個物件被建立需要多少行的程式碼。

A - LLVM

1
@code_llvm A{5}()
1
2
3
4
5
6
7
;  @ REPL[1]:3 within `Type'
define nonnull %jl_value_t addrspace(10)* @japi1_Type_12238(%jl_value_t addrspace(10)*, %jl_value_t addrspace(10)**, i32) #0 {
top:
%3 = alloca %jl_value_t addrspace(10)**, align 8
store volatile %jl_value_t addrspace(10)** %1, %jl_value_t addrspace(10)*** %3, align 8
ret %jl_value_t addrspace(10)* addrspacecast (%jl_value_t* inttoptr (i64 140407726014496 to %jl_value_t*) to %jl_value_t addrspace(10)*)
}

B - LLVM

1
@code_llvm B(5)
1
2
3
4
5
6
;  @ REPL[1]:2 within `Type'
define { i64 } @julia_Type_12221(%jl_value_t addrspace(10)*, i64) {
top:
%.fca.0.insert = insertvalue { i64 } undef, i64 %1, 0
ret { i64 } %.fca.0.insert
}

A - Assembly

1
@code_native A{5}()
1
2
3
4
5
; ┌ @ REPL[1]:3 within `Type'
movq %rsi, -8(%rsp)
movabsq $140407726014496, %rax # imm = 0x7FB338A20020
retq
; └

B - Assembly

1
@code_native B(5)
1
2
3
4
5
; ┌ @ REPL[1]:2 within `Type'
movq %rsi, %rax
retq
nopw %cs:(%rax,%rax)
; └

取值

接著測試從物件當中取值出來的效能。

定義取值的方法:

1
2
get_value(::A{T}) where {T} = T
get_value(b::B) = b.x

事先建立好物件:

1
2
a = A{5}()
b = B(5)

A - LLVM

1
@code_llvm get_value(a)
1
2
3
4
5
;  @ REPL[8]:1 within `get_value'
define i64 @julia_get_value_12274() {
top:
ret i64 5
}

B - LLVM

1
@code_llvm get_value(b)
1
2
3
4
5
6
7
8
9
;  @ REPL[5]:1 within `get_value'
define i64 @julia_get_value_12630({ i64 } addrspace(11)* nocapture nonnull readonly dereferenceable(8)) {
top:
; ┌ @ sysimg.jl:18 within `getproperty'
%1 = getelementptr inbounds { i64 }, { i64 } addrspace(11)* %0, i64 0, i32 0
; └
%2 = load i64, i64 addrspace(11)* %1, align 8
ret i64 %2
}

A - Assembly

1
@code_native get_value(a)
1
2
3
4
5
; ┌ @ REPL[8]:1 within `get_value'
movl $5, %eax
retq
nopw %cs:(%rax,%rax)
; └

B - Assembly

1
@code_native get_value(b)
1
2
3
4
5
; ┌ @ REPL[5]:1 within `get_value'
movq (%rdi), %rax
retq
nopw %cs:(%rax,%rax)
; └

給大家參考。