inline #1 ほんとに速くなる?
結論: それなりに速くなる、と思ってよさそう。
「それなりに」というのは、今回やったのは処理自体がそんなに時間かかるものではないので関数呼び出しのオーバーヘッドが相対的に大きかったはず。つまり実際の処理がもっと時間かかるものだと関数呼び出しのオーバーヘッドは相対的に小っさくなるので、これを avoid しても大して変わらんという場合もありえる。
とはいえ、今回の処理自体(`(oddp (example-value X))`)の半分くらいの時間を喰ってたみたいなので、まぁなんというか「それなり」と。
;;; 準備 (defstruct example value) => #<structure-definition: example> ;; この関数を呼び出す関数と、同等の式を埋め込んだ関数で比較 (defun ev-oddp (obj) (oddp (example-value obj))) => ev-oddp (compile 'ev-oddp) => ev-oddp ;; 実験用の生け贄 (setq X (make-example :value 88)) => #S(example value 88)
(defmacro bench (form) `(float (time 100 (dotimes (n 5000) ,form)))) => bench ;; ev-oddp を呼び出す版 (defun test-call () (bench (ev-oddp X))) => test-call (compile 'test-call) => test-call ;; 埋め込んだ版 (defun test-inline () (bench (oddp (example-value X)))) => test-inline (compile 'test-inline) => test-inline ;; 結果: けっこー違った (test-call) => 8.184972 (test-inline) => 5.439945
絶対値でわかるともうちょっと役に立つのだけど、いかんせんそんな小っさな数字を信用していいのか(計測精度的に)って問題が。
bench macro に nil だけ渡してただただ 5000回 nil を返す関数でやってみたらそれだけで 0.24μsec ほどかかってることになってるので、信用できるかは疑問なのだが、この nil 返すだけの 0.24μsec ほどを dotimes やらのオーバーヘッドとして取り除くと
- test-call=> 1回あたり 1.41μsec くらい
- test-inline=> 1回あたり 0.86μsec くらい
関数呼び出しのオーバーヘッドは 0.55μsec くらいで実際の処理の半分以上ということに。
信用できたとしても他の処理がどれくらいかかるかわかんないので、それが大きいのか小っさいのか感覚的にわからんというしょーもない結果に。