<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>by Anshuman</title><link>https://www.byanshuman.page/</link><description>Writing on systems, GPUs, and distributed runtimes.</description><language>en</language><atom:link href="https://www.byanshuman.page/rss.xml" rel="self" type="application/rss+xml"/><item><title>three hundred processes waited for one pid</title><link>https://www.byanshuman.page/writing/three-hundred-processes-waited-for-one-pid</link><guid isPermaLink="false">https://byanshuman.page/writing/three-hundred-processes-waited-for-one-pid</guid><pubDate>Fri, 31 Jul 2026 00:00:00 GMT</pubDate><description>The first description of HAMi issue 1662 blamed a file called /tmp/vgpulock/lock. Two hundred to three hundred processes were starting at once. Container logs repeated unified_lock locked, waiting 1 second, and a CUDA initialization that should have been quick took roughly a minute.</description><category>hami</category><category>cuda</category><category>kubernetes</category><category>linux</category><category>concurrency</category></item><item><title>the tensor was only the handle</title><link>https://www.byanshuman.page/writing/the-tensor-was-only-the-handle</link><guid isPermaLink="false">https://byanshuman.page/writing/the-tensor-was-only-the-handle</guid><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate><description>I began with a question that seemed too small for an article about an entire framework: when I write x, what exactly do I have? I had written reshape, not clone, and still acquired new storage. The transpose itself moved no values. It changed metadata from row-major strides (4, 1) to (1, 4). Flattening that order…</description><category>pytorch</category><category>systems</category><category>python</category><category>ml-systems</category></item><item><title>One collective call used two generations</title><link>https://www.byanshuman.page/writing/one-collective-call-used-two-generations</link><guid isPermaLink="false">https://byanshuman.page/writing/one-collective-call-used-two-generations</guid><pubDate>Tue, 28 Jul 2026 00:00:00 GMT</pubDate><description>The first two-machine run printed nothing. Locality zero contributes 1. Locality one contributes 2. Both should get 3. The same source worked with one locality, where it triumphantly proved that (1 = 1), but the two-locality process sat there until it was interrupted.</description><category>hpx</category><category>collectives</category><category>cpp</category><category>distributed-systems</category></item><item><title>arrays become matrices</title><link>https://www.byanshuman.page/writing/arrays-become-matrices</link><guid isPermaLink="false">https://byanshuman.page/writing/arrays-become-matrices</guid><pubDate>Mon, 27 Jul 2026 00:00:00 GMT</pubDate><description>The vector owns one contiguous run of storage, a fact established when a retained pointer watched a vector grow in the address investigation. Nothing about those six integers says matrix. C++ sees a vector with six elements.</description><category>cpp</category><category>linear-algebra</category><category>memory</category><category>performance</category></item><item><title>my canary got bigger</title><link>https://www.byanshuman.page/writing/my-canary-got-bigger</link><guid isPermaLink="false">https://byanshuman.page/writing/my-canary-got-bigger</guid><pubDate>Sun, 26 Jul 2026 00:00:00 GMT</pubDate><description>The previous chapter reruns today’s two-configuration research scaffold. This final investigation preserves an earlier end-to-end session at CommCanary commit 02d894a, where the CLI reducer’s default oracle used five configurations. That is why the later ledger says six oracle calls and forty ranking relations…</description><category>ml-systems</category><category>nccl</category><category>benchmarking</category><category>distributed-systems</category></item><item><title>one hundred events became one</title><link>https://www.byanshuman.page/writing/one-hundred-events-became-one</link><guid isPermaLink="false">https://byanshuman.page/writing/one-hundred-events-became-one</guid><pubDate>Sun, 26 Jul 2026 00:00:00 GMT</pubDate><description>A one hundred event communication trace went into a reducer. One event came out. The oracle accepted it. The reducer is commcanary reduce, a ddmin-style minimizer. Delta debugging is the old, honorable idea: delete chunks of the input, keep any deletion that preserves a chosen property, repeat until nothing more can…</description><category>ml-systems</category><category>nccl</category><category>benchmarking</category><category>distributed-systems</category></item><item><title>the address where the value lived</title><link>https://www.byanshuman.page/writing/the-address-where-the-value-lived</link><guid isPermaLink="false">https://byanshuman.page/writing/the-address-where-the-value-lived</guid><pubDate>Wed, 08 Jul 2026 00:00:00 GMT</pubDate><description>values[0] was still 17. The pointer to values[0] was already dead. An ordinary optimized build printed 17 twice on one run. That was the least helpful result it could have produced. The last line looked correct, so the program looked correct.</description><category>cpp</category><category>memory</category><category>allocators</category><category>performance</category></item><item><title>the head pointer came back</title><link>https://www.byanshuman.page/writing/the-head-pointer-came-back</link><guid isPermaLink="false">https://byanshuman.page/writing/the-head-pointer-came-back</guid><pubDate>Tue, 07 Jul 2026 00:00:00 GMT</pubDate><description>The compare-and-swap succeeded. Every node it had observed had already left the queue. The delayed operation read head pointer D, then stopped. Another operation removed D. The storage pool reused that exact address for a later node. Enough queue operations ran for the head pointer to contain D again.</description><category>cpp</category><category>concurrency</category><category>atomics</category><category>performance</category></item><item><title>the syscall the kernel refused</title><link>https://www.byanshuman.page/writing/the-syscall-the-kernel-refused</link><guid isPermaLink="false">https://byanshuman.page/writing/the-syscall-the-kernel-refused</guid><pubDate>Tue, 07 Jul 2026 00:00:00 GMT</pubDate><description>The first call returned a file descriptor. The second returned Operation not permitted. The path did not change. The bytes in the file did not change. The process kept the same user ID. Its working directory stayed where it was. The permission bits were still 0600, which allowed the owner to read and write. One…</description><category>security</category><category>syscalls</category><category>sandbox</category><category>macos</category></item><item><title>idle gaps are not compute</title><link>https://www.byanshuman.page/writing/idle-gaps-are-not-compute</link><guid isPermaLink="false">https://byanshuman.page/writing/idle-gaps-are-not-compute</guid><pubDate>Mon, 06 Jul 2026 00:00:00 GMT</pubDate><description>The collectives chapter ended with algorithms whose cost changes with message size, topology, and arrival skew. A production tuner has to choose among those paths using incomplete evidence. One NCCL configuration looked ordinary until the workload ran.</description><category>ml-systems</category><category>nccl</category><category>gpu</category><category>benchmarking</category></item><item><title>Rings, Trees, and Butterflies: HPX Collectives</title><link>https://www.byanshuman.page/writing/rings-trees-and-butterflies-hpx-collectives-dissected</link><guid isPermaLink="false">https://byanshuman.page/writing/rings-trees-and-butterflies-hpx-collectives-dissected</guid><pubDate>Mon, 06 Jul 2026 00:00:00 GMT</pubDate><description>Every machine calls it, every machine gets back the same total, and nobody wrote a single send or recv. This is a collective: an operation that a whole group of machines performs together, the primitive underneath MPI_Allreduce and a gradient reduction in a distributed training run. The GPU investigation followed…</description><category>hpx</category><category>collectives</category><category>distributed</category></item><item><title>the page that was not there</title><link>https://www.byanshuman.page/writing/the-page-that-was-not-there</link><guid isPermaLink="false">https://byanshuman.page/writing/the-page-that-was-not-there</guid><pubDate>Mon, 06 Jul 2026 00:00:00 GMT</pubDate><description>mmap returned a pointer. None of the memory behind it was resident. The mapping covered 4 MiB. The first loop loaded one byte from every 16 KiB page. It caused exactly 256 minor faults, and all 256 pages became resident. The second loop executed the same source loads without another page fault.</description><category>os</category><category>memory</category><category>performance</category><category>architecture</category></item><item><title>how your computer fakes randomness</title><link>https://www.byanshuman.page/writing/how-your-computer-fakes-randomness</link><guid isPermaLink="false">https://byanshuman.page/writing/how-your-computer-fakes-randomness</guid><pubDate>Sun, 05 Jul 2026 00:00:00 GMT</pubDate><description>The program never called srand. Nothing in its source selected 16807, yet the first process and the third process agreed down to the last bit. A process restart had apparently erased every variable in the program and restored one hidden variable to the same value.</description><category>probability</category><category>statistics</category><category>prng</category></item><item><title>one line to machine code</title><link>https://www.byanshuman.page/writing/one-line-to-machine-code</link><guid isPermaLink="false">https://byanshuman.page/writing/one-line-to-machine-code</guid><pubDate>Tue, 23 Jun 2026 00:00:00 GMT</pubDate><description>Four details did not fit the simple word “compile.” The matrix multiplication became extern_kernels.mm, which is a call through an Inductor lowering rather than a loop visible in this wrapper. The transpose became a different set of strides passed to reinterpret_tensor; no copy appears. The add and relu became…</description><category>compilers</category><category>pytorch</category><category>ml-systems</category></item><item><title>teaching a model</title><link>https://www.byanshuman.page/writing/teaching-a-model</link><guid isPermaLink="false">https://byanshuman.page/writing/teaching-a-model</guid><pubDate>Mon, 15 Jun 2026 00:00:00 GMT</pubDate><description>The loss reached zero while the big matrix stayed untouched. That sounds like the patch learned the task. It did learn the rows I gave it. Later, the same experiment made the model substantially worse on unrelated text. A second patch reached the same training accuracy and disagreed on a held-out prompt. A third…</description><category>fine-tuning</category><category>lora</category><category>alignment</category></item><item><title>one gradient, backward</title><link>https://www.byanshuman.page/writing/one-gradient-backward</link><guid isPermaLink="false">https://byanshuman.page/writing/one-gradient-backward</guid><pubDate>Wed, 03 Jun 2026 00:00:00 GMT</pubDate><description>The tape and PyTorch print the same ten decimal places. The central difference with h=0.1 differs by 0.0008778921. Calling the third row wrong would already assume the first two are the oracle. It is more useful to ask what each method computed. The tape applies stored local derivative rules. PyTorch executes its own…</description><category>autograd</category><category>training</category><category>deep-learning</category></item><item><title>one forward pass</title><link>https://www.byanshuman.page/writing/one-forward-pass</link><guid isPermaLink="false">https://byanshuman.page/writing/one-forward-pass</guid><pubDate>Wed, 27 May 2026 00:00:00 GMT</pubDate><description>Paris is fifth. GPT-2 assigns 8.5 percent to ' the' and 3.2 percent to ' Paris'. The output is not one selected answer. It is a distribution across 50,257 possible next tokens, and the table shows its five largest entries.</description><category>transformers</category><category>inference</category><category>quantization</category></item><item><title>how machines agree</title><link>https://www.byanshuman.page/writing/how-machines-agree</link><guid isPermaLink="false">https://byanshuman.page/writing/how-machines-agree</guid><pubDate>Fri, 22 May 2026 00:00:00 GMT</pubDate><description>A says 5. B says 4. The client sent five increments and there’s no honest answer to “what is the count,” because the two machines that are supposed to be the same machine now disagree, and nothing in this design will ever fix it. There’s no line of code that reconciles them, no moment where B notices it’s behind. The…</description><category>distributed-systems</category><category>consensus</category><category>networking</category></item><item><title>two machines talking to each other</title><link>https://www.byanshuman.page/writing/two-machines-talking-to-each-other</link><guid isPermaLink="false">https://byanshuman.page/writing/two-machines-talking-to-each-other</guid><pubDate>Mon, 04 May 2026 00:00:00 GMT</pubDate><description>Copper. Glass. Sometimes radio. That is the entire physical inventory of networking. Everything else, Ethernet, IP, TCP, RDMA, NCCL, the whole 600-page tower of acronyms, is a way of dressing those three media so that a 1 you put in over here comes out as a 1 over there, with some guarantees about how often it doesn’t.</description><category>ethernet</category></item><item><title>where the time goes</title><link>https://www.byanshuman.page/writing/where-the-time-goes</link><guid isPermaLink="false">https://byanshuman.page/writing/where-the-time-goes</guid><pubDate>Thu, 30 Apr 2026 00:00:00 GMT</pubDate><description>Here’s a program that does exactly one interesting thing. It opens a file and adds up every byte. Twenty-one seconds to add up 67 million numbers. My phone can add 67 million numbers in a blink. And look at the split: 4.61 user is time my code spent running, 15.59 sys is time spent inside the kernel. Three-quarters…</description><category>performance</category><category>os</category><category>systems</category></item><item><title>a file is just bytes</title><link>https://www.byanshuman.page/writing/a-file-is-just-bytes</link><guid isPermaLink="false">https://byanshuman.page/writing/a-file-is-just-bytes</guid><pubDate>Fri, 24 Apr 2026 00:00:00 GMT</pubDate><description>One column came back in 3 milliseconds from one file and 114 milliseconds from the other. Both files had two million logical records with fields named id, category, price, and qty. That is not quite the same as saying they contained the same information. The CSV carried characters and separators but no authoritative…</description><category>data</category><category>parquet</category><category>storage</category></item><item><title>the fast path out of python</title><link>https://www.byanshuman.page/writing/the-fast-path-out-of-python</link><guid isPermaLink="false">https://byanshuman.page/writing/the-fast-path-out-of-python</guid><pubDate>Mon, 20 Apr 2026 00:00:00 GMT</pubDate><description>The same ten million input values, and numpy is eighty-five times faster. I first called them the same additions and the answer bit-for-bit identical. Both statements survive only with qualifications that became important later. Numpy changes the grouping of the additions, and this particular input happens to sum…</description><category>python</category><category>numpy</category><category>performance</category></item><item><title>two threads to a task runtime</title><link>https://www.byanshuman.page/writing/two-threads-to-a-task-runtime</link><guid isPermaLink="false">https://byanshuman.page/writing/two-threads-to-a-task-runtime</guid><pubDate>Wed, 15 Apr 2026 00:00:00 GMT</pubDate><description>There is no typo; the program says what its author meant. And yet a million increments evaporated. This is the first unpleasant fact of concurrency: correct-looking code can produce a different wrong answer every run.</description><category>concurrency</category><category>atomics</category><category>systems</category></item><item><title>from a C loop to a GPU kernel</title><link>https://www.byanshuman.page/writing/from-a-c-loop-to-a-gpu-kernel</link><guid isPermaLink="false">https://byanshuman.page/writing/from-a-c-loop-to-a-gpu-kernel</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><description>The machine refused to give me that exact number. (The 460x came from cross-build arithmetic: the unoptimized naive time divided by an optimized build’s Accelerate sample, 385.4 ms over ~0.84 ms. Two numbers that never lived in the same binary.)</description><category>gpu</category><category>metal</category><category>cpp</category></item><item><title>sixteen million and one</title><link>https://www.byanshuman.page/writing/sixteen-million-and-one</link><guid isPermaLink="false">https://byanshuman.page/writing/sixteen-million-and-one</guid><pubDate>Thu, 26 Mar 2026 00:00:00 GMT</pubDate><description>Not 16777217.0. The number sixteen million seven hundred seventy-two thousand two hundred sixteen survives the addition. The one disappears. Why is 16777216.0f + 1.0f still 16777216.0f? And why does the same shape of thing happen when summing gradients, computing variance, doing a dot product, reducing across…</description><category>numerics</category><category>floating-point</category><category>cpp</category></item><item><title>from source to a running process</title><link>https://www.byanshuman.page/writing/from-source-to-a-running-process</link><guid isPermaLink="false">https://byanshuman.page/writing/from-source-to-a-running-process</guid><pubDate>Sat, 21 Mar 2026 00:00:00 GMT</pubDate><description>The first program was ten lines long. It uses the templates and value categories from the previous article, but understanding the template is not the puzzle here. I wanted to know what the machine received after C++ had finished with it.</description><category>cpp</category><category>toolchain</category><category>linkers</category></item><item><title>Python is a C program</title><link>https://www.byanshuman.page/writing/python-is-a-c-program</link><guid isPermaLink="false">https://byanshuman.page/writing/python-is-a-c-program</guid><pubDate>Sun, 15 Mar 2026 00:00:00 GMT</pubDate><description>The first weird thing was the size. On this Mac, the python3.13 executable is not a giant interpreter binary. It is 52,640 bytes. Fifty-two kilobytes is not enough room for the whole Python runtime, the parser, the compiler, the object system, dictionaries, lists, integers of unbounded size, exceptions, imports,…</description><category>python</category><category>cpython</category><category>c</category></item><item><title>std::move doesn't move anything</title><link>https://www.byanshuman.page/writing/std-move-doesnt-move-anything</link><guid isPermaLink="false">https://byanshuman.page/writing/std-move-doesnt-move-anything</guid><pubDate>Wed, 11 Mar 2026 00:00:00 GMT</pubDate><description>I finally opened the file where std::move lives on my Mac: /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__utility/move.h. I had been typing the name for weeks because the HPX code I was studying was full of it. Somewhere along the way I had started treating it like a compiler instruction…</description><category>cpp</category><category>move-semantics</category><category>hpx</category></item></channel></rss>