<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jeff Geiser</title>
    <description>The latest articles on DEV Community by Jeff Geiser (@jeff_geiser).</description>
    <link>https://dev.to/jeff_geiser</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3714979%2Fcdad1fab-9f27-43bb-b5f0-951a5f8ec8f1.png</url>
      <title>DEV Community: Jeff Geiser</title>
      <link>https://dev.to/jeff_geiser</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jeff_geiser"/>
    <language>en</language>
    <item>
      <title>Q8_0 isn't slow because of swap</title>
      <dc:creator>Jeff Geiser</dc:creator>
      <pubDate>Tue, 19 May 2026 13:33:47 +0000</pubDate>
      <link>https://dev.to/jeff_geiser/q80-isnt-slow-because-of-swap-287p</link>
      <guid>https://dev.to/jeff_geiser/q80-isnt-slow-because-of-swap-287p</guid>
      <description>&lt;p&gt;&lt;em&gt;A complete quantization benchmark for Llama 3.1 8B on Apple M4 16GB — speed and perplexity&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I’ve been building an account intelligence model — a fine-tuned system that pulls from Salesforce, Confluence, Slack and some internal systems and grabs everything worth knowing about a customer account into structured JSON. The kind of thing that normally takes some time to generate - and can’t be generated from within any one of those - but takes time. Hoping to make this more efficient. Very isolated use case, but is interesting. I think these highly specialized local models will likely dominate enterprise architectures.. I think..&lt;/p&gt;

&lt;p&gt;Part of that project is deciding which local models are viable in production — specifically, which quantization level makes sense for the 7B distilled model I’m eventually releasing.. I decided to use a basic mac mini as the reference architecture.&lt;/p&gt;

&lt;p&gt;I built an automated benchmark harness, ran Llama 3.1 8B through all 11 quantization levels on an Apple M4 Mac Mini with 16GB unified memory, and measured three things per quant: token generation speed, perplexity on Wikitext-2, and swap behavior.&lt;/p&gt;

&lt;p&gt;I expected a smooth quality/speed tradeoff curve. I got a cliff, a plateau, and a finding I had to re-run twice to believe - thought it was an error..&lt;/p&gt;

&lt;p&gt;Q8_0 — the highest-quality quantization I tested — produced 0.13 tokens per second.&lt;/p&gt;

&lt;p&gt;Not because it was swapping. The re-run shows swap_any: false. No swap at all. The model fits cleanly in 16GB unified memory. It just doesn't run fast.&lt;/p&gt;

&lt;p&gt;The explanation: 8.5GB of 8-bit weights saturates the M4's unified memory bandwidth during inference. The GPU shows 80% utilization — not because it's computing, but because it's moving weights from memory to compute units. At 8-bit precision, the weight transfer bottleneck dominates everything else. There's no swap to blame. The constraint is the memory bus.&lt;/p&gt;

&lt;p&gt;This is an architectural property of the hardware, not a configuration problem. You can't fix it by closing other apps or adding more swap. Q8_0 on a 16GB M4 is slow by design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What swaps and what doesn’t&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Five of eleven quants hit disk during the benchmark. The clean ones — no swap, usable speed:&lt;/p&gt;

&lt;p&gt;IQ3_XS — 3.5 GB — 13.0 tok/s&lt;br&gt;
Q3_K_M — 4.0 GB — 10.1 tok/s&lt;br&gt;
Q4_K_M — 4.9 GB — 19.7 tok/s ← sweet spot&lt;br&gt;
Q6_K — 6.6 GB — 16.3 tok/s ← quality ceiling&lt;/p&gt;

&lt;p&gt;Everything above Q6_K either swaps or hits the bandwidth wall. The jump from Q6_K to Q8_0 (6.6 GB → 8.5 GB) doesn’t just add size — it crosses the threshold where the memory bus can’t keep up.&lt;/p&gt;

&lt;p&gt;One weird thing worth calling out: Q5_K_S hit 6.96 tok/s per watt — the best efficiency number in the entire set. But it’s swapping. Low GPU power (2.4W average) plus active swap means the work is happening on CPU and memory bandwidth, not GPU. A misleading number if you only look at efficiency without checking swap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now add perplexity&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Speed tells you how fast the model runs. Perplexity tells you how much quality you’ve traded away to get there. Lower perplexity = better quality. Q8_0 is the baseline.&lt;/p&gt;

