Running 10 million Codex CLIs on one server – LFI processes A developer's experiment published on kapteko.com tests whether 10 million OpenAI Codex CLI processes could run on a single basement server with 16 CPUs, 100GB of RAM and a 1TB SSD, starting with 10 million empty Rust processes. A minimal `fn main() { park(); }` binary of 300KB consumed 1.73MB of RAM per process, and the author moved to a `#![no_std]` naked-assembly `_start` function calling the ppoll syscall to shrink the footprint further. The stated goal is to run the 10 million Codex CLIs with no changes to Codex source code and no external services. Running 10 million Codex CLIs on one server - LFI processes Sitting on a toilet, I got a great idea - OpenAI spends billions on their servers; let's make them migrate to my infra instead. They have 9 million paying business users, so the business plan is: - Run 10 million Codex CLIs without using any external services - Our data center is a basement server with 16CPU/100GB RAM/1TB SSD - No changes to Codex source code - We can change dependencies - libc, tokio runtime, etc. - We can fork Rust and rebuild anything - We can choose OS/drivers and use our own kernel - The main goal is, of course, money - once we reach the target, we could rent that server for 29.99$ and become rich An experienced engineer would immediately notice that, given the constraints, the task is impossible to solve. Luckily for us, we are missing the required experience, so that blocker is solved. Learning is understanding What is heavier - light blue or false? - is our current mental model. We know little, and even things we know we've misunderstood. An LLM has absolutely destroyed half of my brain, and yet it is the best tool for learning. Throughout the article you'll see prompts which will help you to learn. Every answer from AI will make you only more confused, and confusion is at the core of learning - keep asking. The idea is not to replace reading papers with LLM talk, but to build enough understanding with LLM talk to be able to read papers. \ 1\ https://kapteko.com/running-10-million-codex-clis-on-one-server-lfi-processes/ fn-noos 10 million processes Global warming will kill us all in the end - let's help it by doing a warmup. I have a hunch that it might be a little difficult to run 10 million Codex, so let's start with just 10 million empty running processes. To ensure we understand how things work, let's create an absolutely minimal running process. An empty main wouldn't cut it - we don't want a process to simply exit. We need the minimal process that keeps running while consuming the least amount of resources. 1. loop {} - 16 CPUs divided by 10M gives us 0,0000016CPU per Codex. Plenty, but I think we should start optimising CPU from the beginning, so no busy loop 2. thread::spawn || thread::sleep Duration::MAX - a new thread consumes 48KB of memory; our enormous 100GB divided by 10M gives us a whopping 10KB, which is plenty for super efficient Codex, but too small for running additional threads, skip 3. std::thread::park - ah, the perfection, look at that, sleep is 5 letters, while park is only 4 - 20% less RAM. For a simple Rust fn main { park ; } , the produced binary is 300KB; to run it, the OS needs to load part of it into RAM, initialise kernel structs related to the new process, and then our app itself might allocate RAM for its own needs. In our example, total RAM usage is 1.73MB. Can we do better? First, let's remind ourselves how an OS works: bash $ codex "How OS runs my binaries?" Cloning https://github.com/torvalds/linux Enumerating objects: 11853083, done. Receiving objects: 0% 1/11853083 ^C^C $ codex "How OS runs my binaries? SHORT. LIKE. CAVEMAN" Loads binary. Loads binary libs. Execute machine code. Aha, let's try to remove all the dependencies and also ensure machine code is the smallest with manual Assembly. I remember I've seen no std mentioned in Rust deps. Let's use that - it's probably telling Rust that we do something cool and nonstandard, so we'll get some respect from the compiler and also smaller RAM usage. The following code might look scary, but essentially it is hey oniichan kernel, please run syscall=73 and wait : no std no main unsafe naked no mangle pub extern "C" fn start - { / The simplest way to block a process is to call the kernel syscall ppoll mov loads a syscall number and the svc/syscall instruction makes a call / cfg target arch = "aarch64" core::arch::naked asm "mov x8, 73", // Essentially syscall num=73 "svc 0" // Execute syscall ; / For the rest of the article, I'll focus mainly on ARM, but I want you to appreciate how explicit the instruction for calling a syscall on x86 is / cfg target arch = "x86 64" core::arch::naked asm "mov eax, 271", // syscall number is different, but same idea "syscall" ; } panic handler fn panic : &core::panic::PanicInfo - { // Required even if not used unsafe { core::hint::unreachable unchecked } }