読者です 読者をやめる 読者になる 読者になる

=関数よりもeql関数の方が速かった(間接呼び出し時)

sbcl speed optimize

以下、sbcl-1.0.51-x86-64-linuxでの実行結果。

;; 計時用関数
(defun compare-time (fn nums1 nums2)
  (declare (optimize (speed 3) (safety 0) (debug 0))
           (function fn))
  (time
    (loop FOR n1 fixnum IN nums1
          FOR n2 fixnum IN nums2
          WHEN (funcall fn n1 n2)
          SUM 1)))

;; fixnum用の=関数
(declaim (inline fixnum=))
(defun fixnum= (a b)
  (declare (fixnum a b)
           (optimize (speed 3) (safety 0) (debug 0)))
  (= a b))

;; データ
(defparameter *nums1* (loop REPEAT 10000000 COLLECT (random 1000000)))
(defparameter *nums2* (loop REPEAT 10000000 COLLECT (random 1000000)))
;;;; 比較
;; =関数
(compare-time #'= *nums1* *nums2*)
Evaluation took:
  1.312 seconds of real time
  1.300000 seconds of total run time (1.300000 user, 0.000000 system)
  99.09% CPU
  2,616,703,170 processor cycles
  0 bytes consed
==> 12

;; fixnum=関数
(compare-time #'fixnum= *nums1* *nums2*)
Evaluation took:
  0.367 seconds of real time
  0.350000 seconds of total run time (0.320000 user, 0.030000 system)
  95.37% CPU
  732,105,438 processor cycles
  0 bytes consed
==> 12

;; eql関数
(compare-time #'eql *nums1* *nums2*)
Evaluation took:
  0.202 seconds of real time
  0.190000 seconds of total run time (0.190000 user, 0.000000 system)
  94.06% CPU
  403,706,880 processor cycles
  0 bytes consed
==>

eql関数の方がだいぶ効率的。少し意外。


直接使用するなら=関数とeqlの間に差異はない。(fixnum=関数はなぜか遅い)

;; =
(time
 (locally
  (declare (optimize (speed 3) (safety 0) (debug 0)))
  (loop FOR n1 fixnum IN *nums1*
        FOR n2 fixnum IN *nums2*
        WHEN (= n1 n2)
        SUM 1)))
Evaluation took:
  0.074 seconds of real time
  0.080000 seconds of total run time (0.080000 user, 0.000000 system)
  108.11% CPU
  147,692,292 processor cycles
  0 bytes consed
==> 12

;; fixnum=
(time
 (locally
  (declare (optimize (speed 3) (safety 0) (debug 0)))
  (loop FOR n1 fixnum IN *nums1*
        FOR n2 fixnum IN *nums2*
        WHEN (fixnum= n1 n2)
        SUM 1)))
Evaluation took:
  0.299 seconds of real time
  0.300000 seconds of total run time (0.300000 user, 0.000000 system)
  100.33% CPU
  595,071,324 processor cycles
  0 bytes consed
==> 12

;; eql
(time
 (locally
  (declare (optimize (speed 3) (safety 0) (debug 0)))
  (loop FOR n1 fixnum IN *nums1*
        FOR n2 fixnum IN *nums2*
        WHEN (eql n1 n2)
        SUM 1)))
Evaluation took:
  0.076 seconds of real time
  0.070000 seconds of total run time (0.070000 user, 0.000000 system)
  92.11% CPU
  150,384,648 processor cycles
  0 bytes consed
==> 12