&lt;p&gt;Q2_K — PPL 11.15 — +29% worse than Q8_0&lt;br&gt;
Q3_K_M — PPL 9.21 — +6.4% worse&lt;br&gt;
Q4_K_M — PPL 8.80 — +1.7% worse&lt;br&gt;
Q5_K_M — PPL 8.73 — +0.9% worse&lt;br&gt;
Q6_K — PPL 8.68 — +0.4% worse&lt;br&gt;
Q8_0 — PPL 8.66 — baseline&lt;/p&gt;

&lt;p&gt;The quality cliff is at Q3, not Q4. Q4_K_M to Q8_0 is essentially flat — a 1.7% perplexity difference you would not notice on any real task. Q3_K_M jumps to +6.4%, which is detectable. Q2_K at +29% is a last resort.&lt;/p&gt;

&lt;p&gt;The practical decision range is Q4_K_M to Q6_K. Everything in that band delivers 98–100% of Q8_0 quality at usable speed with no swap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q4_K_M gives you 98.3% of Q8_0 quality at 152× the speed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The account intelligence model I'm building runs on two very different pieces of hardware depending on what it's doing.&lt;/p&gt;

&lt;p&gt;The fine-tuning and eval work runs on a DGX Spark — Qwen2.5-32B in FP8, 64GB VRAM. That's not the model I'm releasing.&lt;/p&gt;

&lt;p&gt;The distilled 7B model — the one anyone can run locally — needs to work on a Mac Mini, a single-GPU workstation, a team server. For that audience, shipping Q8_0 would be a mistake. Someone tries it on 16GB, gets 0.13 tok/s, and concludes the model is broken. That's a distribution failure I can prevent by choosing the right quantization before release.&lt;/p&gt;

&lt;p&gt;Target: Q4_K_M GGUF. Fits in 16GB with room to spare. 19+ tok/s. 1.7% quality loss. No surprises at deployment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What’s next&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This benchmark covers one model on one hardware configuration. The next round is Qwen3.6 — a 27B dense model — on the same M4 setup. The questions are different: at 27B, the “safe” quant range on 16GB is much narrower. And the Qwen3 family has a thinking-mode variable (enable_thinking=false reliability) that adds a dimension Llama doesn’t have.&lt;/p&gt;

&lt;p&gt;I’ll also (maybe) run the same harness on the DGX Spark for a direct comparison: what does a Mac Mini get you vs enterprise inference hardware on the same model family? Would be nice but it’s a shared machine so I need to be careful with the workloads.. might just spin up a vps/bmc..&lt;/p&gt;

&lt;p&gt;Next post: the synthetic data generator for the account intelligence model — what broke in the first smoke test (62 schema validation errors on run 1), how the retry loop works, and what we learned from building 8 gold examples by hand from real customer data.&lt;/p&gt;

&lt;p&gt;Had claude pump out some graphs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy565mndd7qax3ctyfxwu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy565mndd7qax3ctyfxwu.png" alt="speed and perplexity graphs" width="800" height="1536"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>machinelearning</category>
      <category>performance</category>
    </item>
    <item>
      <title>Local LLMs in Production: Squeezing Qwen to Match Claude</title>
      <dc:creator>Jeff Geiser</dc:creator>
      <pubDate>Tue, 19 May 2026 13:29:38 +0000</pubDate>
      <link>https://dev.to/jeff_geiser/local-llms-in-production-squeezing-qwen-to-match-claude-9h2</link>
      <guid>https://dev.to/jeff_geiser/local-llms-in-production-squeezing-qwen-to-match-claude-9h2</guid>
      <description>&lt;p&gt;Lessons from the DGX Spark: Speed, VRAM, and the "Thinking" Problem&lt;/p&gt;

&lt;p&gt;We have a DGX Spark at the office everyone fights over.. dying to play with it.. had a simple goal: build an internal automation agent that peers into Salesforce, Confluence, and our internal APIs to generate workflows, pricing quotes, etc. Keep sensitive data local and, frankly, kill the API costs as much as possible.&lt;/p&gt;

&lt;p&gt;But as you know, “running it locally” is not straightforward.. many times I wanted to just throw the key in .env and be done with it. Here’s what we learned from the trenches of model selection, VRAM management, and prompt tuning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The “Thinking” Tax: Why We Pivoted from Qwen 3.6&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first instinct was to grab the newest shiny object: Qwen3.6-27B. It’s a beast on paper, but we ran into an immediate “personality” issue. The model has a heavy “scratchpad” style—it wants to think out loud before it gives you the answer.&lt;/p&gt;

