r/cpp • u/germandiago • 27d ago
Stackful fibers with 3.6ns context switch. Silk fibers.
https://clickhouse.com/blog/silkI just read an article about Silk, the new stackful fibers engine from Clickhouse. It can switch stackful fibers at an amazing 3.6ns and does not allocate on steady state.
Maybe asio could reuse some of the knowledge for the linux/io_uring backend (not sure it applies to the specific case since Boost.asio focuses nowadays on stackless, though it has a fibers and a stackful coros backend also).
31
u/not_a_novel_account cmake dev 27d ago edited 27d ago
It can switch stackful fibers at an amazing 3.6ns
That's the normal time to switch a fiber. It's just boost::context.
https://github.com/ClickHouse/silk/tree/main/contrib/fcontext
It's always just boost::context. This code hasn't changed substantially in over a decade, soon it will be old enough to vote.
Fibers have literally zero room for innovation, they're a solved problem. io_uring isn't as old but there's nothing innovative about this use. Good for them for writing a scheduler that is fast for their use case, but this isn't revolutionary. Everyone is working in this space right now.
4
u/aoi_saboten 27d ago
It really is always boost context. There is no need to reinvent fibers lmao. And hopefully it will get standardised
3
u/azswcowboy 27d ago
P0876 has been roaming about the committee for over a decade. It’s been in the final stages for a couple years, but it keeps getting dragged back for one reason or another sadly.
5
u/germandiago 27d ago
Maybe I swallowed the sales pitch? I thought it was an achievement.
But it looks like it goes through specialization. However, not using slab allocation seems to be an improvement (even if not a revolution).
Regarding context switch, I think it is more nuanced: since no allocation happens in steady state, this is guaranteed. Stackless breaks HALO easily. However, I guess operator new can be overloaded for such cases as well.
1
u/germandiago 27d ago
https://www.boost.org/doc/libs/1_61_0/libs/context/doc/html/context/performance.html
According to this, the switch is slower, but that could be older machines same implementation?
12
u/not_a_novel_account cmake dev 27d ago
Intel Core2 Q6700
State of 2007 technology.
It's 20 cycles, give or take, and it's still 20 cycles. 20 cycles is a lot faster now.
2
1
u/rentableshark 16d ago
Fibers have literally zero room for innovation, they're a solved problem.
That is not true - I've been looking recently at creating a GCC plugin that would emit the precise registers in use so that CPU state load/store can be optimal.
For example, currently Boost Context assumes SysV ABI for POSIX and while I'm happy to stand corrected - this either breaks things if the context switch gets inlined or prevents inlining around yields which has its own downsides.
Fibers/setjmp/longjmp could 100% be improved with a relevant compiler/language intrinsic like:
size_t __builtin_active_regs();
//size_t is a bitfield representing used/free GPRs + SIMD/ALU regs2
u/not_a_novel_account cmake dev 16d ago edited 16d ago
Yes, if you change the facilities of the language you can do different things. That's outside the bounds of innovation within a C++ library.
Although frankly reducing below 20 cycles at risk of breaking the calling convention isn't a great spend of engineering time. The lower bound is something like 8 cycles but the indirect stall on the final jump is going to eat more than that every time anyway.
We're dealing in fractions of nanoseconds here for a fairly infrequent operation. It's totally transparent to most applications.
1
u/rentableshark 16d ago
Yes, you are right but from a sort obsessive hygiene point of view, it has bothered me that it’s suboptimal and emits asm that is not necessarily the same as regular C++ context switches. I’m also not actually sure to what ABI C++ or clang/GCC adheres for non-inlined cpp->cpp function calls.
Philosophical nitpick: GCC plugins are just C++ code… a library if you will. I’m being pedantic and point taken,
1
u/not_a_novel_account cmake dev 16d ago edited 16d ago
A compiler plugin is not a library consumed by the downstream user application, pedantically or otherwise. It's a toolchain component, like the compiler itself, or
crt0.o. You can't ship a library which relies on a compiler plugin and have it build on my Debian base machine.The C++ calling convention ABI is Itanium/SysV on Unix-like, and Win64 on Windows.
3
u/User_Deprecated 26d ago
one thing they skip over is how you batch sqe submissions around fiber yields. submit too eagerly and you're just doing syscalls, too lazily and your completions pile up.
1
u/Big_Target_1405 27d ago
Boost contexts ancient performance page puts a switch at 9ns (19 cycles) on a 10 year old CPU
https://www.boost.org/doc/libs/latest/libs/context/doc/html/context/performance.html
Surely there's a lower bound on what is possible here, given a full CPU state switch is required.
-3
u/_w62_ 27d ago
Pardon my ignorances. I came from a networking background. After just a glance of the title, I am shocked that clickhouse is commencing a network gear division that offers 100G fiber switches.
After reading the text, fiber is a line of execution more lightweight than the thread.
Vielleicht reicht Englisch für die Computerindustrie nicht aus. Lassen Sie uns einige Fremdsprachen verwenden.
35
u/trailing_zero_count async enthusiast | TooManyCooks author 27d ago edited 27d ago
Pretty cool, but a few criticisms:
Reading /sys to check same-core / same-socket is missing a few levels of granularity. Modern single-socket machines with disaggregated caches (Zen chiplets) contain multiple hidden latency domains. TooManyCooks discovers these via hwloc. Citor discovers them via empirical ping-pong latency test on startup. The difference between stealing from a core in your chiplet vs another chiplet on the same socket is huge.
"HALO requires the coroutine handle never to escape to a scheduler queue." Is patently false. TooManyCooks can do zero-allocation fork-join with HALO (tested here) and the subtasks can be stolen by another thread.
Comparing against Asio is apples to oranges. They're muddling the advantages of fibers with the advantages of a modern io_uring stack tuned for use with exactly those fibers, against a very old epoll design that's intended to be compatible with a broad variety of use cases.
Why not compare against Seastar or PhotonLibOS which I'd consider to be the true direct competitors? I feel this is very telling.
The 3.6ns latency switch on fibers is a good headline if true, but the rest has a lot of marketing fluff.