2015-12-05-01-思い出したのでファンクタを再び
>> Site top >> weblog >> 月別アーカイブ >> 2015年12月のlog >> 2015-12-05-01-思い出したのでファンクタを再び
最終更新日付:2015/12/05 01:00:00
思い出したのでファンクタを再び
2015 年 12 月 05 日
2 年くらい前、まだ現在のかたちになる前の CL-STL で、ファンクタ呼び出しのパフォーマンスについてぐだぐだ書いていた記事があった。それを読み返していて、現状はどうなっているのか、そこが気になった。今日はそんな話。
やることは2年前と変わらない。ただ、現在の CL-STL で動作するようなコードを書いて動かしてみるだけだ。まず、基準となる関数 foo-function を用意する。
(locally (declare (optimize speed)) (defun foo-function (n) (declare (type fixnum n)) (the fixnum (* 2 n))))
で、これに対応するファンクタクラス foo-functor は以下のようになる。やっぱりアレだな。なんとかなんないかなこれ。
(defclass foo-functor (#-cl-stl-0x98 stl:functor #+cl-stl-0x98 stl:unary-function) ()) (declare-constructor foo-functor (0)) (locally (declare (optimize speed)) (labels ((__foo-fnctr-ctor () (make-instance 'foo-functor :closure (lambda (n) (* 2 n))))) (define-constructor foo-functor () (__foo-fnctr-ctor)) (defmethod operator_clone ((obj foo-functor)) (__foo-fnctr-ctor))))
次に、指定された回数だけファンクタ(または関数)をコールするテスト関数を作成する。
(locally (declare (optimize speed)) (defun function-test (fnc n) (declare (type cl:function fnc)) (declare (type fixnum n)) (dotimes (i n) (funcall fnc i)))) (locally (declare (optimize speed)) (defun functor-test1 (fnc n) (declare (type fixnum n)) (dotimes (i n) (stl:functor-call fnc i)))) (locally (declare (optimize speed)) (defun functor-test2 (fnc n) (declare (type fixnum n)) (let ((fnc (stl:functor-function fnc))) (declare (type cl:function fnc)) (dotimes (i n) (funcall fnc i)))))
みればわかると思うが、概ね以下の通り。
- function-test:関数を直接コールする(これが基準になる)
- functor-test1:stl:functor-call を繰り返しコールする
- functor-test2:stl:functor-function で関数を(一度だけ)取得してから繰り返し funcall する
これを以下の要領で実行する。繰り返し回数は1億回。
(defparameter *count* 100000000) (time (function-test #'foo-function *count*)) (time (functor-test1 #'foo-function *count*)) (time (functor-test1 (new foo-functor) *count*)) (time (functor-test2 #'foo-function *count*)) (time (functor-test2 (new foo-functor) *count*))
5種類のテストについて10回程度実行し、time が表示する processor cycles の結果が最も良いものを採用した結果は以下の通り。
テスト関数 | オペランド | processor cycles | 比率 |
---|---|---|---|
function-test | #'foo-function | 1,068,515,087 | 1.000 |
functor-test1 | #'foo-function | 4,887,013,104 | 4.574 |
functor-test1 | (new foo-functor) | 5,932,309,691 | 5.552 |
functor-test2 | #'foo-function | 1,043,676,628 | 0.977 |
functor-test2 | (new foo-functor) | 1,282,054,753 | 1.200 |
まぁなんというか、以前と対して変わらない。直接 stl:functor-call するのはおおむね5倍遅いし、一度 stl:functor-function で関数を取得してから繰り返しコールする functor-test2 はまぁ関数の直接呼び出しと変わらない。この結果には安心していいと思うが、一方で満足してもいけない。特に、5倍ってのがなんとかならないかと思うし、それよりも気になるのはファンクタを自作する時の煩雑さだ。本当に、なんとかならないだろうか。
コメント
このページのタグ
Page tag : STLとその移植
Page tag : Common Lisp
Copyright(C) 2005-2021 project-enigma.
Generated by CL-PREFAB.