&lt;p&gt;For our use case—generating clean JSON for an internal UI—this was a disaster. It burned tokens and time on analysis we didn’t ask for. We tried enable_thinking=false, but it wasn’t consistent. We moved to Qwen3-30B-A3B and hit the same wall.&lt;/p&gt;

&lt;p&gt;So! if you just need a model to follow tool calls and return a schema, “thinking” models can actually be a hindrance. You don’t need a philosopher; you need a clerk.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Sweet Spot: Qwen2.5-32B-Instruct-fp8&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We eventually landed on Qwen2.5-32B-Instruct-fp8.&lt;/p&gt;

&lt;p&gt;TThe FP8 quantization allowed it to sit comfortably in the Spark’s VRAM, even with our embedding model (BGE-M3) running alongside it.&lt;/p&gt;

&lt;p&gt;In head-to-head evals against Claude 3.5 Sonnet, the latency difference was a little surprising.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Benchmarks (22 Paired Evals)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Metric.    Qwen2.5-32B (Local)      Claude 3.5 Sonnet (Cloud)&lt;br&gt;
TTFT       1–2s                     9–35s&lt;br&gt;
Response   Concise                  2.3x longer&lt;/p&gt;

&lt;p&gt;Claude is impressive—it adds citations and caveats that Qwen just doesn’t match—but for routine synthesis, 35 seconds for a first token is a non-starter for a snappy UI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Closing the Quality Gap: The “Schema-First” Strategy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Qwen was fast, but it was “hallucination-prone”—dropping schema fields and making up URLs. To fix this, we stopped treating it like a chatbot and started treating it like a compiler.&lt;/p&gt;

&lt;p&gt;Our Optimization Stack:&lt;/p&gt;

&lt;p&gt;Temperature 0.1: Kill the creativity.&lt;/p&gt;

&lt;p&gt;Schema-First Prompting: We moved the JSON structure to the very top of the prompt. We tell it how to output before we tell it what to do.&lt;/p&gt;

&lt;p&gt;Hard Constraints: We added rules like empty section = [] and a strict Never fabricate command.&lt;/p&gt;

&lt;p&gt;Zero Persona: We stripped all “You are a helpful assistant” fluff. It just gets in the way of the logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Hardware Squeeze&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One thing to watch if you’re running on a Spark: VRAM is a zero-sum game, obviously. Adding BGE-M3 for semantic search and multilingual support was non-negotiable for our data, but it made the memory overhead incredibly tight.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What’s Next?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We’re going to run a full eval on these changes to see if the prompt tuning is enough. If not, the next step is building a middleware layer to catch malformed JSON and trigger second calls. I’m also looking at putting Llama 3 through its paces to see if the tool-calling is more robust.&lt;/p&gt;

&lt;p&gt;The Bottom Line: We’re closing the gap. We’ll use the local Qwen for the 90% “routine” synthesis and save the Claude API calls for the truly hard reasoning tasks.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>llm</category>
      <category>performance</category>
    </item>
    <item>
      <title>WES: Why Tokens Per Watt Isn't Enough for Edge Inference</title>
      <dc:creator>Jeff Geiser</dc:creator>
      <pubDate>Wed, 11 Mar 2026 16:33:17 +0000</pubDate>
      <link>https://dev.to/jeff_geiser/wes-why-tokens-per-watt-isnt-enough-for-edge-inference-fl3</link>
      <guid>https://dev.to/jeff_geiser/wes-why-tokens-per-watt-isnt-enough-for-edge-inference-fl3</guid>
      <description>&lt;p&gt;Edge inference is still nascent.&lt;/p&gt;

&lt;p&gt;I work at Zenlayer helping companies deploy compute in hard to reach places. Spin up a VM with Ollama, pull a model, running inference in minutes. The infrastructure is there. The tooling is maturing. But the metrics for understanding what's actually happening on those nodes is still catching up.&lt;/p&gt;

&lt;p&gt;I've also been building Wicklee in my weekend time — a sovereign GPU fleet monitor written in Rust with an embedded React dashboard. Running a mixed fleet of Apple Silicon and AMD CPU nodes, I kept running into the same problem: the standard metrics weren't telling me quite enough.. &lt;/p&gt;

&lt;p&gt;Everyone in AI talks about efficiency at the data center level. Jensen talks tokens per watt. Google reports Gemini in watt-hours. Microsoft targets 8-20x energy reductions per query. Great work — but these are hyperscaler metrics, built for environments with precision cooling, facilities teams, and controlled everything.&lt;/p&gt;

