Show HN: DOOM in the kernel, or fibers in eBPF
Posted by ayles 2 days ago
Some time ago my coworker who was working on first version of Perforator (https://github.com/yandex/perforator) kept talking about eBPF, so I got curious about its ISA and restrictions. That was around the time I read about DOOM on pregnancy test, so I thought: "what if someone run DOOM inside of Linux kernel in eBPF? Surely, with some restrictions, this should still be possible?"
I started to play around with it somewhere in 2024 - first stripping DOOM to bare minimum that is needed for showcase, simplifying code and trying to pass first restrictions that I encountered - function limit, recursion, memory access and checks. I tried to do this by hand, but it was, well, tedious labor. So I changed direction and instead started to do some of the things with LLVM-passes - rewriting memory access, simplifying and rewriting loops etc. But there were just so many corners. And given absence of time and all, I forgot about this project.
But couple months ago I thought: "LLMs are quite good nowadays, so why not try again this time with more hands". I tried different approaches on how memory access could be "virtualized", how loops can be made bounded, and in general - how to run unbounded logic on such a machine.
When I got DOOM running, I got carried away. Approach was so "generic", so it would be a crime not to try to run more things. And now we have it - lua running on xdp hot path, llama2 working with softfloats, and even cpython, that did not fit initially into 1M verifier budget, is running there now thanks to freplace.
There is ton of work to do in order to make programs run faster, to make integration easier, but working examples are already there.
Comments
Comment by tptacek 1 day ago
Comment by ayles 1 day ago
Comment by MisterTea 1 day ago
Comment by ayles 1 day ago
Comment by tptacek 1 day ago
A big problem with current model AI writing is that the topic sentence of every paragraph reads like a magazine headline, and it can be tricky to catch because a lot of magazine headlines are kind of good --- when they're headlines!
Number with a biography, yeesh. :)
This was neat work, though. Thanks for sharing!
Comment by ayles 1 day ago
Comment by kbigdelysh 20 hours ago
Comment by tptacek 16 hours ago
Comment by rvz 1 day ago
Comment by markrwilliams 1 day ago
"On Linux 6.9 and newer (6.10 on arm64, where JIT support for the arena landed later), the window is backed by bpf_arena... On kernels without a usable arena, the same four gigabytes are assembled from 4-MiB pieces... [in] separate global-data maps."
These maps are of type BPF_MAP_TYPE_ARRAY.
See https://lwn.net/Articles/961941/ for a discussion of `bpf_arena`.
Comment by ayles 1 day ago
Basically, it is better to use maps that can be directly used with load with immediate map index/fd, but we have at most 64 of those, sharing limit with user's data maps and even maps used for (iirc) 7.1 gotox. So for most programs we just use 32 maps or so. If we need more memory - only then array maps (I mean one that has more than 1 element and each element is 4MB) are used as upper part of address space, since they require helper call and are overall slower for our case. But fiber stacks can be allocated from this "slow space", because fiber mostly never reloads its map pointer and fiber stack is aligned so it is always within one such region. (and that is one part of two - memory; second one is about compute and verifier limits and we overcome them by using regions and dispatch-loop)
Comment by morolis 1 day ago
Comment by phishin 1 day ago
Comment by krttherealest 23 hours ago