Jerome Abela said:
>I have to confess I didn't understood everything
I should make clear that if your intended use is to dereference slots at will, you should immediately make a foreign-variable object out of the foreign-address one that the C-POINTER :return type gives you.
I posted a foreign-variable constructor a few days ago.
When you later want to dereference some slots, you then use
(defun dereference-now (fv)
(declare (type foreign-variable fv))
(with-c-place (x fv)
(list (deref x) (slot (deref x) 'foo) x))))
This will avoid lots of calls to PARSE-C-TYPE and thus render the application faster.
>(like why the type
>checking is so slow while navigating among foreign types - slower than
>converting it into lisp types ?).
There are (at least) three things that make FFI slow:
o The structure description language is interpreted at run-time by a the FFI implementation. I.e there's an (FFI structure) interpreter on top of a (bytecode) interpreter. Compare this to native compilers where both interpretation levels disappear (at compile-time).
o Calls to PARSE-C-TYPE at run-time. This is currently the case when using WITH-C-VAR, WITH-FOREIGN-OBJECT, ALLOCATE-* etc.
It's not the case with DEF-CALL-OUT, because then PARSE-C-TYPE is invoked at compile-time or load-time only.
This state is not irremediable, and some invocations of PARSE-C-TYPE (with constant types) could be evaluated at compile or load-time as well.
E.g., the (c-pointer mystruct) :return-type extension yields several opportunities for removal of run-time invocation of PARSE-C-TYPE.
o Loop over individual elements as opposed to array-based conversions.
In particular, ELEMENT is slower than conceivable, because for every element accessed, a FOREIGN-VARIABLE object is created and immediately thrown away, so there's much more overhead than people imagine. As opposed to native code compilation, where such loops across arrays are mostly a matter of a few machine instructions.
(with-c-var/c-place (x ...) ; c-ptr (c-array something
(dotimes (i n)
(element (deref x) i)))
is o(2*n) in cost of temporary foreign-variable objects, whereas
(with-c-var/c-place (x ...)
(with-c-place (y (c-var-object (deref x)))
(dotimes (i n) (element y i))))
is only o(1*n) (this is a typical case of optimization by moving a constant expression out of a loop).
Still, both are much, much slower then when you can convert a (c-ptr (c-array x n)) in one go, which CLISP allows (except for the difficulties with arrays of unknown length).
Remember: block operations are faster. Good APIs provide for block operations.
Only pure theoretical computer scientists think that an interface which allows to manipulate one element is enough "because when I can do 1, I can do 1+1, then do 1+1+1" :-)
Similarly, good GUIs provide for operations on several elements in one command. There are enough examples of bad GUIs.
Not only are block operations faster because they eliminate repeated pre-element setup overhead, but they allow additional optimizations (e.g. reorder operations etc.)