&lt;p&gt;That's not edge inference.&lt;/p&gt;

&lt;p&gt;Here's a scenario that'll be familiar if you're running a distributed fleet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tok/s drops slightly&lt;/li&gt;
&lt;li&gt;board power creeps up slightly&lt;/li&gt;
&lt;li&gt;thermal state moves from Normal to Fair&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You do get a drop in tokens/watt. But now what? Is it a blip? Is it meaningful? What do you chase?&lt;/p&gt;

&lt;p&gt;Honest answer: hard to tell. Tokens/watt can't distinguish a legitimate workload increase from thermal throttling. They look identical in the number. One means the node is doing its job. The other means it's quietly degrading and inserting some wait sates to prevent reaching a critical state. They require completely different responses.&lt;/p&gt;

&lt;p&gt;And in practice, a 15% drift on one node in a six-node fleet at 2am looks like noise. You don't chase it. The node keeps running. Keeps burning power. Keeps delivering worse inference. Until something obvious breaks.&lt;/p&gt;

&lt;p&gt;The data was there. Nothing put it in front of you.&lt;/p&gt;

&lt;p&gt;In other cases, the token/watt metric can stand still even if token/s is dropping if power output is also dropping. So, efficiency looks stable but throughput is actually dropping.&lt;/p&gt;

&lt;p&gt;So I wanted to add thermal state to the equation.&lt;/p&gt;

&lt;p&gt;WES — the Wicklee Efficiency Score:&lt;br&gt;
WES = tok/s ÷ (Watts_adjusted × ThermalPenalty)&lt;/p&gt;

&lt;p&gt;The ThermalPenalty comes directly from what the device reports — on Apple Silicon that's IOPMCopyCPUPowerStatus via IOKit, on NVIDIA it's the nvmlDeviceGetCurrentClocksThrottleReasons() bitmask. Not temperature guesses. Not externally imposed thresholds. The hardware's own classification of its thermal condition, amplified into the score.&lt;/p&gt;

&lt;p&gt;Thermal StatePenaltyNormal1.0Fair1.25Serious1.75Critical2.0+&lt;/p&gt;

&lt;p&gt;When thermals are clean, penalty is 1.0 and WES equals tokens/watt. When throttling starts, the penalty amplifies the drop — turning a subtle drift you'd dismiss as noise into something that screams at you.&lt;/p&gt;

&lt;p&gt;Higher WES = better. Miles per gallon for inference.&lt;/p&gt;

&lt;p&gt;Why the leaderboard is the real insight&lt;/p&gt;

&lt;p&gt;WES on a single node is useful. The Wicklee fleet leaderboard is where it gets interesting.&lt;/p&gt;

&lt;p&gt;Stack rank every node by WES. A thermally degraded node doesn't just show a number that drifted. It falls in the ranking. Drops below nodes it was beating yesterday. That positional change is impossible to miss — you don't need to be actively monitoring anything, you just notice your #1 node is now #3.&lt;/p&gt;

&lt;p&gt;That's the moment tok/watt never creates.&lt;/p&gt;

&lt;p&gt;WES surfaces the signal. The thermal panel explains the cause. Route requests to the top of the leaderboard and you're automatically routing away from degraded nodes without lifting a finger.&lt;/p&gt;

&lt;p&gt;Real numbers from my fleet&lt;br&gt;
Running llama3.2:3b via Ollama across hardware:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmjo5rwi6dhfl9ena5pcz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmjo5rwi6dhfl9ena5pcz.png" alt=" " width="678" height="246"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;tok/s makes this look like a 6x gap. WES shows a 1,293x efficiency difference. The Ryzen is fast. It is not efficient.&lt;/p&gt;

&lt;p&gt;Now throw the M2 into thermal throttling — WES drops from 181.5 to 83.6. Still #1 on the leaderboard. But the drop is visible. The thermal panel tells you why. WES made you notice. Thermal data gave you the diagnosis. They work together.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Raw WES vs Penalized WES&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
Wicklee reports WES two ways:&lt;br&gt;
Raw WES — ThermalPenalty forced to 1.0. Hardware ceiling under clean conditions. Essentially tok/watt.&lt;/p&gt;

&lt;p&gt;Penalized WES — live thermal penalty applied. Operational reality.&lt;br&gt;
The gap is your Thermal Cost — efficiency being lost to throttling right now:&lt;/p&gt;

