[cffi-devel] optimization opportunities for type translators

James Bielman jamesjb at jamesjb.com
Fri Feb 3 09:41:50 UTC 2006


"Hoehle, Joerg-Cyril" <Joerg-Cyril.Hoehle at t-systems.com> writes:

>>Thu Feb  2 18:41:28 CST 2006  James Bielman  <jamesjb at jamesjb.com>
>>  * Add an optimization for defining non-translatable types.
> Is that something akin to sealing?
>
> Maybe that's a good step towards optimization. I've noticed the
> following behaviour (with CFFI-CVS from last week or so), which led
> me to write this note:
>
> Since the addition of the new type translators, I'd got some bad
> feelings in my stomach (and wrote about it), without the time to
> look closer. Now I looked.
>
> Somehow I feel there's a missing API for compile-time
> transformations in the new branch, similar to the old duality
> provided by translate-to-c <-> to-c-FORM.
>
> To make a long story short, here's output for test struct.5
> (defctype my-int :int)
> (defcstruct s5 (a my-int))
> (deftest struct.5
>     (with-foreign-object (s 's5)
>       (setf (foreign-slot-value s 's5 'a) 42)
>       (foreign-slot-value s 's5 'a))
>   42)

Today's patch allows you to optimize the case where you define a
typedef that you can guarantee does not need translation (as in
this example).  So you can do:

(defctype my-int :int :translate-p nil)

And you should get the same disassembly as before.  Any TRANSLATE-*
methods defined on MY-INT will simply be ignored.

> Ouch.  Two generic function calls, which each call another generic
> function (e.g. translate-to-foreign), some of which cons, e.g.
> (defmethod translate-type-to-foreign (value (type foreign-typedef))
>   ;;We build a list out of the second value returned...
>   ;;IMHO bug: 1. undocumented and 2. most don't provide a second value

This doesn't need to be documented---it builds a list of the optional
second return values from each (possibly nested) type translator for
use internally so that it can recurse down the list when freeing the
object, passing the correct parameters to each free method.  If
user-defined translators don't return a second value, it will just
pass nil to the free method.

> So we compare
> o 4 GF calls in total, and some consing
> o to nothing like this previously
> o with something a C compiler compiles to 2-4 native instructions.
>
> IMHO this hurts. It hurts even more so, since CFFI originaly started
> out from disatisfaction with UFFI on cmucl, where James Bielman
> observed boxing of float values IIRC, and he initially reported
> performance improvements over UFFI using his approach.  Right now,
> I'd expect CFFI to lag far behind UFFI in performance (at least with
> typedefs and structs, other tests are still compiled fine).

Well, the idea here was to get it right first, then get it fast.  The
:TRANSLATE-P argument is a start at optimizing types that won't need
translation.

Ideally, it would be possible to tell at compile-time whether a given
type would need translation based on the set of applicable methods on
TRANSLATE-TO-FOREIGN, but since this method can also be specialized on
the Lisp value to convert, all the specializers are not known.

> I believe there's a need for some translate-*-FORM protocol, which
> can generate code for known types, and eliminate run-time GF calls
> when present, by which I mean that user-defined custom fancy
> converters may still call GF at run-time, they are welcome.  But GF
> is not the typical case, which gets optimized as tight as can be.

I've thought a little bit about this, and I think an interface based
loosely on Common Lisp compiler macros (but always expanded) might be
a good fit here---define the translator using the method when there is
no way around doing the conversion at runtime, but override using the
"compiler macro" (which can punt when necessary and fall back to the
runtime method) when performing conversions on known types.

Obviously, what you lose with such an interface is the ability to
cleanly translate different Lisp types in different ways---for example
passing pointers as :STRING values without translation.  This is the
primary reason the new interface is defined using GFs.

James



More information about the cffi-devel mailing list