Re: Concurrent native callbacks performance

Diogo via Chicken-users <[email protected]>
Newsgroups gmane.lisp.scheme.chicken
Message-ID <[email protected]>
Hi Felix,

On Wed, Mar 19, 2025 at 10:32:35PM +0100, felix.winkelmann--- via Chicken-users wrote:
> > The goal of the benchmark is to measure the C-to-Scheme call overhead. It
> > consists of a native thread calling one function `(foo)` 10M times. The time is
> > measured in the C program, around the loop calling the function. The time per
> > call is reported. Here is the loop code:
> > [...]
> > Is the approach above a reasonable alternative to cncb, or am I missing some
> > major point?
> >
> Hi! Very interesting, indeed! It's not suprising that the hand rolled variants
> are so much faster. I'm not so sure about the portability issues, though.

Yes, portability could be an issue. One could always fallback to ucontext, but that
will restrict the set of supported systems.

> That the pipe-based approach goes through the kernel naturally has a cost,
> and the current implementation is more intended to have a usable device
> to make communication among native threads possible, than as a high
> performance measure.

I understand. In my case, I am evaluating the use of CHICKEN in a runtime 
checker of C programs. I am trying to avoid losing performance just to enter CHICKEN.

> Can you show us the code for the assembly variant? I'd love to take a look.

Sure, I pushed the code to the following repository:

https://github.com/db7/callseq

The specific stack trick in assembly is implemented in include/crouton.h
At the end of the file you'll find the crouton_swap function defined as
inline assembly for AArch64. It basically takes two pointers to context objects
(defined at the top of the file). And then swap them. The context contains
the value of all relevant save registers including sp (stack pointer) and x30
(the return address used by ret instruction).

The results I sent before were generated with the benchmark in bench/. You can
give a try if you like.

I also tried packing the idea as an egg that auto generates the trampolines
like cncb does. For lack of better name, I called it callseq. The benchmark
will try to build one variant using that, so you have to build callseeq before
building the benchmarks.

Note that the "sequencer" part is still rough (crostini.h). I am not using a
mutex because that will be inefficient. Instead, I am doing "flat combining" by
delegating pending requests to the current lock owner. The global lock is at
the moment a spinlock based on MCS lock. That isn't the end design. The 
waiting threads must park in the kernel (futex). Specially on mobile devices,
with many running threads, that will be important. So, just ignore the heavy
multithreading aspect at the moment. 

Again, any feedback is very welcome. Thank you!

Cheers,
-Diogo
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.