&lt;p&gt;Thermal Cost % = (Raw WES − Penalized WES) / Raw WES × 100&lt;/p&gt;

&lt;p&gt;A node with Raw WES 181.5 and Penalized WES 83.6 is losing 54% of its potential efficiency to thermals. That's the number that drives action — not a raw temperature reading, not a wattage blip.&lt;/p&gt;

&lt;p&gt;Here's the implementation if you want to compute it yourself:&lt;/p&gt;

&lt;p&gt;javascriptconst THERMAL_PENALTIES = { Normal: 1.0, Fair: 1.25, Serious: 1.75, Critical: 2.0 };&lt;/p&gt;

&lt;p&gt;function computeWESPair(tps, watts, thermalState, pue = 1.0) {&lt;br&gt;
  if (tps == null) return { raw: null, penalized: null, thermalCostPct: null };&lt;br&gt;
  const penalty = THERMAL_PENALTIES[thermalState] ?? 1.0;&lt;br&gt;
  const w = watts * pue;&lt;br&gt;
  if (w &amp;lt;= 0) return null;&lt;br&gt;
  const raw = Math.round((tps / w) * 10) / 10;&lt;br&gt;
  const penalized = Math.round((tps / (w * penalty)) * 10) / 10;&lt;br&gt;
  const thermalCostPct = Math.round((1 - penalized / raw) * 100);&lt;br&gt;
  return { raw, penalized, thermalCostPct };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;// Clean node:&lt;br&gt;
computeWESPair(108.9, 0.6, "Normal");  // → { raw: 181.5, penalized: 181.5, thermalCostPct: 0 }&lt;/p&gt;

&lt;p&gt;// Throttled node:&lt;br&gt;
computeWESPair(94.1, 0.9, "Fair");     // → { raw: 104.6, penalized: 83.6, thermalCostPct: 20 }&lt;br&gt;
And in Rust for the monitoring agent side:&lt;br&gt;
rustpub struct WESResult {&lt;br&gt;
    pub raw: Option,&lt;br&gt;
    pub penalized: Option,&lt;br&gt;
    pub thermal_cost_pct: Option,&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;pub fn compute_wes_pair(&lt;br&gt;
    tps: Option, watts: f64, thermal_penalty: f64, pue: f64&lt;br&gt;
) -&amp;gt; WESResult {&lt;br&gt;
    let compute = |p: f64| tps.and_then(|t| {&lt;br&gt;
        let w = watts * pue;&lt;br&gt;
        if w &amp;lt;= 0.0 { return None; }&lt;br&gt;
        Some((t / (w * p) * 10.0).round() / 10.0)&lt;br&gt;
    });&lt;br&gt;
    let raw = compute(1.0);&lt;br&gt;
    let penalized = compute(thermal_penalty);&lt;br&gt;
    let thermal_cost_pct = raw.zip(penalized)&lt;br&gt;
        .map(|(r, p)| ((1.0 - p / r) * 100.0).round());&lt;br&gt;
    WESResult { raw, penalized, thermal_cost_pct }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;WES is derived — compute it at render time from fields you're already collecting. No telemetry layer changes required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How WES relates to existing work&lt;/strong&gt;&lt;br&gt;
Stanford and Together AI published "Intelligence per Watt" (IPW) last year — accuracy divided by power, measured offline against benchmarks. Solid research. It answers "what is this hardware capable of per watt?"&lt;/p&gt;

&lt;p&gt;WES answers "what is it delivering right now?"&lt;/p&gt;

&lt;p&gt;Raw WES and IPW are the same question from different vantage points — IPW from a benchmark lab, WES from live fleet telemetry. IPW tells you the ceiling. WES tells you how close you're running to it, under real thermal conditions, continuously.&lt;/p&gt;

&lt;p&gt;**What's coming in Wicklee&lt;br&gt;
**The Fleet WES Leaderboard is shipping soon — every node ranked by Penalized WES, Raw WES as a secondary column, Thermal Cost % visible at a glance.&lt;/p&gt;

&lt;p&gt;After that, a series of benchmark posts:&lt;/p&gt;

&lt;p&gt;Cross-platform WES benchmarks — Apple Silicon vs AMD CPU vs NVIDIA GPU, same model, same prompt. Raw WES per platform.&lt;br&gt;
Thermal stress testing — deliberately inducing throttling and watching Raw vs Penalized WES diverge in real time.&lt;br&gt;
Sustained load degradation — how long before each platform throttles, how fast does WES collapse when it does.&lt;br&gt;
Edge enclosure testing — WES in a fanless case vs open air. Spoiler: not pretty.&lt;/p&gt;

&lt;p&gt;Goal: a reproducible WES dataset across hardware. Not just a formula — empirical data behind it.&lt;br&gt;
If you're running a local inference fleet, try computing your WES from the formula above and drop your numbers in the comments. Curious where different hardware lands.&lt;br&gt;
Miles per gallon for inference. When you need a race car, gas be damned — go for it. But at the edge, efficiency wins.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>monitoring</category>
      <category>performance</category>
    </item>
    <item>
      <title>Distributed Inference Observability gaps</title>
      <dc:creator>Jeff Geiser</dc:creator>
      <pubDate>Fri, 16 Jan 2026 19:10:12 +0000</pubDate>
      <link>https://dev.to/jeff_geiser/distributed-inference-observability-gaps-3pn3</link>
      <guid>https://dev.to/jeff_geiser/distributed-inference-observability-gaps-3pn3</guid>
      <description>&lt;p&gt;It seems that distributed inference observability has some gaps.&lt;/p&gt;

&lt;p&gt;In terms of framing this, I am referring to inference deployments at the edge (or so called near edge).. pops close to end users. Let's say you are using ollama for some early testing and/or scaling but are using vllm in production. &lt;/p&gt;

&lt;p&gt;Traditional monitoring platforms will report on GPU/CPU load, memory usage, network status, etc, etc.&lt;/p&gt;

&lt;p&gt;However, other stuff is also happening:&lt;/p&gt;

&lt;p&gt;GPU throttled - 100% utilization but clock speed dropped 33%&lt;br&gt;
KV cache saturated causing some queue backlog&lt;br&gt;
Time to first token spiked 200% from CPU contention&lt;br&gt;
Another tenant's PCIe traffic impacted inference&lt;/p&gt;

&lt;p&gt;maybe some contextual drift - some hardware stresses that degrade inference performance but it is happening in ways that is generally invisible to system metrics.&lt;/p&gt;

&lt;p&gt;Most of the monitoring in the market is built for servers and takes a peek at intervals that may not make sense for inference&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;token generation:20-100 per second&lt;/li&gt;
&lt;li&gt;cache saturation: spikes in seconds&lt;/li&gt;
&lt;li&gt;thermal throttling happens instantly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;but traditional monitoring might see this as smooth if only glancing at the server every 30 seconds. But, you also can't grab data every 2 seconds or you might contribute to some cpu scheduling pressure. &lt;/p&gt;

&lt;p&gt;So, if you are going to run both ollama (for dev/test or smaller loads) and vLLM for production they have completely different failure modes but traditional monitoring would treat them the same.&lt;/p&gt;

&lt;p&gt;We also have a blind spot with regard to time to first token (ttft) and time per output token (tpot). We might show request latency spiking, but we need to know whether ttft spiked or tpot spiked.. &lt;/p&gt;

&lt;p&gt;so, I am thinking about an open source project that would be a lightweight observability agent.. large companies will likely solve this by building a giant observability layer on top of their distributed inference solution -- but I think having a more bottoms up approach that can be deployed might make sense..&lt;/p&gt;

&lt;p&gt;the observability agent would strive to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;have limited cpu impact/overhead&lt;/li&gt;
&lt;li&gt;2 second sampling with some intelligent backoff&lt;/li&gt;
&lt;li&gt;built in ttft/tpot splitting&lt;/li&gt;
&lt;li&gt;contextual drift detection&lt;/li&gt;
&lt;li&gt;works with vLLM/Prometheus and Ollama API stats&lt;/li&gt;
&lt;li&gt;embedded DB storage (duckDB?) - no external dependencies&lt;/li&gt;
&lt;li&gt;runs at edge.. maybe federates.. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Curious to get feedback on where people are hitting observability gaps.. this is a new area for me to spend time on so curious about all feedback.&lt;/p&gt;

&lt;p&gt;What are you doing to monitor vLLM and/or other inference engines?&lt;/p&gt;

&lt;p&gt;What metrics do you wish you had?&lt;/p&gt;

&lt;p&gt;Drop the war stories here.. thanks.. &lt;/p&gt;

&lt;p&gt;(apologies for lack of formatting.. maybe I will get better over time..)&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>monitoring</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
