<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>loop-unroller</title>
<link>https://loop-unroller.eu/</link>
<atom:link href="https://loop-unroller.eu/index.xml" rel="self" type="application/rss+xml"/>
<description></description>
<generator>quarto-1.10.19</generator>
<lastBuildDate>Sat, 10 Oct 2026 00:00:00 GMT</lastBuildDate>
<item>
  <title>From prompt to token: LLM inference on a GPU, and on a thermodynamic chip</title>
  <dc:creator>Victor Bieszka</dc:creator>
  <link>https://loop-unroller.eu/posts/2026-10-10-llm-inference-thermodynamic.html</link>
  <description><![CDATA[ 





<p>In my <a href="../posts/2026-10-09-thermodynamic-processors-primer.html">primer on thermodynamic processors</a> I argued that generative AI is, at its core, a sampling problem, and that hardware which samples natively could do that job far more efficiently than a GPU. That is a nice slogan. In this post I want to make it concrete by following a single request, <em>“What is the capital of France?”</em>, through today’s hardware and then through a hypothetical thermodynamic one.</p>
<p>For the second half I’ll be generous: assume the hard problems from the primer (scaling to millions of cells, precise couplings, fast I/O, models that match transformer quality) have been solved. The question is not <em>whether</em> that happens, but what an LLM server would look like <em>if</em> it does.</p>
<section id="part-1-serving-an-llm-today" class="level2">
<h2 class="anchored" data-anchor-id="part-1-serving-an-llm-today">Part 1: Serving an LLM today</h2>
<section id="the-life-of-a-request" class="level3">
<h3 class="anchored" data-anchor-id="the-life-of-a-request">The life of a request</h3>
<p>A modern LLM server is a CPU and one or more GPUs working as a team. The CPU does the bookkeeping, the GPU does the maths.</p>
<div class="cell" data-layout-align="default">
<div class="cell-output-display">
<div>
<p></p><figure class="figure"><p></p>
<div>
<pre class="mermaid mermaid-js">sequenceDiagram
    participant U as Client
    participant C as CPU (API server)
    participant G as GPU
    U-&gt;&gt;C: prompt (text)
    C-&gt;&gt;C: tokenize, schedule into a batch
    C-&gt;&gt;G: token IDs
    G-&gt;&gt;G: prefill: all prompt tokens in parallel, fill KV cache
    loop until end-of-sequence or max tokens
        G-&gt;&gt;G: decode: one forward pass → logits
        G-&gt;&gt;G: sample the next token
        G--&gt;&gt;C: token ID
        C--&gt;&gt;U: detokenized text (streamed)
    end
</pre>
</div>
<p></p><figcaption> One request through a typical CPU + GPU serving stack.</figcaption> </figure><p></p>
</div>
</div>
</div>
<ol type="1">
<li><strong>Tokenization (CPU).</strong> The text is split into tokens, integer IDs from a vocabulary of typically 30k–250k entries. <em>“What is the capital of France?”</em> becomes about eight of them.</li>
<li><strong>Scheduling (CPU).</strong> The server does not run one request at a time. A scheduler continuously merges requests into batches and manages GPU memory for them. Serving engines like vLLM page the per-request state much like an operating system pages virtual memory <span class="citation" data-cites="kwon2023vllm">(Kwon et al. 2023)</span>.</li>
<li><strong>Prefill (GPU).</strong> All prompt tokens go through the network at once. Every layer produces a <em>key</em> and a <em>value</em> vector per token, which are stored in the <strong>KV cache</strong> so they never have to be recomputed. Prefill determines the <em>time to first token</em>.</li>
<li><strong>Decode (GPU).</strong> Now the model generates, one token per forward pass. Each pass looks at the KV cache, appends one entry and produces a vector of <strong>logits</strong>, one score per vocabulary entry.</li>
<li><strong>Sampling (GPU).</strong> The logits are turned into a probability distribution, and one token is drawn from it. That token is fed back in as the input of the next decode step.</li>
<li><strong>Detokenization and streaming (CPU).</strong> Token IDs are turned back into text and streamed to the client.</li>
</ol>
<p>Steps 3 and 4 run the same network, but they stress the hardware in completely different ways. To see why, we need a bit of maths.</p>
</section>
<section id="prefill-is-compute-bound-decode-is-memory-bound" class="level3">
<h3 class="anchored" data-anchor-id="prefill-is-compute-bound-decode-is-memory-bound">Prefill is compute-bound, decode is memory-bound</h3>
<p>A transformer with <img src="https://latex.codecogs.com/png.latex?N"> parameters needs roughly <img src="https://latex.codecogs.com/png.latex?2N"> floating-point operations per token: one multiply and one add per weight. For a prompt of <img src="https://latex.codecogs.com/png.latex?L"> tokens, prefill therefore costs</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctext%7BFLOPs%7D_%5Ctext%7Bprefill%7D%20%5Capprox%202NL,%0A"></p>
<p>and the weights only have to be read from memory <em>once</em> for all <img src="https://latex.codecogs.com/png.latex?L"> tokens.</p>
<p>Decode is different. Every step produces a single token per sequence, but it still has to stream <strong>all</strong> weights from GPU memory (HBM) into the compute units. With a batch of <img src="https://latex.codecogs.com/png.latex?B"> sequences and 16-bit weights (2 bytes each), one decode step does about <img src="https://latex.codecogs.com/png.latex?2NB"> FLOPs while moving <img src="https://latex.codecogs.com/png.latex?2N"> bytes. The ratio of the two is the <strong>arithmetic intensity</strong> <img src="https://latex.codecogs.com/png.latex?I">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AI_%5Ctext%7Bdecode%7D%20%5Capprox%20%5Cfrac%7B2NB%7D%7B2N%7D%20=%20B%20%5C%20%5Cfrac%7B%5Ctext%7BFLOP%7D%7D%7B%5Ctext%7Bbyte%7D%7D,%20%5Cqquad%20I_%5Ctext%7Bprefill%7D%20%5Capprox%20L%20%5C%20%5Cfrac%7B%5Ctext%7BFLOP%7D%7D%7B%5Ctext%7Bbyte%7D%7D.%0A"></p>
<p>The <em>roofline model</em> <span class="citation" data-cites="williams2009roofline">(Williams et al. 2009)</span> tells us what a chip can deliver at a given intensity: either it is limited by memory bandwidth <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> or by peak compute <img src="https://latex.codecogs.com/png.latex?%5Cpi">,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AP(I)%20=%20%5Cmin(%5Cpi,%5C%20%5Cbeta%20%5Ccdot%20I).%0A"></p>
<p>An Nvidia H100 SXM has <img src="https://latex.codecogs.com/png.latex?%5Cpi%20%5Capprox%20989"> TFLOP/s (dense BF16) and <img src="https://latex.codecogs.com/png.latex?%5Cbeta%20%5Capprox%203.35"> TB/s. The <em>ridge point</em>, where the two limits meet, is at <img src="https://latex.codecogs.com/png.latex?%5Cpi%20/%20%5Cbeta%20%5Capprox%20295"> FLOP/byte. Anything below that leaves compute units idle while they wait for data.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code hidden" id="cb1" data-startfrom="75" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 74;"><span id="cb1-75">{</span>
<span id="cb1-76">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> peak <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">989</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> bw <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.35</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-77">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> xs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> d3<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">range</span>(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.01</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.02</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(e <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> e)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-78">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> roof <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> xs<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(I <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> ({I<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">perf</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Math</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">min</span>(peak<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> bw <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> I)}))<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-79">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> points <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb1-80">    {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">name</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"decode, batch 1"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">I</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>}<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-81">    {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">name</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"decode, batch 64"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">I</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">64</span>}<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-82">    {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">name</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"prefill, 2k-token prompt"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">I</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2000</span>}<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-83">  ]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(p <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> ({<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">...</span>p<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">perf</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Math</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">min</span>(peak<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> bw <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> p<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">I</span>)}))<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-84">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> Plot<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>({</span>
<span id="cb1-85">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">width</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">640</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-86">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">marginRight</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-87">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">x</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">type</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"log"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">label</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Arithmetic intensity (FLOP/byte) →"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">grid</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span>}<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-88">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">y</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">type</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"log"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">label</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"↑ Attainable TFLOP/s"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">domain</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2000</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">grid</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span>}<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-89">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">marks</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> [</span>
<span id="cb1-90">      Plot<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">line</span>(roof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">x</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"I"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">y</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"perf"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">strokeWidth</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.5</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">stroke</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#00bc8c"</span>})<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-91">      Plot<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ruleX</span>([peak <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> bw]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">strokeDasharray</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"4,4"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">strokeOpacity</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.6</span>})<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-92">      Plot<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">text</span>([{<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">I</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> peak <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> bw<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">perf</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.4</span>}]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">x</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"I"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">y</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"perf"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">text</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ridge ≈ 295"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">dx</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">textAnchor</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"start"</span>})<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-93">      Plot<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dot</span>(points<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">x</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"I"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">y</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"perf"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">r</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">fill</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"currentColor"</span>})<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-94">      Plot<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">text</span>(points<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">x</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"I"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">y</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"perf"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">text</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"name"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">dy</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">14</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">textAnchor</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"end"</span>})<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-95">    ]</span>
<span id="cb1-96">  })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-97">}</span></code></pre></div></div>
<div id="fig-roofline" class="cell-output cell-output-display quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-roofline-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div id="ojs-cell-1" data-nodetype="expression">

