[Ecls-list] Speed of indirect calls.

Juan Jose Garcia-Ripoll juanjose.garciaripoll at googlemail.com
Mon Feb 16 10:13:13 UTC 2009

I have done some more testing. The problem with your code, Waldek, is
that it does not only test the speed of indirect calls, but also of
other operations which are not always optimized by the compiler: array
references, symbol lookup, etc.

I have produced another test code (see below), which shows that the
differences are not so large, even with the old code for "funcalling".
The latest comparison with that code shows that we cangain some speed
by reorganizing the function objects and including a default dispatch
pointer, that is a pointer to a function which either does the job
(for functions without a fixed # of arguments) or performs the
dispatch (for functions with a fixed # arguments, generic functions,

However, the speed gain is not that much when you include all other
things in an unoptimized way. For instance, if I remove the DECLAIM at
the top of the code and some type declarations in the macro, execution
times can be three or four times larger.

In any case, the new_cfun branch is probably going to be integrated
into the master tree, for it also includes substantial simplifications
and a more readable C code output.


P.S. Tests were done on an OS X, using gcc 4.0, SBCL 1.0.24 and CLISP 2.45

CALL-FUNCTION    real:   40ms run:   41ms ; SBCL
CALL-SYMBOL      real: 1350ms run: 1353ms

CALL-FUNCTION    real:   98ms run:   99ms ; ECL new_cfun branch
CALL-SYMBOL      real:  179ms run:  180ms
CALL-METHOD1     real:   40ms run:   41ms
CALL-METHOD2     real:   95ms run:   96ms
CALL-METHOD1B    real:   43ms run:   43ms
CALL-METHOD2B    real:   94ms run:   95ms

CALL-FUNCTION    real:  166ms run:  168ms ; ECL master branch
CALL-SYMBOL      real:  189ms run:  190ms

CALL-FUNCTION    real: 1085ms run: 1088ms ; CLISP
CALL-SYMBOL      real: 1089ms run: 1091ms

(declaim (optimize (safety 0) (speed 3)))

(defun f1 (x y) x)
(defun f2 (x y) y)
(defun f3 (x y) nil)
(defun f4 (x y) t)

(deftype index () '(integer 0 #.most-positive-fixnum))

(eval-when (:compile-toplevel :execute)
  (defmacro dotest (method &key (times 10000000) (fdefinition 'fdefinition))
    `(let ((a (mapcar ',fdefinition '(f1 f2 f3 f4))))
       (setf (cdr (last a)) a)
       (let ((run-time (get-internal-run-time))
	     (real-time (get-internal-real-time)))
	 (dotimes (i ,times)
	   (declare (type index i))
	   (,method (car a) i i)
	   (setf a (cdr (the cons a))))
	 (let* ((new-run-time (get-internal-run-time))
		(new-real-time (get-internal-real-time))
		(x (/ internal-time-units-per-second 1000)))
	   (format t "~&~16A~Treal:~T~4Dms~Trun:~T~4Dms" ',method
		   (floor (- new-run-time run-time) x)
		   (floor (- new-real-time real-time) x))))))

  (defmacro call-function (f a b)
    `(funcall (the (function (t t) t) ,f) ,a ,b))
  (defmacro call-symbol (f a b)
    `(funcall (the symbol ,f) ,a ,b))
); eval-when

(dotest call-function)
(dotest call-symbol :fdefinition identity)

;;; Comment out for the new_cfun branch

(eval-when (:compile-toplevel)
  (defmacro call-method1 (f a b)
    `(ffi:c-inline (,f ,a ,b) (:object :object :object) t
		   :one-liner t))
  (defmacro call-method2 (f a b)
    `(ffi:c-inline (,f ,a ,b) (:object :object :object) t
		   :one-liner t))
  (defmacro call-method1b (f a b)
    `(ffi:c-inline (,f ,a ,b) (:object :object :object) t
                 :one-liner t))
  (defmacro call-method2b (f a b)
    `(ffi:c-inline (,f ,a ,b) (:object :object :object) t
		   :one-liner t))
) ; eval-when

(dotest call-method1)
(dotest call-method2)
(dotest call-method1b :fdefinition identity)
(dotest call-method2b :fdefinition identity)

Instituto de Física Fundamental, CSIC
c/ Serrano, 113b, Madrid 28009 (Spain)

More information about the ecl-devel mailing list