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