関数呼び出しのコストを見てみる
気になったので調べてみたついでに、メモしておく。
main.d
import std.string, std.range, std.algorithm, std.conv, std.array, std.stdio; alias double[16] Matrix; Matrix func( Matrix m ) { return m; } Matrix func_rc( ref const Matrix m ) { return m; } auto ref func_ar( Matrix m ) { return m; } auto ref func_ar_rc( ref const Matrix m ) { return m; } auto func_l = ( Matrix m ) => m; auto func_l_rc = ( ref const Matrix m ) => m; Matrix func_i( in Matrix m ) { return m; } auto ref func_ar_i( in Matrix m ) { return m; } auto func_l_i = ( in Matrix m ) => m; void main( string[] args ) { Matrix m = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0 ]; foreach( i; 0..1000000 ) func(m); foreach( i; 0..1000000 ) func_rc(m); foreach( i; 0..1000000 ) func_ar(m); foreach( i; 0..1000000 ) func_ar_rc(m); foreach( i; 0..1000000 ) func_l(m); foreach( i; 0..1000000 ) func_l_rc(m); foreach( i; 0..1000000 ) func_i(m); foreach( i; 0..1000000 ) func_ar_i(m); foreach( i; 0..1000000 ) func_l_i(m); return; }
なコードを -profile付けてコンパイル。
dmd main.d -profile
そして実行して吐いた trace.logを見る。
以下結果。
一回目
======== Timer Is 2935112 Ticks/Sec, Times are in Microsecs ======== Num Tree Func Per Calls Time Time Call 1 12540677 7605232 7605232 _Dmain 11000000 690005 690005 0 pure nothrow @safe const(double[16]) main.__lambda3(const(double[16])) 11000000 687401 687401 0 pure nothrow @safe const(double[16]) main.__lambda2(ref const(double[16])) 11000000 673076 673076 0 double[16] main.func_i(const(double[16])) 11000000 670352 670352 0 const(double[16]) main.func_ar_i(const(double[16])) 11000000 644416 644416 0 pure nothrow @safe double[16] main.__lambda1(double[16]) 11000000 569693 569693 0 double[16] main.func_rc(ref const(double[16])) 11000000 516156 516156 0 double[16] main.func(double[16]) 11000000 439182 439182 0 ref const(double[16]) main.func_ar_rc(ref const(double[16])) 1000000 45160 45160 0 double[16] main.func_ar(double[16])
二回目
======== Timer Is 2935112 Ticks/Sec, Times are in Microsecs ======== Num Tree Func Per Calls Time Time Call 1 13766704 8394815 8394815 _Dmain 12000000 749979 749979 0 pure nothrow @safe const(double[16]) main.__lambda2(ref const(double[16])) 12000000 746487 746487 0 pure nothrow @safe const(double[16]) main.__lambda3(const(double[16])) 12000000 726993 726993 0 const(double[16]) main.func_ar_i(const(double[16])) 12000000 722372 722372 0 double[16] main.func_i(const(double[16])) 12000000 692746 692746 0 pure nothrow @safe double[16] main.__lambda1(double[16]) 12000000 614376 614376 0 double[16] main.func_rc(ref const(double[16])) 12000000 561719 561719 0 double[16] main.func(double[16]) 12000000 467464 467464 0 ref const(double[16]) main.func_ar_rc(ref const(double[16])) 2000000 89749 89749 0 double[16] main.func_ar(double[16])
三回目
======== Timer Is 2935112 Ticks/Sec, Times are in Microsecs ======== Num Tree Func Per Calls Time Time Call 1 14996076 9190335 9190335 _Dmain 13000000 810349 810349 0 pure nothrow @safe const(double[16]) main.__lambda3(const(double[16])) 13000000 801379 801379 0 pure nothrow @safe const(double[16]) main.__lambda2(ref const(double[16])) 13000000 781782 781782 0 const(double[16]) main.func_ar_i(const(double[16])) 13000000 771946 771946 0 double[16] main.func_i(const(double[16])) 13000000 740717 740717 0 pure nothrow @safe double[16] main.__lambda1(double[16]) 13000000 660759 660759 0 double[16] main.func_rc(ref const(double[16])) 13000000 606062 606062 0 double[16] main.func(double[16]) 13000000 497636 497636 0 ref const(double[16]) main.func_ar_rc(ref const(double[16])) 3000000 135108 135108 0 double[16] main.func_ar(double[16])
"auto ref 返り値"って場合によっては実行効率かなり高くなるのか…
そして個人的には "ref const 引数" が "修飾無し引数" より効率悪くなる事の方が驚き。
というか悲しい。
以前コード書いてた時に ref const 修飾子付けたら実行速度上がった事があったから
ずっとそれを盲信して来たのだが…うん…
測定方法がこれで合ってるか確信無いので、
こんな結果も出ましたよってくらいに読み流しておいて下さい。