Boron – fast and lightweight stackful coroutines

miniBill2 pts0 comments

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.

license coroutines commit works boron initial

Related Articles