Reusing cast values

18 views
Skip to first unread message

Sébastien Pierre

unread,
Nov 19, 2016, 9:10:57 AM11/19/16
to python-cffi
Hi there!

I'm using CFFI to wrap a C parsing library, with quite a lot of success so far (I had a ctypes implementation, and the CFFI version is much faster thanks to lower function call overhead). I'm trying to optimize the bindings and have noticed that most of the CPU time is spent wrapping C objects as Python objects (as opposed to code spent in processing the parsing result).

One of the call that pops up often in the profiler is "ffi.cast" (because it's called so oten), so I was wondering if I could re-use the object and reassign an uncast void* pointer. For instance

cobject = ffi.cast("Match*", untyped_pointer)
...
# Here's what I'd like to do
cobject.set_pointer(other_utyped_pointer)


Thanks!

-- Sébastien



Armin Rigo

unread,
Nov 19, 2016, 10:55:25 AM11/19/16
to pytho...@googlegroups.com
Hi,

On 19 November 2016 at 15:10, Sébastien Pierre
<sebastie...@gmail.com> wrote:
> One of the call that pops up often in the profiler is "ffi.cast" (because
> it's called so oten), so I was wondering if I could re-use the object and
> reassign an uncast void* pointer. For instance
>
> cobject = ffi.cast("Match*", untyped_pointer)
> ...
> # Here's what I'd like to do
> cobject.set_pointer(other_utyped_pointer)

Sorry, cdata objects are supposed to be immutable, so no. Allowing
that would break other things, e.g. their hash().

Are you using an ffi object loaded by set_source(), or one created by
cffi.FFI()? The former is faster for various things, including
function calls but also ffi.cast().

If you need the last bits of performance you can avoid a dictionary
lookup by calling ``ffi.cast(match_type, untyped_pointer)``, with a
precomputed value of ``match_type = ffi.typeof("Match*")``.


A bientôt,

Armin.

Sébastien Pierre

unread,
Nov 23, 2016, 3:50:27 PM11/23/16
to python-cffi
Hi Armin,

I'm using the API mode (set_source) -- but it's useful to know that we can cache the match_type, it's definitely going to make a difference in the 500K+ calls it makes in one parsing.

Thanks!

-- Sébastien

Armin Rigo

unread,
Nov 23, 2016, 7:01:34 PM11/23/16
to pytho...@googlegroups.com
Hi Sébastien,

On 23 November 2016 at 21:50, Sébastien Pierre
<sebastie...@gmail.com> wrote:
> I'm using the API mode (set_source) -- but it's useful to know that we can
> cache the match_type, it's definitely going to make a difference in the
> 500K+ calls it makes in one parsing.

Ok! Fwiw, 500K dictionary calls in CPython should not cost more than
50 or 100 ms, as a guess. If you are really desperate for
performance, try PyPy: the optimization we're talking about should
happen automatically there, but of course the rest is likely to be
much faster too.


A bientôt,

Armin.

Sébastien Pierre

unread,
Nov 28, 2016, 3:05:58 PM11/28/16
to python-cffi
Interestingly enough, there is little performance gained by switching to PyPy (or Py3K) -- it seems that the main performance loss comes from the back-and-forth between C and Python (basically iterating on the AST, which requires wrapping each AST node in a Python object). Last time I measured, about 5% of the time was spent on parsing while 95% was spent on iterating the result tree. The way I was using cytpes had horrendous performance compared to CFFI in this respect.

Armin Rigo

unread,
Nov 29, 2016, 5:02:51 AM11/29/16
to pytho...@googlegroups.com
Hi Sébastien,

On 28 November 2016 at 21:05, Sébastien Pierre
<sebastie...@gmail.com> wrote:
> Interestingly enough, there is little performance gained by switching to
> PyPy (or Py3K)

You can't use PyPy3 right now for performance comparisons. The next
alpha release of PyPy3, supporting 3.5, will hopefully have fixed the
most glaring performance issues. I guess your project is Python 3
only, so you can't try PyPy2? Too bad. I'd really think that PyPy
should be much faster if your program does a large number of calls
between Python and C.


A bientôt,

Armin.
Reply all
Reply to author
Forward
0 new messages