jjl/boron: incredibly fast and lightweight stackful coroutines - Codeberg.org
This website requires JavaScript.
jjl/boron
Watch
Star
Fork
You've already forked boron
Code
Issues
Pull requests
Activity
incredibly fast and lightweight stackful coroutines
1 commit
1 branch
0 tags
42 KiB
51.9%
Assembly
38.1%
Meson
10%
main
Find a file
HTTPS
Download ZIP<br>Download TAR.GZ<br>Download BUNDLE
Open with VS Code
Open with VSCodium
Open with Intellij IDEA
jjl
19ef91436a
initial commit, but it works
2026-07-16 20:48:39 +02:00
include
initial commit, but it works
2026-07-16 20:48:39 +02:00
src
initial commit, but it works
2026-07-16 20:48:39 +02:00
test
initial commit, but it works
2026-07-16 20:48:39 +02:00
LICENSE
initial commit, but it works
2026-07-16 20:48:39 +02:00
meson.build
initial commit, but it works
2026-07-16 20:48:39 +02:00
README.md
initial commit, but it works
2026-07-16 20:48:39 +02:00
README.md
boron - incredibly fast and lightweight stackful coroutines
Boron provides minimalist tools for running stackful coroutines. It is deliberately lightweight to<br>provide a fast and efficient base for building higher level primitives such as green threads.
Supported platforms:
x86-64/SysV
Support planned:
aarch64/SysV
riscv64/SysV
Features:
Spawn coroutines on the provided stack (passing up to 3 pointer-sized arguments!).
Switch coroutines (passing up to 2 pointer-sized arguments!).
Stack watermarking during switch, to help size coroutine stacks more tightly.
Nonfeatures:
SIMD register arguments (why?)
Saving/restoring thread-local state (coroutines are not threads!):
thread local variables
x86 control segment register
x87 floating point state register
Unwinding (don't unwind out of a coroutine, it's UB!)
Performance
Between the benchmarks and fiddling about with some performance tools, I've managed to determine the<br>following on my machine, a Zen 2 3900X:
Starting a coroutine and instantly switching back (predicted): ~24 cycles
Starting a coroutine and instantly switching back (mispredicted): ~37 cycles
Simple (adder) coroutine call and return (predicted): ~18 cycles
Simple (adder) coroutine call and return (mispredicted): ~66 cycles
Switching a nop (predicted): ~9 cycles
Switching a nop (mispredicted): ~31 cycles
Note that the first four of these are measuring two operations per iteration whereas the last two<br>are measuring just one. Double the last two for a straightforward comparison.
Cycle counts are obtained by 2 rdtscs around a million iterations.
If you're wondering how I managed to get a mispredicted cost, I uncovered a Zen 2 bug that makes it<br>mispredict every time. Details are at the bottom of boron.x86-64.S if you're interested.
I haven't tested it on any other machines, your results may differ wildly, but assuming my Zen 2 is<br>representative, I conclude:
Stack watermark tracking basically free even by my standards.
CPUs are able to soak up saving and loading local state and even some arithmetic when switching in<br>a hot loop at essentially no cost.
Branch prediction is the biggest performance factor:
If it works, we are so fast.
If it doesn't work, we're still
Copyright and License
Copyright 2026 James Laver
Licensed under the Apache License, Version 2.0 (the "License");<br>you may not use this file except in compliance with the License.<br>You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software<br>distributed under the License is distributed on an "AS IS" BASIS,<br>WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.<br>See the License for the specific language governing permissions and<br>limitations under the License.