</div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-roofline-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: Roofline of an H100 (log-log). Decode at small batch sizes sits far left on the memory-bound slope; prefill of a long prompt reaches the compute roof.
</figcaption>
</figure>
</div>
</div>
<p>A back-of-the-envelope example with an 8B-parameter model in BF16, i.e.&nbsp;~16 GB of weights:</p>
<ul>
<li><strong>Prefill</strong> of a 2,000-token prompt: <img src="https://latex.codecogs.com/png.latex?2%20%5Ccdot%208%20%5Ccdot%2010%5E9%20%5Ccdot%202000%20%5Capprox%203.2%20%5Ccdot%2010%5E%7B13%7D"> FLOPs, about <strong>32 ms</strong> at peak compute.</li>
<li><strong>Decode</strong> at batch size 1: every token requires reading 16 GB, so the GPU can produce at most <img src="https://latex.codecogs.com/png.latex?3.35%5C,%5Ctext%7BTB/s%7D%20%5C,/%5C,%2016%5C,%5Ctext%7BGB%7D%20%5Capprox"> <strong>210 tokens/s</strong>, using well under 1% of its compute.</li>
</ul>
<p>This is why serving is all about batching: a larger <img src="https://latex.codecogs.com/png.latex?B"> moves decode to the right on the roofline and amortises each weight read over more users <span class="citation" data-cites="pope2022scaling">(Pope et al. 2022)</span>. It is also why tricks like speculative decoding exist, which guess several tokens cheaply and verify them in one pass <span class="citation" data-cites="leviathan2023speculative">(Leviathan et al. 2023)</span>.</p>
<p>The KV cache makes things worse as contexts grow. Per token it stores</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctext%7BKV%20bytes%20per%20token%7D%20=%202%20%5Ccdot%20n_%5Ctext%7Blayers%7D%20%5Ccdot%20n_%5Ctext%7Bkv%20heads%7D%20%5Ccdot%20d_%5Ctext%7Bhead%7D%20%5Ccdot%20%5Ctext%7Bbytes%20per%20value%7D.%0A"></p>
<p>For a Llama-3-8B-style model (<img src="https://latex.codecogs.com/png.latex?32"> layers, <img src="https://latex.codecogs.com/png.latex?8"> KV heads, <img src="https://latex.codecogs.com/png.latex?d_%5Ctext%7Bhead%7D%20=%20128">, BF16) that is <img src="https://latex.codecogs.com/png.latex?2%20%5Ccdot%2032%20%5Ccdot%208%20%5Ccdot%20128%20%5Ccdot%202%20=%20131%7B,%7D072"> bytes, i.e.&nbsp;<strong>128 KiB per token</strong>. An 8k-token conversation holds 1 GiB of cache, which has to be read on every decode step as well.</p>
</section>
<section id="where-the-energy-goes" class="level3">
<h3 class="anchored" data-anchor-id="where-the-energy-goes">Where the energy goes</h3>
<p>The punchline for energy: moving a value from DRAM costs on the order of a hundred times more energy than doing arithmetic on it <span class="citation" data-cites="horowitz2014energy">(Horowitz 2014)</span>. Decode is dominated by exactly that: shuffling weights and KV cache from HBM to the compute units, over and over, once per generated token. The actual “creative” step, picking the next token, is almost free in comparison.</p>
</section>
<section id="the-sampling-step-is-a-boltzmann-distribution" class="level3">
<h3 class="anchored" data-anchor-id="the-sampling-step-is-a-boltzmann-distribution">The sampling step is a Boltzmann distribution</h3>
<p>Let’s look at that last step more closely, because this is where the thermodynamic story begins. Given logits <img src="https://latex.codecogs.com/png.latex?z_1,%20%5Cdots,%20z_V">, the model samples token <img src="https://latex.codecogs.com/png.latex?i"> with probability</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ap(i)%20=%20%5Cfrac%7Be%5E%7Bz_i%20/%20T%7D%7D%7B%5Csum_%7Bj=1%7D%5E%7BV%7D%20e%5E%7Bz_j%20/%20T%7D%7D,%0A"></p>
<p>where <img src="https://latex.codecogs.com/png.latex?T"> is the <em>temperature</em> knob you may know from LLM APIs. Compare that to the Boltzmann distribution from the primer, <img src="https://latex.codecogs.com/png.latex?p(x)%20%5Cpropto%20e%5E%7B-E(x)/kT%7D">. They are the same formula, with energy <img src="https://latex.codecogs.com/png.latex?E_i%20=%20-z_i">. <strong>Every LLM already ends with a Boltzmann sampler</strong>, just one that is simulated in floating point on a GPU.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code hidden" id="cb2" data-startfrom="130" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 129;"><span id="cb2-130">viewof T <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Inputs<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">range</span>([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">value</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">step</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">label</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Temperature T"</span>})</span></code></pre></div></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-2" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code hidden" id="cb3" data-startfrom="136" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 135;"><span id="cb3-136">{</span>
<span id="cb3-137">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> logits <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Paris"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.1</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lyon"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.2</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"France"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.9</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"the"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.4</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"a"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.8</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Nice"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Berlin"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.4</span>]]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-138">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> logits<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(([<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> z]) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Math</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">exp</span>(z <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> T))<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-139">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> Z <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> d3<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(w)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-140">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> logits<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(([token]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> i) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> ({token<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">p</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> w[i] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> Z}))<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-141">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> Plot<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>({</span>
<span id="cb3-142">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">width</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">640</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb3-143">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">x</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">domain</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(d <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> d<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">token</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">label</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">null</span>}<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb3-144">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">y</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">domain</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">label</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"↑ p(token)"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">grid</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span>}<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb3-145">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">marks</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> [</span>
<span id="cb3-146">      Plot<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">barY</span>(data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">x</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"token"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">y</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"p"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">fill</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#00bc8c"</span>})<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb3-147">      Plot<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">text</span>(data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">x</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"token"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">y</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"p"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">text</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> d <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> d<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">p</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">toFixed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">dy</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>})<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb3-148">      Plot<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ruleY</span>([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb3-149">    ]</span>
<span id="cb3-150">  })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-151">}</span></code></pre></div></div>
<div id="fig-temperature" class="cell-output cell-output-display quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-temperature-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div id="ojs-cell-3" data-nodetype="expression">

</div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-temperature-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;2: Next-token distribution for <em>“The capital of France is …”</em> with made-up logits. Low temperatures freeze the distribution onto the most likely token; high temperatures flatten it.
</figcaption>
</figure>
</div>
</div>
<p>So can we just replace the sampler with a thermodynamic chip? We could, but it would be pointless. A categorical distribution over 128k entries is a tiny computation; the expensive part is everything <em>before</em> it, the forward pass that produces the logits. To gain anything, the thermodynamic hardware has to take over the heavy lifting, not just the last step.</p>
</section>
</section>
<section id="part-2-serving-the-same-request-on-a-thermodynamic-processor" class="level2">
<h2 class="anchored" data-anchor-id="part-2-serving-the-same-request-on-a-thermodynamic-processor">Part 2: Serving the same request on a thermodynamic processor</h2>
<p>From here on we enter speculation. Assume a mature <em>thermodynamic sampling unit</em> (TSU): millions of p-bits, programmable couplings with enough precision, fast enough I/O, and, crucially, a language model that was designed for it and matches today’s quality.</p>
<section id="a-different-kind-of-model" class="level3">
<h3 class="anchored" data-anchor-id="a-different-kind-of-model">A different kind of model</h3>
<p>A TSU does not execute a transformer. It samples from an energy function over binary variables <img src="https://latex.codecogs.com/png.latex?s%20%5Cin%20%5C%7B0,%201%5C%7D%5En"> of the form</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AE(s)%20=%20-%5Csum_i%20h_i%5C,%20s_i%20%5C;-%5C;%20%5Csum_%7B(i,j)%20%5Cin%20G%7D%20J_%7Bij%7D%5C,%20s_i%20s_j%20,%0A"></p>
<p>where <img src="https://latex.codecogs.com/png.latex?h_i"> are per-cell biases, <img src="https://latex.codecogs.com/png.latex?J_%7Bij%7D"> are coupling strengths, and <img src="https://latex.codecogs.com/png.latex?G"> is the chip’s (sparse, local) wiring graph. Each cell repeatedly updates itself given its neighbours. The probability of a cell landing on 1 is a sigmoid of its local field:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AP(s_i%20=%201%20%5Cmid%20s_%7B-i%7D)%20=%20%5Csigma%5C!%5Cleft(%5Cfrac%7Bh_i%20+%20%5Csum_%7Bj%7D%20J_%7Bij%7D%20s_j%7D%7BT%7D%5Cright),%20%5Cqquad%20%5Csigma(u)%20=%20%5Cfrac%7B1%7D%7B1%20+%20e%5E%7B-u%7D%7D%20.%0A"></p>
<p>This is exactly the Gibbs sampling loop from the primer, done by physics instead of by arithmetic. Cells that aren’t neighbours update simultaneously, so one <em>sweep</em> over millions of cells takes about as long as updating one.</p>
<p>A language model for this hardware therefore has to express <em>“which tokens come next, given the context”</em> as such an energy function:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ap_%5Ctheta(x%20%5Cmid%20c)%20%5Cpropto%20%5Cexp%5C!%5Cbig(-E_%5Ctheta(x;%5C,%20c)%5C,%20/%5C,%20T%5Cbig),%0A"></p>
<p>where <img src="https://latex.codecogs.com/png.latex?x"> is a binary encoding of the next tokens (a vocabulary of 128k entries needs only <img src="https://latex.codecogs.com/png.latex?%5Clceil%20%5Clog_2%20128%7B,%7D000%20%5Crceil%20=%2017"> bits per token) and <img src="https://latex.codecogs.com/png.latex?c"> is the context. The temperature knob is now literally a temperature, or rather the analog control that plays its role.</p>
<p>Two ingredients make this plausible:</p>
<ul>
<li><strong>Generate blocks, not single tokens.</strong> <em>Diffusion language models</em> already generate text by starting from a fully masked block and iteratively denoising it <span class="citation" data-cites="nie2025llada">(Nie et al. 2025)</span>. Extropic’s denoising thermodynamic models apply the same idea to TSUs, chaining a handful of energy-based models, each of which the chip samples from directly <span class="citation" data-cites="jelincic2026">(<span class="nocase">Jelinčič et al.</span> 2026)</span>. Instead of one token per network pass, a block of <img src="https://latex.codecogs.com/png.latex?k"> tokens emerges after a few denoising steps.</li>
<li><strong>Keep a digital front-end.</strong> Attention over a long context is not something local p-bit wiring is good at. A realistic design keeps a (smaller) digital network that reads the context and turns it into the biases <img src="https://latex.codecogs.com/png.latex?h(c)"> for the TSU. That is the split Extropic’s Z1T models use, with a companion FPGA next to the thermodynamic chip <span class="citation" data-cites="extropic-z1t">(Extropic 2026)</span>.</li>
</ul>
</section>
<section id="the-life-of-the-same-request" class="level3">
<h3 class="anchored" data-anchor-id="the-life-of-the-same-request">The life of the same request</h3>
<div class="cell" data-layout-align="default">
<div class="cell-output-display">
<div>
<p></p><figure class="figure"><p></p>
<div>
<pre class="mermaid mermaid-js">sequenceDiagram
    participant U as Client
    participant C as CPU (API server)
    participant D as Digital accelerator
    participant T as TSU
    U-&gt;&gt;C: prompt (text)
    C-&gt;&gt;C: tokenize, schedule
    C-&gt;&gt;D: token IDs
    D-&gt;&gt;D: encode context (prefill)
    loop for each block of k tokens
        D-&gt;&gt;T: biases h(c), couplings already on chip
        loop denoising steps
            T-&gt;&gt;T: Gibbs sweeps until equilibrium
        end
        T--&gt;&gt;D: k tokens as bits
        D-&gt;&gt;D: extend context
        D--&gt;&gt;C: k token IDs
        C--&gt;&gt;U: detokenized text (streamed)
    end
</pre>
</div>
<p></p><figcaption> The same request on a hypothetical hybrid server: the digital side encodes the context, the TSU samples blocks of tokens.</figcaption> </figure><p></p>
</div>
</div>
</div>
<ol type="1">
<li><strong>Tokenization and scheduling (CPU)</strong> stay exactly the same.</li>
<li><strong>Prefill (digital).</strong> The context still has to be read. This remains compute-bound and fits GPU-style hardware well, and a smaller encoder makes it cheaper than today.</li>
<li><strong>Conditioning (digital → TSU).</strong> Instead of producing logits, the digital side produces the bias vector <img src="https://latex.codecogs.com/png.latex?h(c)">. The couplings <img src="https://latex.codecogs.com/png.latex?J"> are the model’s “weights” and stay resident on the chip. There is no weight streaming per token. <strong>This removes the memory-bandwidth wall from Part 1.</strong></li>
<li><strong>Sampling (TSU).</strong> The chip runs a few denoising steps. In each, it performs Gibbs sweeps until it has equilibrated, and the read-out is a block of <img src="https://latex.codecogs.com/png.latex?k"> tokens. Sampling isn’t the final 1% of the work anymore. It <em>is</em> the work.</li>
<li><strong>Feedback and streaming.</strong> The new tokens extend the context; the digital side updates its state, and the loop continues with the next block.</li>
</ol>
</section>
<section id="a-simple-energy-model" class="level3">
<h3 class="anchored" data-anchor-id="a-simple-energy-model">A simple energy model</h3>
<p>To compare the two worlds, let’s write down the energy per generated token. On the GPU it is dominated by data movement, roughly</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AE_%5Ctext%7BGPU%7D%20%5Capprox%20%5Cfrac%7B2N%20%5Ccdot%20e_%5Ctext%7BHBM%7D%7D%7BB%7D%20+%202N%20%5Ccdot%20e_%5Ctext%7BFLOP%7D%20,%0A"></p>
<p>with <img src="https://latex.codecogs.com/png.latex?e_%5Ctext%7BHBM%7D"> the energy per byte read from memory and <img src="https://latex.codecogs.com/png.latex?e_%5Ctext%7BFLOP%7D"> the energy per operation. On the hybrid system, with <img src="https://latex.codecogs.com/png.latex?n_%5Ctext%7Bsteps%7D"> denoising steps of <img src="https://latex.codecogs.com/png.latex?n_%5Ctext%7Bsweeps%7D"> Gibbs sweeps over <img src="https://latex.codecogs.com/png.latex?M"> p-bits each, and <img src="https://latex.codecogs.com/png.latex?e_%5Ctext%7Bflip%7D"> the energy of one p-bit update:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AE_%5Ctext%7Bhybrid%7D%20%5Capprox%20%5Cunderbrace%7BE_%5Ctext%7Bdigital%7D%20+%20E_%5Ctext%7BI/O%7D%7D_%5Ctext%7Bstill%20conventional%7D%20%5C;+%5C;%20%5Cfrac%7Bn_%5Ctext%7Bsteps%7D%20%5Ccdot%20n_%5Ctext%7Bsweeps%7D%20%5Ccdot%20M%20%5Ccdot%20e_%5Ctext%7Bflip%7D%7D%7Bk%7D%20.%0A"></p>
<p>The TSU term can be tiny: no weights move, <img src="https://latex.codecogs.com/png.latex?e_%5Ctext%7Bflip%7D"> is small, and the cost is shared by <img src="https://latex.codecogs.com/png.latex?k"> tokens. But the first term doesn’t go away. This is Amdahl’s law in energy form. If a fraction <img src="https://latex.codecogs.com/png.latex?%5Cvarphi"> of today’s energy moves to hardware that is <img src="https://latex.codecogs.com/png.latex?s"> times more efficient, the overall gain is</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AG(%5Cvarphi,%20s)%20=%20%5Cfrac%7B1%7D%7B(1%20-%20%5Cvarphi)%20+%20%5Cvarphi%20/%20s%7D%20%5C;%5Cle%5C;%20%5Cfrac%7B1%7D%7B1%20-%20%5Cvarphi%7D%20.%0A"></p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code hidden" id="cb4" data-startfrom="243" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 242;"><span id="cb4-243">{</span>
<span id="cb4-244">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> ss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> d3<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.01</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(e <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> e)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-245">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> phis <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.9</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.99</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.999</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-246">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> phis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">flatMap</span>(phi <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> ss<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(s <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> ({<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">phi</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`φ = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">${</span>phi<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">G</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> ((<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> phi) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> phi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> s)})))<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-247">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> Plot<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>({</span>
<span id="cb4-248">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">width</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">640</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb4-249">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">x</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">type</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"log"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">label</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"TSU efficiency advantage s →"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">grid</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span>}<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb4-250">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">y</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">type</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"log"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">label</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"↑ System-level gain G"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">grid</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span>}<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb4-251">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">color</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">legend</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">scheme</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"viridis"</span>}<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb4-252">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">marks</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> [</span>
<span id="cb4-253">      Plot<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">line</span>(data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">x</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"s"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">y</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"G"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">stroke</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"phi"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">strokeWidth</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.5</span>})<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb4-254">    ]</span>
<span id="cb4-255">  })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-256">}</span></code></pre></div></div>
<div id="fig-amdahl" class="cell-output cell-output-display quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-amdahl-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div id="ojs-cell-4" data-nodetype="expression">

</div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-amdahl-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;3: System-level energy gain G for different fractions φ of the work moved onto a TSU that is s times more efficient. The flat tails are the conventional parts of the system.
</figcaption>
</figure>
</div>
</div>
<p>The plot makes the main point of this post visible: <strong>a 10,000× better sampler buys a 10× better system if 90% of the work moves to it.</strong> This is the gap between the headline numbers and system-level reality that the primer warned about. In Extropic’s own Z1T estimates the companion FPGA, not the thermodynamic chip, consumes over 95% of the energy <span class="citation" data-cites="aiwiki-extropic">(AI Wiki 2026)</span>. A thermodynamic LLM server only pays off if the model is designed so that almost all of the work happens in the sampler, and the digital front-end stays small.</p>
</section>
<section id="what-changes-and-what-doesnt" class="level3">
<h3 class="anchored" data-anchor-id="what-changes-and-what-doesnt">What changes, and what doesn’t</h3>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th></th>
<th>GPU today</th>
<th>Hybrid with TSU (hypothetical)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><strong>Model weights</strong></td>
<td>Streamed from HBM on every decode step</td>
<td>Resident on chip as couplings <img src="https://latex.codecogs.com/png.latex?J"></td>
</tr>
<tr class="even">
<td><strong>Bottleneck</strong></td>
<td>Memory bandwidth (decode)</td>
<td>Mixing time, digital front-end, I/O</td>
</tr>
<tr class="odd">
<td><strong>Unit of generation</strong></td>
<td>1 token per forward pass</td>
<td>Block of <img src="https://latex.codecogs.com/png.latex?k"> tokens per denoising chain</td>
</tr>
<tr class="even">
<td><strong>Randomness</strong></td>
<td>Pseudo-random numbers + softmax</td>
<td>Thermal noise, native</td>
</tr>
<tr class="odd">
<td><strong>Temperature</strong></td>
<td>A scalar in the softmax</td>
<td>A physical control on the chip</td>
</tr>
<tr class="even">
<td><strong>Long context</strong></td>
<td>KV cache in HBM</td>
<td>Still digital, still a KV-cache-like problem</td>
</tr>
<tr class="odd">
<td><strong>Batching</strong></td>
<td>Essential to amortise weight reads</td>
<td>Less critical, no weight reads to amortise</td>
</tr>
</tbody>
</table>
<p>Some things are worth pointing out:</p>
<ul>
<li><strong>The memory wall disappears, and a new one appears.</strong> Instead of bytes per second, the limiting factor becomes how many sweeps the chip needs to reach equilibrium (its <em>mixing time</em>). Hard, multimodal distributions mix slowly, and a model that is cheap per sweep but needs a million sweeps gains nothing.</li>
<li><strong>Batching becomes less important.</strong> Today, batching exists mostly to amortise weight reads. If the weights never move, a single user’s request is not a waste of the hardware, which could make local, low-latency inference much more attractive.</li>
<li><strong>The compiler problem changes.</strong> Instead of tiling matrix multiplications for caches and tensor cores, a toolchain would have to map a sparse energy function onto a fixed physical wiring graph, choose update schedules (which cells may flip simultaneously) and trade sweeps for accuracy. This looks a lot more like place-and-route for FPGAs than like CUDA.</li>
</ul>
</section>
</section>
<section id="wrapping-up" class="level2">
<h2 class="anchored" data-anchor-id="wrapping-up">Wrapping up</h2>
<p>Today, an LLM answers a prompt with a compute-bound prefill followed by a long, memory-bound decode loop, and it only touches randomness in its very last, cheapest step, through a softmax that is secretly a Boltzmann distribution. A thermodynamic processor turns this upside down: the weights stay put as physical couplings, sampling becomes the main event, and tokens can emerge in blocks from a denoising chain rather than one per pass.</p>
<p>Whether that future arrives depends on the problems we generously assumed away. But the exercise shows where the potential really is, and where it isn’t. Replacing the sampler alone does nothing. The gains only come from rebuilding the model around the hardware, and they are capped by whatever stays digital.</p>



</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-aiwiki-extropic" class="csl-entry">
AI Wiki. 2026. <span>“Extropic.”</span> September.
</div>
<div id="ref-extropic-z1t" class="csl-entry">
Extropic. 2026. <span>“Z1T: Sparse Transformer-Like Models for Probabilistic Hardware.”</span> September.
</div>
<div id="ref-horowitz2014energy" class="csl-entry">
Horowitz, Mark. 2014. <span>“Computing’s Energy Problem (and What We Can Do about It).”</span> <em>IEEE International Solid-State Circuits Conference (ISSCC)</em>.
</div>
<div id="ref-jelincic2026" class="csl-entry">
<span class="nocase">Jelinčič et al.</span> 2026. <span>“An Efficient Probabilistic Hardware Architecture for Diffusion-Like Models.”</span> <em>Npj Unconventional Computing</em>.
</div>
<div id="ref-kwon2023vllm" class="csl-entry">
Kwon, Woosuk, Zhuohan Li, Siyuan Zhuang, et al. 2023. <span>“Efficient Memory Management for Large Language Model Serving with PagedAttention.”</span> <em>Proceedings of the 29th Symposium on Operating Systems Principles (SOSP)</em>.
</div>
<div id="ref-leviathan2023speculative" class="csl-entry">
Leviathan, Yaniv, Matan Kalman, and Yossi Matias. 2023. <span>“Fast Inference from Transformers via Speculative Decoding.”</span> <em>Proceedings of the 40th International Conference on Machine Learning (ICML)</em>.
</div>
<div id="ref-nie2025llada" class="csl-entry">
Nie, Shen, Fengqi Zhu, Zebin You, et al. 2025. <span>“Large Language Diffusion Models.”</span> <em>arXiv Preprint arXiv:2502.09992</em>.
</div>
<div id="ref-pope2022scaling" class="csl-entry">
Pope, Reiner, Sholto Douglas, Aakanksha Chowdhery, et al. 2022. <span>“Efficiently Scaling Transformer Inference.”</span> <em>arXiv Preprint arXiv:2211.05102</em>.
</div>
<div id="ref-williams2009roofline" class="csl-entry">
Williams, Samuel, Andrew Waterman, and David Patterson. 2009. <span>“Roofline: An Insightful Visual Performance Model for Multicore Architectures.”</span> <em>Communications of the ACM</em> 52 (4): 65–76.
</div>
</div></section></div> ]]></description>
  <category>hardware</category>
  <category>ai</category>
  <category>thermodynamic-computing</category>
  <category>llm-inference</category>
  <guid>https://loop-unroller.eu/posts/2026-10-10-llm-inference-thermodynamic.html</guid>
  <pubDate>Sat, 10 Oct 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Thermodynamic Processors: A Primer</title>
  <dc:creator>Victor Bieszka</dc:creator>
  <link>https://loop-unroller.eu/posts/2026-10-09-thermodynamic-processors-primer.html</link>
  <description><![CDATA[ 





<p>Thermodynamic processors are chips that compute by letting random physical noise do the work, instead of spending energy to suppress it. They target one specific job that modern AI does constantly: drawing random samples from probability distributions. And they promise to do it with orders of magnitude less energy than a GPU.</p>
<p>Every chip you own is built on a single promise: a transistor is either on or off, and nothing in between ever leaks through. Keeping that promise is expensive. Engineers spend enormous effort holding voltages high enough above the electronic jitter of warm silicon that a 1 never flips to a 0. Then, ironically, a large share of today’s AI workloads takes those perfectly deterministic bits and uses them to simulate randomness.</p>
<p>Thermodynamic computing asks an obvious-sounding question: if the algorithm wants randomness, and the hardware is naturally random, why pay twice? This primer explains what that means, how the chips work, and where the idea stands as of late 2026.</p>
<section id="the-problem-ai-is-hitting-an-energy-wall" class="level2">
<h2 class="anchored" data-anchor-id="the-problem-ai-is-hitting-an-energy-wall">The problem: AI is hitting an energy wall</h2>
<p>Energy, not raw chip speed, is becoming the binding constraint on AI. Moore’s Law has slowed, energy per operation has largely plateaued, and data centers are now limited by how much power and cooling they can get. Building more GPUs scales the bill linearly with the ambition.</p>
<p>There is also a mismatch hiding inside the workload. Generative AI is, at its core, a sampling problem:</p>
<ul>
<li><strong>Training</strong> learns a probability distribution from data (what images, sentences or molecules tend to look like).</li>
<li><strong>Inference</strong> draws samples from that distribution (a new image, the next token, a candidate molecule).</li>
</ul>
<p>A digital chip has no native way to be random. It generates pseudo-random numbers with arithmetic, then pushes them through long chains of multiply-and-add to shape them into the right distribution. Diffusion models make this especially vivid: they start from pure noise and spend dozens to hundreds of network passes gradually turning it into an image.</p>
<p>So the stack looks like this: physics gives us noisy transistors, we spend energy making them perfectly deterministic, and then we spend more energy faking randomness on top. Thermodynamic computing tries to remove both layers of waste.</p>
<div class="cell" data-layout-align="default">
<div class="cell-output-display">
<div>
<p></p><figure class="figure"><p></p>
<div>
<pre class="mermaid mermaid-js">flowchart LR
    N([Thermal noise in silicon])
    subgraph D["Digital"]
        direction LR
        d1["Suppress noise&lt;br/&gt;(energy)"] --&gt; d2[Deterministic bits] --&gt; d3["Fake randomness&lt;br/&gt;with arithmetic (energy)"] --&gt; d4([Sample])
    end
    subgraph T["Thermodynamic"]
        direction LR
        t1[Let noise drive the circuit] --&gt; t2([Sample])
    end
    N --&gt; d1
    N --&gt; t1
</pre>
</div>
<p></p><figcaption> The digital path spends energy twice, once removing noise and again faking it; the thermodynamic path skips both.</figcaption> </figure><p></p>
</div>
</div>
</div>
</section>
<section id="the-core-idea-let-physics-do-the-sampling" class="level2">
<h2 class="anchored" data-anchor-id="the-core-idea-let-physics-do-the-sampling">The core idea: let physics do the sampling</h2>
<p>A physical system sitting in a warm environment already samples from a probability distribution for free. That is the whole trick.</p>
<p>Think of a ball in a hilly landscape that is being constantly shaken. It rolls around at random, but it spends most of its time in the valleys and rarely sits on the peaks. Watch it long enough and the fraction of time it spends at each spot follows a precise rule from 19th-century statistical physics, the Boltzmann distribution:</p>
<p><img src="https://latex.codecogs.com/png.latex?p(x)%20%5Cpropto%20e%5E%7B-E(x)/kT%7D"></p>
<p>Here <img src="https://latex.codecogs.com/png.latex?E(x)"> is the “energy” (the height of the landscape) at state <img src="https://latex.codecogs.com/png.latex?x">, <img src="https://latex.codecogs.com/png.latex?T"> is temperature (how hard the shaking is), and <img src="https://latex.codecogs.com/png.latex?k"> is Boltzmann’s constant. Low-energy states are exponentially more likely.</p>
<p>Now flip it around. If you can design the landscape by setting <img src="https://latex.codecogs.com/png.latex?E(x)"> so that its valleys correspond to the things you want (realistic images, good solutions to an optimization problem), then simply letting the system jiggle and taking snapshots gives you samples from exactly the distribution you care about. No pseudo-random number generator, no long chains of arithmetic.</p>
<p>This maps directly onto a family of machine-learning models called <em>energy-based models</em>, which describe data by an energy function rather than an explicit formula for probabilities. On a GPU these models are notoriously slow to sample from. On thermodynamic hardware, sampling is what the hardware does by default.</p>
</section>
<section id="how-a-thermodynamic-processor-works" class="level2">
<h2 class="anchored" data-anchor-id="how-a-thermodynamic-processor-works">How a thermodynamic processor works</h2>
<p>A thermodynamic processor takes the parameters of a probability distribution as input and returns samples from it as output. That is why Extropic calls its chips Thermodynamic Sampling Units (TSUs) rather than processing units <span class="citation" data-cites="extropic-tsu101">(Extropic 2025)</span>.</p>
<section id="the-building-block-a-probabilistic-bit" class="level3">
<h3 class="anchored" data-anchor-id="the-building-block-a-probabilistic-bit">The building block: a probabilistic bit</h3>
<p>The simplest version starts with a <em>p-bit</em> (probabilistic bit). An ordinary bit is a light switch. A p-bit is a weighted coin that flips itself continuously.</p>
<p>In Extropic’s all-transistor design, a p-bit’s output voltage wanders randomly between high (1) and low (0), driven by the natural thermal noise in its transistors. A single control voltage sets the bias: turn it up and the p-bit spends, say, 80% of its time at 1. Reading the voltage at any moment gives you one random sample. The company reports that one X0 p-bit design settles in roughly 100 nanoseconds, and claims each flip costs far less energy than a single floating-point addition on a conventional chip <span class="citation" data-cites="extropic-tsu101">(Extropic 2025)</span>.</p>
</section>
<section id="from-coins-to-a-computer" class="level3">
<h3 class="anchored" data-anchor-id="from-coins-to-a-computer">From coins to a computer</h3>
<p>One weighted coin is not useful. The power comes from wiring many of them together so that each one’s bias depends on its neighbours. The chip then runs a loop that statisticians call <em>Gibbs sampling</em>:</p>
<ol type="1">
<li><strong>Program the landscape.</strong> Load the model’s parameters onto the chip: a bias for each p-bit and a coupling strength for each wire between neighbours. Together these define the energy function <img src="https://latex.codecogs.com/png.latex?E(x)">.</li>
<li><strong>Each cell listens to its neighbours.</strong> It sums up their current states, weighted by the couplings, plus its own bias.</li>
<li><strong>Each cell flips its weighted coin.</strong> That sum sets the p-bit’s probability of landing on 1, and the noise does the rest.</li>
<li><strong>Repeat in parallel.</strong> Cells that aren’t neighbours update at the same time, so a bigger chip doesn’t make each step slower.</li>
<li><strong>Read out.</strong> After enough rounds, the pattern of 1s and 0s across the chip is a sample from the programmed distribution. Keep running to get more.</li>
</ol>
<p>Two design choices make this efficient. Memory and compute live in the same place, so there is no shuttling of data between a processor and RAM, which is where much of a GPU’s energy goes. And each cell only talks to nearby cells, which keeps wires short and cheap.</p>
</section>
<section id="two-flavours-of-hardware" class="level3">
<h3 class="anchored" data-anchor-id="two-flavours-of-hardware">Two flavours of hardware</h3>
<p>The two best-known startups take different physical routes to the same idea.</p>
<table class="caption-top table">
<colgroup>
<col style="width: 11%">
<col style="width: 41%">
<col style="width: 46%">
</colgroup>
<thead>
<tr class="header">
<th></th>
<th>Extropic</th>
<th>Normal Computing</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><strong>Basic unit</strong></td>
<td>p-bits (discrete 0/1), plus multi-level and Gaussian variants</td>
<td>Continuous “s-units”: analog voltages in resonant circuits</td>
</tr>
<tr class="even">
<td><strong>Physics</strong></td>
<td>Thermal noise in ordinary CMOS transistors</td>
<td>Coupled oscillators settling into thermal equilibrium (Langevin dynamics)</td>
</tr>
<tr class="odd">
<td><strong>Native operation</strong></td>
<td>Sampling from energy-based models (Ising-style)</td>
<td>Gaussian sampling and linear algebra, e.g.&nbsp;matrix inversion</td>
</tr>
<tr class="even">
<td><strong>Flagship chip</strong></td>
<td>Z1: 269,568 p-bits, under 1 W (taped out 2026)</td>
<td>CN101 (taped out June 2025); CN201 and CN301 planned</td>
</tr>
</tbody>
</table>
<p>Normal’s matrix-inversion trick is a good example of how strange and elegant this can be <span class="citation" data-cites="normal-matrix-inversion">(Normal Computing, n.d.)</span>. You encode a matrix <img src="https://latex.codecogs.com/png.latex?A"> into the couplings between a set of oscillators, let the system reach thermal equilibrium, and measure how the voltages fluctuate together. That covariance turns out to be proportional to the inverse of the matrix you put in:</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cmathrm%7BCov%7D(x)%20%5Cpropto%20A%5E%7B-1%7D"></p>
<p>The physics solved the equation; you just watched.</p>
</section>
</section>
<section id="what-its-good-for-and-what-it-isnt" class="level2">
<h2 class="anchored" data-anchor-id="what-its-good-for-and-what-it-isnt">What it’s good for (and what it isn’t)</h2>
<p>Thermodynamic processors are accelerators for probabilistic work, not replacements for CPUs or GPUs. You will never run a web browser on one. The promising targets are:</p>
<ul>
<li><strong>Generative models built for sampling.</strong> Extropic’s Denoising Thermodynamic Model borrows the structure of a diffusion model, but instead of hundreds of small deterministic denoising steps, it chains a handful of energy-based models that the chip samples from directly <span class="citation" data-cites="jelincic2026">(<span class="nocase">Jelinčič et al.</span> 2026)</span>.</li>
<li><strong>Sparse language models.</strong> In September 2026 Extropic published Z1T, a family of sparse, transformer-like models redesigned to fit the chip’s 16-neighbour wiring, with open weights on Hugging Face <span class="citation" data-cites="extropic-z1t">(Extropic 2026b)</span>.</li>
<li><strong>Linear algebra.</strong> Normal Computing’s continuous-variable hardware can invert matrices and solve linear systems by letting oscillators equilibrate. These operations sit underneath much of scientific computing and machine learning.</li>
<li><strong>Bayesian inference and uncertainty.</strong> Any model that wants a distribution of plausible answers rather than one best guess, such as weather forecasting, financial risk or robotics under uncertainty.</li>
<li><strong>Optimisation.</strong> Many hard scheduling and routing problems can be written as “find the lowest valley in an energy landscape”, which is exactly what these systems explore.</li>
</ul>
<p>The realistic picture is heterogeneous: a server where a CPU orchestrates, a GPU does dense matrix maths, and a thermodynamic chip handles the sampling-heavy parts. Both Extropic and Normal describe their chips as cards that sit alongside existing accelerators.</p>
</section>
<section id="whos-building-it-and-where-things-stand" class="level2">
<h2 class="anchored" data-anchor-id="whos-building-it-and-where-things-stand">Who’s building it, and where things stand</h2>
<p>As of October 2026, thermodynamic computing has real silicon but no commercial deployments yet. Two US startups lead, both founded in 2022 by alumni of Google’s quantum and AI research groups.</p>
<p><strong>Extropic</strong> builds all-transistor p-bit chips in standard CMOS. Its Z1 chip packs 269,568 p-bits into a die under 12 mm per side drawing under 1 W, and is due in M.2 sticks, PCIe cards and a planned billion-p-bit cluster with early access in 2027 <span class="citation" data-cites="extropic-z1">(Extropic 2026a)</span>. It publishes open-source software (THRML for simulation, Torx for programming) so developers can build for the hardware before it ships.</p>
<p><strong>Normal Computing</strong> builds continuous-variable analog chips under what it calls the Carnot architecture, targeting up to 1000x energy efficiency on selected AI and scientific workloads. Its 2025 <em>Nature Communications</em> paper demonstrated an eight-cell circuit-board prototype <span class="citation" data-cites="melanson2025">(<span class="nocase">Melanson et al.</span> 2025)</span>; CN101 is its first silicon <span class="citation" data-cites="normal-cn101">(Normal Computing 2025)</span>.</p>
<table class="caption-top table">
<colgroup>
<col style="width: 8%">
<col style="width: 91%">
</colgroup>
<thead>
<tr class="header">
<th>Date</th>
<th>Milestone</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Sep 2026</td>
<td>Extropic releases Z1T sparse transformer-like models with open weights <span class="citation" data-cites="extropic-z1t">(Extropic 2026b)</span></td>
</tr>
<tr class="even">
<td>Aug 2026</td>
<td>Extropic says Z1 has taped out; launches Torx framework and simulator API <span class="citation" data-cites="extropic-z1">(Extropic 2026a)</span></td>
</tr>
<tr class="odd">
<td>Jul 2026</td>
<td>Extropic signs a non-binding letter of intent for up to $75M from the US Commerce Department’s CHIPS R&amp;D office <span class="citation" data-cites="iconnect-loi">(I-Connect007 2026)</span></td>
</tr>
<tr class="even">
<td>Jul 2026</td>
<td>Extropic’s diffusion-like-model paper published in <em>npj Unconventional Computing</em> <span class="citation" data-cites="jelincic2026">(<span class="nocase">Jelinčič et al.</span> 2026)</span></td>
</tr>
<tr class="odd">
<td>Mar 2026</td>
<td>Normal Computing raises $50M led by Samsung Catalyst <span class="citation" data-cites="fortune2026">(Fortune 2026)</span></td>
</tr>
<tr class="even">
<td>Oct 2025</td>
<td>Extropic launches X0 prototype chip, XTR-0 dev platform and THRML library <span class="citation" data-cites="extropic-tsu101">(Extropic 2025)</span></td>
</tr>
<tr class="odd">
<td>Aug 2025</td>
<td>Normal’s CN101 produces its first data in testing</td>
</tr>
<tr class="even">
<td>Jun 2025</td>
<td>Normal tapes out CN101, billed as the first thermodynamic computing chip <span class="citation" data-cites="normal-cn101">(Normal Computing 2025)</span></td>
</tr>
<tr class="odd">
<td>Apr 2025</td>
<td>Normal publishes its stochastic processing unit prototype in <em>Nature Communications</em> <span class="citation" data-cites="melanson2025">(<span class="nocase">Melanson et al.</span> 2025)</span></td>
</tr>
</tbody>
</table>
<p>The idea itself is not new. Boltzmann machines, the neural networks Geoffrey Hinton and colleagues described in 1985, are exactly the kind of model these chips run, and academic groups have built p-bit hardware for years. What changed is the push to make it scalable in mainstream semiconductor processes, and AI’s energy bill gave it a market.</p>
</section>
<section id="caveats-read-the-fine-print-on-10000x" class="level2">
<h2 class="anchored" data-anchor-id="caveats-read-the-fine-print-on-10000x">Caveats: read the fine print on “10,000x”</h2>
<p>The headline efficiency numbers are projections, not measurements of shipping products. Treat them as hypotheses that 2027 hardware will test <span class="citation" data-cites="aiwiki-extropic">(AI Wiki 2026)</span>.</p>
<ul>
<li><strong>The big multipliers come from simulation.</strong> Extropic’s widely quoted ~10,000x figure comes from a hardware model of a Z1-like chip generating low-resolution Fashion-MNIST clothing images, a simple benchmark far from a frontier image or language model. Its Z1T language-model estimates (about 14x to 139x over an Nvidia H100 per token) depend on assumed GPU utilisation and exclude parts of the workload.</li>
<li><strong>The rest of the system still costs energy.</strong> In the Z1T estimates, the companion FPGA, not the thermodynamic chip, consumes over 95% of the energy. Gains on the chip can be swallowed by the conventional hardware around it.</li>
<li><strong>Algorithms have to be rebuilt.</strong> Today’s models were co-designed with GPUs. To use these chips, models must be reshaped into sparse, locally connected, energy-based forms, and Extropic’s own study found its sparse models need roughly ten times more training compute to match a dense GPT-2.</li>
<li><strong>Scaling is unproven.</strong> Small prototypes work; whether useful signals survive at millions of cells, across manufacturing variation and chip-to-chip communication, is the open question both companies are now trying to answer.</li>
<li><strong>Analog is hard.</strong> Continuous-variable designs like Normal’s must cope with component tolerances and calibration drift, which is why the history of analog computing is full of promising prototypes that digital chips overtook.</li>
</ul>
<p>None of this means the idea fails. It means the next 12 to 18 months, when independent benchmarks on real Z1 and CN-series hardware become possible, matter more than any press release.</p>
</section>
<section id="the-takeaway" class="level2">
<h2 class="anchored" data-anchor-id="the-takeaway">The takeaway</h2>
<p>Thermodynamic computing flips the oldest rule in chip design: instead of fighting noise, it uses noise as the engine. Because so much of modern AI is really about drawing samples from probability distributions, hardware that samples natively could do that job with far less energy than a GPU simulating randomness through arithmetic.</p>
<p>The physics is sound and the first chips exist. What remains unproven is whether the advantage survives at scale, on real workloads, inside full systems. If it does, the AI data center of the 2030s may look less like a wall of identical GPUs and more like a mixed rack, where some chips calculate and others simply let physics settle into the answer.</p>
</section>
<section id="sources" class="level2">
<h2 class="anchored" data-anchor-id="sources">Sources</h2>
<div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-aiwiki-extropic" class="csl-entry">
AI Wiki. 2026. <span>“Extropic.”</span> September.
</div>
<div id="ref-aria2026" class="csl-entry">
ARIA. 2026. <span>“Developing a World-First Thermodynamic Computing Chip.”</span> March.
</div>
<div id="ref-extropic-tsu101" class="csl-entry">
Extropic. 2025. <span>“TSU 101: An Entirely New Type of Computing Hardware.”</span> October.
</div>
<div id="ref-extropic-z1" class="csl-entry">
Extropic. 2026a. <span>“From One to One Billion: Torx, Thermalizers, and Z1.”</span> August.
</div>
<div id="ref-extropic-z1t" class="csl-entry">
Extropic. 2026b. <span>“Z1T: Sparse Transformer-Like Models for Probabilistic Hardware.”</span> September.
</div>
<div id="ref-fortune2026" class="csl-entry">
Fortune. 2026. <span>“Normal Computing Raises $50M from Samsung Catalyst.”</span> March.
</div>
<div id="ref-iconnect-loi" class="csl-entry">
I-Connect007. 2026. <span>“Extropic Signs $75M LOI with US Commerce Department.”</span> July.
</div>
<div id="ref-spectrum2025" class="csl-entry">
IEEE Spectrum. 2025. <span>“Thermodynamic Computing Is the Hot New Trend.”</span>
</div>
<div id="ref-jelincic2026" class="csl-entry">
<span class="nocase">Jelinčič et al.</span> 2026. <span>“An Efficient Probabilistic Hardware Architecture for Diffusion-Like Models.”</span> <em>Npj Unconventional Computing</em>.
</div>
<div id="ref-melanson2025" class="csl-entry">
<span class="nocase">Melanson et al.</span> 2025. <span>“Thermodynamic Computing System for AI Applications.”</span> <em>Nature Communications</em>.
</div>
<div id="ref-normal-cn101" class="csl-entry">
Normal Computing. 2025. <span>“Normal Computing Announces Tape-Out of CN101.”</span> June.
</div>
<div id="ref-normal-matrix-inversion" class="csl-entry">
Normal Computing. n.d. <span>“A First Demonstration of Thermodynamic Matrix Inversion.”</span>
</div>
</div>


</section>

 ]]></description>
  <category>hardware</category>
  <category>ai</category>
  <category>thermodynamic-computing</category>
  <category>energy-based-models</category>
  <guid>https://loop-unroller.eu/posts/2026-10-09-thermodynamic-processors-primer.html</guid>
  <pubDate>Fri, 02 Oct 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Two clocks start on 11 September</title>
  <dc:creator>Victor Bieszka</dc:creator>
  <link>https://loop-unroller.eu/posts/2026-07-04-cra-11-september.html</link>
  <description><![CDATA[ 





<p>Most companies I talk to have filed the Cyber Resilience Act under “December 2027 problem”. That is when the essential requirements bite, when CE marking needs a cybersecurity dimension, when products that don’t comply can no longer be placed on the EU market. Plenty of time, goes the reasoning, especially since the harmonised standards aren’t even finished.</p>
<p>The reasoning is wrong on one important point. The first enforceable obligation of the CRA does not arrive in December 2027. It arrives on <strong>11 September 2026</strong>, and unlike almost everything else in the regulation, it comes with no grandfathering.</p>
<section id="what-actually-changes-on-11-september" class="level2">
<h2 class="anchored" data-anchor-id="what-actually-changes-on-11-september">What actually changes on 11 September</h2>
<p>From that date, Article 14 applies: any manufacturer of a product with digital elements sold in the EU must report two kinds of events.</p>
<p>The first is an <strong>actively exploited vulnerability</strong> in one of its products — a vulnerability that someone is actually using against real systems, not merely one that exists. The second is a <strong>severe incident having an impact on the security of the product</strong>, which the regulation defines roughly as anything that compromises the product’s ability to protect data or that enables the introduction or execution of malicious code.</p>
<p>Both trigger the same unforgiving cadence:</p>
<div class="cell" data-layout-align="default">
<div class="cell-output-display">
<div>
<p></p><figure class="figure"><p></p>
<div>
<pre class="mermaid mermaid-js">flowchart TB
    subgraph V["Actively exploited vulnerability"]
        direction LR
        v0([Awareness]) -- "24 h" --&gt; v1[Early warning]
        v1 -- "72 h from awareness" --&gt; v2[Vulnerability notification]
        v2 -- "14 days after a fix or mitigation exists" --&gt; v3[Final report]
    end
    subgraph I["Severe incident"]
        direction LR
        i0([Awareness]) -- "24 h" --&gt; i1[Early warning]
        i1 -- "72 h from awareness" --&gt; i2[Incident notification]
        i2 -- "1 month after the notification" --&gt; i3[Final report]
    end
</pre>
</div>
<p></p></figure><p></p>
</div>
</div>
</div>
<p>Reports go simultaneously to the CSIRT designated as coordinator in your member state — for German manufacturers, the BSI — and to ENISA, through a new <strong>single reporting platform</strong> that ENISA is required to have operational on the same day the obligation starts. Nobody has production experience with that platform, for the simple reason that it doesn’t exist in production yet. On top of the regulator-facing reports, Article 14 also requires you to inform impacted users — and where appropriate, all users — about the vulnerability or incident and what they can do about it.</p>
<p>For orientation, here is where 11 September sits in the overall CRA schedule:</p>
<div class="cell" data-layout-align="default">
<div class="cell-output-display">
<div>
<p></p><figure class="figure"><p></p>
<div>
<pre class="mermaid mermaid-js">timeline
    title CRA application timeline
    10 Dec 2024 : Regulation (EU) 2024/2847 enters into force
    11 Jun 2026 : Rules for notified bodies and conformity assessment apply
    11 Sep 2026 : Article 14 reporting obligations apply
                : ENISA single reporting platform goes live
    11 Dec 2027 : Full application — essential requirements, CE marking, market surveillance
</pre>
</div>
<p></p></figure><p></p>
</div>
</div>
</div>
</section>
<section id="no-grandfathering" class="level2">
<h2 class="anchored" data-anchor-id="no-grandfathering">No grandfathering</h2>
<p>This is the part that catches people. The CRA’s transitional provisions (Article 69) exempt products placed on the market before 11 December 2027 from the essential requirements, unless they are substantially modified. But the same article carves out an explicit derogation: the Article 14 reporting obligations apply to <strong>all in-scope products already on the market</strong>.</p>
<p>Your 2019 firmware counts. The legacy product line you stopped actively developing but still sell counts. The white-labelled device you rebadge and sell under your own name counts — under the CRA, putting your name on it makes you the manufacturer.</p>
<p>If a vulnerability in any of those products starts being exploited in the wild after 11 September, the 24-hour clock starts the moment you become aware of it. Not the moment you confirm it, reproduce it, or have a patch. Aware.</p>
</section>
<section id="why-this-is-harder-than-it-sounds" class="level2">
<h2 class="anchored" data-anchor-id="why-this-is-harder-than-it-sounds">Why this is harder than it sounds</h2>
<p>On paper, this looks like a paperwork exercise: fill in a form within a day. In practice, three things make it genuinely difficult.</p>
<p><strong>The trigger is awareness of exploitation, and exploitation mostly happens in code you didn’t write.</strong> The phrase in Article 14 is a vulnerability “contained in the product”. That includes every third-party library, every open source dependency, every SoC vendor’s SDK baked into your product. Look at the vulnerabilities that have actually been exploited at scale in recent years — Log4Shell, the libwebp zero-day, MOVEit, the xz backdoor attempt — and notice that for most affected vendors, the vulnerable code was somebody else’s. The question you have to answer in hours, not weeks, is: <em>is this exploited component in any product we ship, in an exploitable configuration?</em> If your SBOMs are PDFs generated once at release and filed away, you cannot answer that question. If you have no structured intake for exploitation intelligence — CISA KEV, your national CSIRT’s advisories, researcher reports, customer tickets — you may not even know the clock has started.</p>
<p><strong>“Severe incident” is a judgment call made under time pressure.</strong> Whether an event “negatively affects the ability of the product to protect the availability, authenticity, integrity or confidentiality of data” is the kind of question legal and engineering can debate for a week. You have a day. The only workable answer is to make the classification decision <em>before</em> the incident: written criteria, worked examples for your own product portfolio, and a named person empowered to make the call at 02:00 on a Saturday.</p>
<p><strong>Reporting an unpatched, actively exploited vulnerability to authorities is uncomfortable — by design.</strong> The early warning will often describe a zero-day for which you have no fix yet. Industry raised exactly this concern during the legislative process — that the regime concentrates knowledge of exploitable vulnerabilities across a network of agencies — and the final text does contain safeguards allowing dissemination of a report to be limited on justified cybersecurity grounds. But the tension with coordinated vulnerability disclosure practice is real, and your disclosure policy, your PSIRT playbooks, and your legal review process all need to accommodate a regulator sitting in the loop from hour 24.</p>
<p>And this regime does not exist in isolation. A single event can simultaneously be a CRA product vulnerability report, a NIS2 incident for your own infrastructure, a GDPR personal data breach, and — if your customers are financial entities — the subject of frantic DORA-driven questionnaires from their side. Same facts, different clocks, different recipients, different severity thresholds. If those workflows live in four different teams that have never run an exercise together, September will be educational.</p>
</section>
<section id="the-supply-chain-view" class="level2">
<h2 class="anchored" data-anchor-id="the-supply-chain-view">The supply-chain view</h2>
<p>For people working in supply-chain security specifically, Article 14 is the visible tip of a larger shift: the CRA turns component-level visibility from a best practice into legal infrastructure.</p>
<p>Two provisions matter beyond the reporting duty itself. Article 13 obliges manufacturers to exercise due diligence when integrating third-party components, and — less noticed — to report vulnerabilities they discover <em>in</em> a component back to whoever maintains it, including open source maintainers. Vulnerability information is now legally expected to flow both up and down the chain. Meanwhile, open source projects themselves are largely out of scope unless commercialised, and the new “open-source steward” category (foundations and similar) carries a deliberately lighter regime.</p>
<p>The practical consequence is already observable: obligations propagate contractually. Manufacturers who must report within 24 hours are pushing 24-hour notification clauses onto their component suppliers, who push them onto theirs. If you sell software or hardware that ends up inside somebody else’s product, CRA-shaped clauses are coming to your contracts regardless of whether the regulation names you directly. Expect the same dynamic that DORA triggered in financial services — a wave of supplier questionnaires and register entries — this time for anything with a processor in it.</p>
<p>The honest test of your program is simple to state: when the next Log4Shell lands, how long does it take you to produce a complete, confident list of affected products and versions? If the answer is “a few hours”, Article 14 is a formality. If the answer is “we’d start by emailing product teams”, the regulation has just put a price on that gap — formally up to €15 million or 2.5% of global turnover, practically the chaos of doing archaeology on your own portfolio with a regulator waiting.</p>
</section>
<section id="ten-weeks-concretely" class="level2">
<h2 class="anchored" data-anchor-id="ten-weeks-concretely">Ten weeks, concretely</h2>
<p>Enforcement on day one will presumably focus on the unprepared rather than the imperfect, and the harmonised standards are still in the pipeline (the first of the prEN 40000 series are expected around Q3 2026). But the reporting duty doesn’t depend on any standard. Between now and September, a realistic minimum looks like this:</p>
<ol type="1">
<li><strong>Inventory what’s in scope.</strong> Every product with digital elements you place on the EU market, including legacy and white-labelled lines. This list is shorter to compile than you fear and longer than you expect.</li>
<li><strong>Establish one intake for exploitation awareness.</strong> KEV feeds, CSIRT advisories, researcher contact point, support-ticket escalation — all converging on one queue someone actually watches, weekends included.</li>
<li><strong>Make SBOMs queryable.</strong> Not documents; data. The question “which products contain component X at version Y” must be answerable by a query, not a project.</li>
<li><strong>Pre-write the reports.</strong> Templates for the 24-hour early warning and the 72-hour notification, with the fields the single reporting platform expects. Decide now who drafts, who reviews, who submits.</li>
<li><strong>Define “severe” for your products.</strong> Written classification criteria with worked examples, and a named decision-maker with a deputy.</li>
<li><strong>Run one exercise.</strong> Pick a past incident or a hypothetical exploited dependency and walk the full chain — detection to early warning to user notification — against the real clocks. The first dry run always fails. Better in July than in September.</li>
</ol>
<p>The CRA’s December 2027 requirements will dominate compliance budgets for the next eighteen months. But 11 September is the date on which the regulation stops being a document and starts being a stopwatch — and it measures something no policy can fake: whether you actually know what is in the products you ship.</p>
<hr>
<p><em>Further reading: the <a href="https://digital-strategy.ec.europa.eu/en/policies/cra-summary">official CRA summary</a> and <a href="https://digital-strategy.ec.europa.eu/en/policies/cra-reporting">reporting obligations overview</a> from the European Commission, ENISA’s <a href="https://www.enisa.europa.eu/topics/product-security-and-certification/single-reporting-platform-srp">Single Reporting Platform page</a>, the <a href="https://www.european-cyber-resilience-act.com/Cyber_Resilience_Act_Article_14.html">full text of Article 14</a>, and the <a href="https://www.bsi.bund.de/EN/Themen/Unternehmen-und-Organisationen/Informationen-und-Empfehlungen/Cyber_Resilience_Act/cyber_resilience_act_node.html">BSI’s CRA resources</a> (German).</em></p>


</section>

 ]]></description>
  <category>cra</category>
  <category>regulation</category>
  <category>supply-chain-security</category>
  <category>sbom</category>
  <category>vulnerability-management</category>
  <guid>https://loop-unroller.eu/posts/2026-07-04-cra-11-september.html</guid>
  <pubDate>Sat, 04 Jul 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Embedding Wasmtime in C++</title>
  <dc:creator>Victor Bieszka</dc:creator>
  <link>https://loop-unroller.eu/posts/2023-07-04-wasmtime-cpp.html</link>
  <description><![CDATA[ 





<p>This is a little guide on how to execute WebAssembly inside C++, and vice versa. First, we are going to embed <a href="https://wasmtime.dev/">Wasmtime</a> in C++. This will allow us to call WebAssembly within any C++ project. Wasmtime is a fantastic standalone runtime for WebAssembly that comes equipped with its own compiler, called Cranelift. I might be a bit biased though, as I have contributed to Cranelift/Wasmtime. Nevertheless, give it a try, and if you have any questions, issues, etc., join us on <a href="https://bytecodealliance.zulipchat.com/">Zulip</a>.</p>
<p>Anyway, let’s get back to work. Calling C++ functions from WebAssembly is a little bit more tricky. This will require us to register host functions in Wasmtime. Lastly, if we are interested in passing more complex data to WebAssembly (such as C++ pointers or classes), we can utilize WebAssembly’s <em>externref</em> type.</p>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>The examples were last tested with <strong>Wasmtime 49</strong> and need C++17. The C++ API still changes between releases from time to time, so check the header that ships with your version if something doesn’t compile.</p>
</div>
</div>
<section id="setup" class="level2">
<h2 class="anchored" data-anchor-id="setup">Setup</h2>
<p>The C++ API is a single header, <code>wasmtime.hh</code>, that wraps Wasmtime’s C API. It used to live in a separate <a href="https://github.com/bytecodealliance/wasmtime-cpp">wasmtime-cpp</a> repository, but nowadays it ships with every Wasmtime release. Download the C API archive for your platform from the <a href="https://github.com/bytecodealliance/wasmtime/releases">releases page</a> (e.g.&nbsp;<code>wasmtime-v49.0.2-aarch64-macos-c-api.tar.xz</code>) and unpack it. You get an <code>include/</code> directory with the headers and a <code>lib/</code> directory with the static and shared library.</p>
<p>Compiling our program is then a single command:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode sh code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># macOS</span></span>
<span id="cb1-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">clang</span>++ <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-std</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>c++17 <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-I</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$WASMTIME</span>/include main.cc <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$WASMTIME</span>/lib/libwasmtime.a <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb1-3">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-framework</span> CoreFoundation <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-framework</span> Security <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-o</span> main</span>
<span id="cb1-4"></span>
<span id="cb1-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Linux</span></span>
<span id="cb1-6"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">g++</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-std</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>c++17 <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-I</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$WASMTIME</span>/include main.cc <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$WASMTIME</span>/lib/libwasmtime.a <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb1-7">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-lpthread</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-ldl</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-lm</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-o</span> main</span></code></pre></div></div>
<p>Throughout the examples I load the WebAssembly modules from disk with this little helper:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode cpp code-with-copy"><code class="sourceCode cpp"><span id="cb2-1"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">#include </span><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">&lt;fstream&gt;</span></span>
<span id="cb2-2"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">#include </span><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">&lt;sstream&gt;</span></span>
<span id="cb2-3"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">#include </span><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">&lt;string&gt;</span></span>
<span id="cb2-4"></span>
<span id="cb2-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">std::</span>string readFile<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">const</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">char</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>path<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-6">  <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">std::</span>ifstream file<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>path<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb2-7">  <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">std::</span>stringstream buffer<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-8">  buffer <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> file<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>rdbuf<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb2-9">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> buffer<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>str<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb2-10"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
</section>
<section id="embedding-webassembly" class="level2">
<h2 class="anchored" data-anchor-id="embedding-webassembly">Embedding WebAssembly</h2>
<p>Now, let’s suppose we have a simple WebAssembly module called <em>wasm.wat</em> as follows:</p>
<pre class="wat"><code>(module
  (func (export "execute"))
)</code></pre>
<p>This module contains one empty exported function that is correct, callable and yet does nothing. We now want to call this function from within our C++ project.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode cpp code-with-copy"><code class="sourceCode cpp"><span id="cb4-1"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">#include </span><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">&lt;wasmtime.hh&gt;</span></span>
<span id="cb4-2"></span>
<span id="cb4-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">using</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">namespace</span> wasmtime<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-4"></span>
<span id="cb4-5"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> main<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb4-6">  Engine engine<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-7">  Store store<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>engine<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb4-8"></span>
<span id="cb4-9">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">auto</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">module</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Module<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>compile<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>engine<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> readFile<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wasm.wat"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)).</span>unwrap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb4-10">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">auto</span> instance <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Instance<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>create<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>store<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">module</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{}).</span>unwrap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb4-11">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">auto</span> execute <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">std::</span>get<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>Func<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;(*</span>instance<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>get<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>store<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"execute"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">));</span></span>
<span id="cb4-12">  execute<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>call<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>store<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{}).</span>unwrap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb4-13"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>A quick tour of what is going on here:</p>
<ul>
<li>The <strong><code>Engine</code></strong> holds the global configuration and the compiler. You usually need exactly one per process.</li>
<li>The <strong><code>Store</code></strong> owns all WebAssembly objects: instances, memories, functions. Everything a module does at runtime lives in a store, and it all gets freed when the store goes away.</li>
<li><strong><code>Module::compile</code></strong> takes either the text format (<code>.wat</code>) or a binary (<code>.wasm</code>) and compiles it to native code with Cranelift. A module is stateless and can be instantiated many times.</li>
<li><strong><code>Instance::create</code></strong> instantiates the module in our store. The empty <code>{}</code> is the list of imports, and our module has none.</li>
<li><strong><code>instance.get</code></strong> looks up an export by name. It returns a <code>std::optional&lt;Extern&gt;</code>, where <code>Extern</code> is a <code>std::variant</code> over functions, globals, memories and tables, hence the <code>std::get&lt;Func&gt;</code>.</li>
</ul>
<p>Almost every call returns a <code>Result</code>, which is either the value or an error. <code>unwrap()</code> returns the value or aborts with the error message, which keeps the examples short. In real code you would check the result instead.</p>
<section id="typed-functions" class="level3">
<h3 class="anchored" data-anchor-id="typed-functions">Typed functions</h3>
<p><code>Func::call</code> takes and returns a <code>std::vector&lt;Val&gt;</code>, which is flexible but clumsy. If you know the signature up front, you can ask for a typed version of the function:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode cpp code-with-copy"><code class="sourceCode cpp"><span id="cb5-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">auto</span> run <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">std::</span>get<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>Func<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;(*</span>instance<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>get<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>store<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"run"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">))</span></span>
<span id="cb5-2">               <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>typed<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int32_t</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int32_t</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;(</span>store<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb5-3">               <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>unwrap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb5-4"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int32_t</span> result <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> run<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>call<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>store<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>unwrap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span></code></pre></div></div>
<p><code>typed</code> checks the signature once, when you call it, so a mismatch shows up as an error right there, not as a crash later. Use <code>std::tuple&lt;...&gt;</code> for multiple parameters or results, and <code>std::monostate</code> for none.</p>
</section>
</section>
<section id="call-c-from-webassembly" class="level2">
<h2 class="anchored" data-anchor-id="call-c-from-webassembly">Call C++ from WebAssembly</h2>
<p>WebAssembly modules can’t do anything on their own. They can’t print, open files or read the clock. Everything the outside world offers has to be <em>imported</em>, and the embedder (that’s us) decides what gets passed in. In our case, these imports are plain C++ functions, called <em>host functions</em>.</p>
<p>Here is a module that imports two functions from a module named <code>host</code>, one to print a number and one to print a string:</p>
<pre class="wat"><code>(module
  (import "host" "print_i32" (func $print_i32 (param i32)))
  (import "host" "print_str" (func $print_str (param i32 i32)))

  (memory (export "memory") 1)
  (data (i32.const 0) "Hello from WebAssembly!")

  (func (export "run") (param $x i32) (result i32)
    (call $print_str (i32.const 0) (i32.const 23))
    (call $print_i32 (local.get $x))
    (i32.mul (local.get $x) (i32.const 2))
  )
)</code></pre>
<p>To provide the imports, we use a <code>Linker</code>. It maps <code>(module, name)</code> pairs to definitions, and <code>func_wrap</code> turns any C++ callable into a WebAssembly function. Wasmtime derives the WebAssembly signature from the C++ parameter and return types, so a lambda taking an <code>int32_t</code> becomes a function with signature <code>(param i32)</code>.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode cpp code-with-copy"><code class="sourceCode cpp"><span id="cb7-1"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> main<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb7-2">  Engine engine<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb7-3">  Store store<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>engine<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb7-4">  Linker linker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>engine<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb7-5"></span>
<span id="cb7-6">  linker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>func_wrap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"host"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"print_i32"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[](</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int32_t</span> value<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb7-7">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">std::</span>cout <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wasm says: "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> value <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb7-8">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}).</span>unwrap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb7-9"></span>
<span id="cb7-10">  linker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>func_wrap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"host"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"print_str"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb7-11">                   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[](</span>Caller caller<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int32_t</span> ptr<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int32_t</span> len<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb7-12">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">auto</span> memory <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">std::</span>get<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>Memory<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;(*</span>caller<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>get_export<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"memory"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">));</span></span>
<span id="cb7-13">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">auto</span> data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> memory<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>caller<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb7-14">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">std::</span>cout <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">std::</span>string_view<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span></span>
<span id="cb7-15">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">reinterpret_cast</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">const</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">char</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*&gt;(</span>data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> ptr<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">),</span> len<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb7-16">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}).</span>unwrap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb7-17"></span>
<span id="cb7-18">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">auto</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">module</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Module<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>compile<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>engine<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> readFile<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"host.wat"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)).</span>unwrap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb7-19">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">auto</span> instance <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> linker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>instantiate<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>store<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">module</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>unwrap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb7-20">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">auto</span> run <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">std::</span>get<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>Func<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;(*</span>instance<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>get<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>store<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"run"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">))</span></span>
<span id="cb7-21">                 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>typed<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int32_t</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int32_t</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;(</span>store<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb7-22">                 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>unwrap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb7-23"></span>
<span id="cb7-24">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int32_t</span> result <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> run<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>call<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>store<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>unwrap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb7-25">  <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">std::</span>cout <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"result: "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> result <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb7-26"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>Running it prints:</p>
<pre><code>Hello from WebAssembly!
wasm says: 20
result: 40</code></pre>
<p>Two things are worth pointing out.</p>
<p><strong>Strings don’t cross the boundary.</strong> WebAssembly only knows numbers, so the module passes a pointer and a length into its own linear memory. That’s why <code>print_str</code> takes a <code>Caller</code> as its first parameter. The <code>Caller</code> gives the host function access to the calling instance, so it can look up the exported <code>memory</code> and read the bytes. Note that <code>memory.data()</code> hands out a view into the instance’s memory. Don’t hold on to it across calls back into WebAssembly, since the memory may grow and move.</p>
<p><strong>Instantiate through the linker.</strong> Instead of <code>Instance::create</code> with an explicit import list, we call <code>linker.instantiate</code>, which resolves every import by name. If an import is missing or has the wrong type, you get a readable error at this point instead of a trap later.</p>
</section>
<section id="externref-for-complex-data" class="level2">
<h2 class="anchored" data-anchor-id="externref-for-complex-data">Externref for complex data</h2>
<p>Passing numbers is easy, and passing strings through linear memory is manageable. But what if a host function needs a C++ object, say a database connection or a counter? We can’t copy it into the module’s memory, and handing out a raw pointer as an <code>i32</code> would let the module forge pointers into our address space.</p>
<p>This is what <code>externref</code> is for. It is an opaque reference to a host value. WebAssembly can store it, pass it around and hand it back to the host, but it can’t look inside or fake one.</p>
<p>Here is a module that takes an <code>externref</code> and passes it back to the host twice:</p>
<pre class="wat"><code>(module
  (import "host" "increment" (func $increment (param externref)))

  (func (export "bump_twice") (param $counter externref)
    (call $increment (local.get $counter))
    (call $increment (local.get $counter))
  )
)</code></pre>
<p>On the C++ side, an <code>ExternRef</code> wraps a <code>std::any</code>, so it can hold any copyable C++ value. In this example it holds a pointer to a <code>Counter</code> that lives on our stack:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode cpp code-with-copy"><code class="sourceCode cpp"><span id="cb10-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">struct</span> Counter <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb10-2">  <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">std::</span>string name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-3">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> value <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-4"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">};</span></span>
<span id="cb10-5"></span>
<span id="cb10-6"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> main<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb10-7">  Engine engine<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-8">  Store store<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>engine<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb10-9">  Linker linker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>engine<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb10-10"></span>
<span id="cb10-11">  linker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>func_wrap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"host"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"increment"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb10-12">                   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[](</span>Caller caller<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">std::</span>optional<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>ExternRef<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> ref<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb10-13">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(!</span>ref<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb10-14">      <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-15">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb10-16">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">auto</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>counter <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">std::</span>any_cast<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>Counter <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*&gt;(</span>ref<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span>data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>caller<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">));</span></span>
<span id="cb10-17">    counter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span>value<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">++;</span></span>
<span id="cb10-18">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}).</span>unwrap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb10-19"></span>
<span id="cb10-20">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">auto</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">module</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Module<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>compile<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>engine<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> readFile<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"externref.wat"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)).</span>unwrap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb10-21">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">auto</span> instance <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> linker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>instantiate<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>store<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">module</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>unwrap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb10-22">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">auto</span> bump <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">std::</span>get<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>Func<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;(*</span>instance<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>get<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>store<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bump_twice"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">))</span></span>
<span id="cb10-23">                  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>typed<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">std::</span>optional<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>ExternRef<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;,</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">std::</span>monostate<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;(</span>store<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb10-24">                  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>unwrap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb10-25"></span>
<span id="cb10-26">  Counter counter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"requests"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">};</span></span>
<span id="cb10-27">  ExternRef ref<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>store<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span>counter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb10-28">  bump<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>call<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>store<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> ref<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>unwrap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb10-29"></span>
<span id="cb10-30">  <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">std::</span>cout <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> counter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>name <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" = "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> counter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>value <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// requests = 2</span></span>
<span id="cb10-31"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>A few details:</p>
<ul>
<li>An <code>externref</code> can be null, so on the C++ side it shows up as <code>std::optional&lt;ExternRef&gt;</code>. Always handle the empty case, because the module is free to pass <code>ref.null extern</code>.</li>
<li><code>ExternRef</code> values are garbage-collected by the store. Creating one needs the store, and so does reading it back with <code>data()</code>. Inside a host function, the <code>Caller</code> stands in for the store.</li>
<li>The reference holds whatever you put into the <code>std::any</code>, here a raw pointer. Wasmtime keeps the <code>std::any</code> alive, but not the object the pointer points to. If the module might keep the reference around (e.g.&nbsp;in a global or a table), make sure the object outlives it, or store a <code>std::shared_ptr</code> instead.</li>
</ul>
</section>
<section id="wrapping-up" class="level2">
<h2 class="anchored" data-anchor-id="wrapping-up">Wrapping up</h2>
<p>That covers the three building blocks of embedding Wasmtime in C++:</p>
<ol type="1">
<li><strong>Compile and instantiate</strong> a module, then call its exports, ideally through typed functions.</li>
<li><strong>Provide host functions</strong> with a <code>Linker</code>, and use the <code>Caller</code> to reach into the instance’s memory.</li>
<li><strong>Pass C++ objects</strong> into WebAssembly safely as opaque <code>externref</code>s.</li>
</ol>
<p>From here, the natural next steps are <a href="https://wasi.dev/">WASI</a>, which gives modules a standard interface to files, clocks and the environment, and the <a href="https://component-model.bytecodealliance.org/">component model</a>, which replaces the pointer-and-length dance with real strings, records and lists. Both are covered in the <a href="https://docs.wasmtime.dev/">Wasmtime documentation</a>.</p>


</section>

 ]]></description>
  <category>webassembly</category>
  <category>wasmtime</category>
  <category>cpp</category>
  <guid>https://loop-unroller.eu/posts/2023-07-04-wasmtime-cpp.html</guid>
  <pubDate>Tue, 04 Jul 2023 00:00:00 GMT</pubDate>
</item>
</channel>
</rss>
