Subject: [clisp-list] Re: Please try out FFI speed improvement

From: "Hoehle, Joerg-Cyril" <[email-masked]>
Date: Mon Apr 7 07:30:27 2003

Aurelio Bignoli wrote:
>with-c-var/cast
>   Real time: 1.273894 sec. (it was 1.494392)
>with-foreign-object/%cast
>   Real time: 0.521461 sec. (it was 0.638666)

This is strange, since the compiler macro using LOAD-TIME-VALUE is supposed to do exactly what I did by hand using %CAST directly. Therefore, one should not see any difference in speed (or slowness).

Likewise, WITH-C-VAR is just a compile-time macro (symbol-macrolet) atop with-foreign-object, and the macro usage should be compiled away. Therefore, it should not make a difference at run-time.

>my FFI code for Berkeley DB works fine with this new definition.

Sure, but knowing how it works one can easily defeat it
(e.g. using non-top-level DEF-C-TYPE and DEFUN in same scope).

Therefore, it cannot IMHO become part of standard CLISP. What's in foreign1.lisp must work in all cases for all FFI users, not only in simple situations.

In other words The LOAD-TIME-VALUE optimization is not conservative enough.

I welcome suggestions. Another approach may be to recursively traverse the c-type definiton at compile-time, computing whether the declaration is a simple one or not. If yes, inline it. That's the other side: a too conservative algorithm/optimization.

Regards,
	Jorg Hohle.

---

From: Aurelio Bignoli <[email-masked]>
Date: Tue Apr 8 13:18:03 2003

Hoehle, Joerg-Cyril writes:
 > This is strange, since the compiler macro using LOAD-TIME-VALUE is
 > supposed to do exactly what I did by hand using %CAST
 > directly. Therefore, one should not see any difference in speed (or
 > slowness).

You are right. For my tests I used the following two functions:

(defun get-foreign-data-2 (data size type)
  (with-c-var (p 'c-pointer data)
    (cast p (cond
	     ((eq type 'integer) '(c-ptr int))
	     ((eq type 'string)
	      `(c-ptr (c-array character ,size)))
	     (t (multiple-value-bind (ft byte-size)
		    (foreign-element-type type)
		  `(c-ptr (c-array ,ft ,(/ size byte-size)))))))))

(defun get-foreign-data-3 (data size type)
  (declare (ignore size))
  (cond
   ((eq type 'integer)
    (with-foreign-object (p 'c-pointer data)
       (ffi::foreign-value
	(ffi::%cast p (load-time-value (ffi::parse-c-type '(c-ptr int)))))))
   ((eq type 'string) "")
   (t 0)))

In both cases the COND macro expands into 

(IF (EQ TYPE 'INTEGER)
  ...)

so, in my opinion, the execution time of the two functions should be
equivalent to the execution time of WITH-C-VAR or WITH-FOREIGN-OBJECT
plus the execution time of IF. I was wrong: the following, simpler functions:

(defun get-foreign-int-1 (data)
  (with-c-var (p 'c-pointer data)
    (cast p '(c-ptr int))))

(defun get-foreign-int-2 (data)
  (with-foreign-object (p 'c-pointer data)
       (ffi::foreign-value
	(ffi::%cast p (load-time-value (ffi::parse-c-type '(c-ptr int)))))))

have exactly the same execution time.