<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://dtype.org/index.php?action=history&amp;feed=atom&amp;title=Perf%2Fwatt_benchmarks_in_a_k8s_home_cluster</id>
	<title>Perf/watt benchmarks in a k8s home cluster - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://dtype.org/index.php?action=history&amp;feed=atom&amp;title=Perf%2Fwatt_benchmarks_in_a_k8s_home_cluster"/>
	<link rel="alternate" type="text/html" href="https://dtype.org/index.php?title=Perf/watt_benchmarks_in_a_k8s_home_cluster&amp;action=history"/>
	<updated>2026-07-15T02:40:54Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.39.5</generator>
	<entry>
		<id>https://dtype.org/index.php?title=Perf/watt_benchmarks_in_a_k8s_home_cluster&amp;diff=2364&amp;oldid=prev</id>
		<title>Drew: Measured perf/watt across 8 cluster nodes (M4/M1/x86/CM5), power at the wall via UniFi PDU+PoE</title>
		<link rel="alternate" type="text/html" href="https://dtype.org/index.php?title=Perf/watt_benchmarks_in_a_k8s_home_cluster&amp;diff=2364&amp;oldid=prev"/>
		<updated>2026-07-15T00:14:53Z</updated>

		<summary type="html">&lt;p&gt;Measured perf/watt across 8 cluster nodes (M4/M1/x86/CM5), power at the wall via UniFi PDU+PoE&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;= Perf/watt of a heterogeneous Kubernetes cluster: Apple silicon vs x86 vs Raspberry Pi CM5 =&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;Measured performance-per-watt for eight nodes of a real, running Kubernetes cluster — Apple M1/M4&lt;br /&gt;
Mac minis, three x86 boxes, and Raspberry Pi CM5s — with power taken at the wall rather than from&lt;br /&gt;
spec sheets. The lens is deliberately &amp;quot;what does a container on this node get, and what does the&lt;br /&gt;
node cost to own&amp;quot;, not bare-silicon SPEC. Written for anyone sizing a home or small-office cluster&lt;br /&gt;
for energy efficiency. Claims are limited to what we directly measured or can cite; inference and&lt;br /&gt;
open questions are marked as such. Every number below is from a single afternoon&amp;#039;s run on 2026-07-14&lt;br /&gt;
and the raw method is given so it can be repeated.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Apple M4 wins performance-per-watt by roughly 2×&amp;#039;&amp;#039;&amp;#039; over every x86 part tested, and it does so &amp;#039;&amp;#039;&amp;#039;from inside a virtual machine&amp;#039;&amp;#039;&amp;#039; while the x86 boxes run on bare metal.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;x86 wins absolute throughput by a wide margin.&amp;#039;&amp;#039;&amp;#039; The i9-13900 produced more than twice the multi-core work of any other node — it is simply expensive to run.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;The CM5 and low-power x86 are tied&amp;#039;&amp;#039;&amp;#039; on perf/watt once the measurement boundary is corrected for. The CM5&amp;#039;s apparent lead is an artifact of how it is metered.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Single-threaded perf/watt is where x86 collapses&amp;#039;&amp;#039;&amp;#039; — up to 6× worse than Apple silicon, because the whole package, DRAM and PSU stay awake to run one core.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Two benchmarks disagreed by ~3× on cross-architecture ranking.&amp;#039;&amp;#039;&amp;#039; Anyone comparing ARM and x86 with a single CPU benchmark is likely publishing a wrong number. Details below.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;The idle floor dominates the result.&amp;#039;&amp;#039;&amp;#039; A node that idles at 25 W has to win hard on throughput to break even against one that idles at 2.6 W.&lt;br /&gt;
&lt;br /&gt;
== The cluster under test ==&lt;br /&gt;
&lt;br /&gt;
All nodes are workers in one k3s cluster (v1.36.2+k3s1), all running the same containerised&lt;br /&gt;
benchmark. RAM differs across nodes but is irrelevant to a CPU benchmark and was not normalised.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Node !! CPU !! Arch !! Threads !! Host OS !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;cx1&amp;lt;/code&amp;gt; || Intel i9-13900 || x86_64 || 32 || Ubuntu 26.04 || Desktop board (ASRock Z790M), 96 GB, ATX PSU&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;cx3&amp;lt;/code&amp;gt; || Intel i7-14700T || x86_64 || 28 || Ubuntu 26.04 || &amp;quot;T&amp;quot; 35 W-class part; carries Postgres/Plex/Thanos&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;cx4&amp;lt;/code&amp;gt; || AMD Ryzen 5 5600U || x86_64 || 12 || Ubuntu 26.04 || Mini-PC, mobile APU&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mx3&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mx4&amp;lt;/code&amp;gt; || Apple M4 || arm64 || 10 || Ubuntu 26.04 &amp;#039;&amp;#039;&amp;#039;in a Lima VM on macOS&amp;#039;&amp;#039;&amp;#039; || VM gets the whole box (10 cpu / 12 GiB)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mx1&amp;lt;/code&amp;gt; || Apple M1 || arm64 || 8 || Fedora Asahi Remix 44 || &amp;#039;&amp;#039;&amp;#039;Bare metal&amp;#039;&amp;#039;&amp;#039; — no VM, no macOS&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;x1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;x2&amp;lt;/code&amp;gt; || Broadcom BCM2712 (Cortex-A76) || arm64 || 4 || Ubuntu 26.04 || Raspberry Pi CM5, PoE-powered&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Method ==&lt;br /&gt;
&lt;br /&gt;
=== Benchmarks ===&lt;br /&gt;
&lt;br /&gt;
Two benchmarks, deliberately, so they could be cross-checked against each other. Both run from one&lt;br /&gt;
multi-arch &amp;lt;code&amp;gt;debian:trixie-slim&amp;lt;/code&amp;gt; container (glibc everywhere, so the C library is a&lt;br /&gt;
constant), as a Kubernetes &amp;lt;code&amp;gt;Job&amp;lt;/code&amp;gt; pinned to each node with &amp;lt;code&amp;gt;nodeName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;sysbench cpu&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; 1.0.20 — &amp;lt;code&amp;gt;--threads=1&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;--threads=$(nproc)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;--time=300&amp;lt;/code&amp;gt;. Score = events/s.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;7z b&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; (7-Zip 25.01) — &amp;lt;code&amp;gt;-mmt1&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;-mmt$(nproc)&amp;lt;/code&amp;gt;, looped to fill 300 s. Score = the &amp;quot;Tot&amp;quot; rating in MIPS, averaged over passes.&lt;br /&gt;
&lt;br /&gt;
Each of the four tests ran for a &amp;#039;&amp;#039;&amp;#039;full 5 minutes&amp;#039;&amp;#039;&amp;#039; per node. That duration is not arbitrary — see&lt;br /&gt;
&amp;#039;&amp;#039;Measuring the power&amp;#039;&amp;#039; below.&lt;br /&gt;
&lt;br /&gt;
=== Measuring the power ===&lt;br /&gt;
&lt;br /&gt;
Every node is individually metered, and the meters are polled into Prometheus/Thanos, so a&lt;br /&gt;
benchmark&amp;#039;s power is a time-range query over the exact epochs the benchmark logged.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;x86 and Mac nodes&amp;#039;&amp;#039;&amp;#039; — a UniFi smart PDU, one outlet each: &amp;#039;&amp;#039;&amp;#039;true AC at the wall&amp;#039;&amp;#039;&amp;#039;, including each machine&amp;#039;s own PSU losses.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;CM5 nodes&amp;#039;&amp;#039;&amp;#039; — PoE ports on a UniFi switch: &amp;#039;&amp;#039;&amp;#039;DC delivered at the port&amp;#039;&amp;#039;&amp;#039;, which &amp;#039;&amp;#039;&amp;#039;excludes&amp;#039;&amp;#039;&amp;#039; the switch PSU&amp;#039;s AC→DC conversion loss.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;These are not the same boundary, and that matters — see Caveats.&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Three practical findings about the instrument, each of which would have silently corrupted the&lt;br /&gt;
results:&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;The meter&amp;#039;s real cadence is 60 s&amp;#039;&amp;#039;&amp;#039;, not the ~2 min we had assumed.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;The PDU lags a load change by ~60–120 s.&amp;#039;&amp;#039;&amp;#039; Every multi-thread window opened with one or two samples still reporting the &amp;#039;&amp;#039;previous&amp;#039;&amp;#039; test&amp;#039;s power. A 5-minute window survives this (take the last 3 samples); &amp;#039;&amp;#039;&amp;#039;a 2–3 minute window would have consisted almost entirely of stale pre-load readings&amp;#039;&amp;#039;&amp;#039; and produced plausible-looking, entirely wrong numbers.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Do not use a Prometheus &amp;lt;code&amp;gt;query_range&amp;lt;/code&amp;gt; with a step finer than the scrape interval.&amp;#039;&amp;#039;&amp;#039; It carries the last sample forward to fill empty steps, so the head of every window replays the previous test&amp;#039;s power as if it were real data. Query raw samples with a range selector instead.&lt;br /&gt;
&lt;br /&gt;
The plateau rule adopted: take the &amp;#039;&amp;#039;&amp;#039;last 3 samples&amp;#039;&amp;#039;&amp;#039; of each 5-minute window; if they disagree by&lt;br /&gt;
more than ~15%, treat the run as contaminated rather than believing it.&lt;br /&gt;
&lt;br /&gt;
=== Baseline (idle) power, and why it is included ===&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;The headline metric is score ÷ total wall watts, with the idle floor included, not subtracted.&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
An always-on cluster node burns its floor 24/7 whether or not it is computing, so that draw is a real&lt;br /&gt;
cost of owning it. We deliberately did not normalise it away.&lt;br /&gt;
&lt;br /&gt;
Idle was taken as the 10th percentile over a verified-quiet 26-minute window with the cluster&amp;#039;s batch&lt;br /&gt;
work stopped. This matters more than it sounds: a naive &amp;quot;10th percentile over 24 h&amp;quot; gave &amp;#039;&amp;#039;&amp;#039;48 W&amp;#039;&amp;#039;&amp;#039; for&lt;br /&gt;
&amp;lt;code&amp;gt;cx3&amp;lt;/code&amp;gt;, because a transcoding job had been running for most of the day. A percentile is only&lt;br /&gt;
an idle estimate if the machine was actually idle for most of the window.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Node !! Idle (W) !! Boundary&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;cx1&amp;lt;/code&amp;gt; (i9-13900) || 25.2 || PDU (AC)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;cx3&amp;lt;/code&amp;gt; (i7-14700T) || 17.2 || PDU (AC)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;cx4&amp;lt;/code&amp;gt; (Ryzen 5600U) || 9.9 || PDU (AC)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mx1&amp;lt;/code&amp;gt; (M1) || 5.8 || PDU (AC)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mx3&amp;lt;/code&amp;gt; (M4) || 2.9 || PDU (AC)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mx4&amp;lt;/code&amp;gt; (M4) || 2.6 || PDU (AC)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;x1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;x2&amp;lt;/code&amp;gt; (CM5) || 2.7, 2.6 || PoE (DC)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The spread here is the story of the whole article: &amp;#039;&amp;#039;&amp;#039;an M4 Mac mini idles at about the same power as a&lt;br /&gt;
Raspberry Pi&amp;#039;&amp;#039;&amp;#039;, despite roughly ten times the peak performance, while the desktop i9 idles at nearly&lt;br /&gt;
ten times either.&lt;br /&gt;
&lt;br /&gt;
== Results ==&lt;br /&gt;
&lt;br /&gt;
=== 7z, all cores — the headline ===&lt;br /&gt;
&lt;br /&gt;
This is the number we trust for cross-architecture comparison (see the next section for why).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Node !! CPU !! Threads !! Score (MIPS) !! Idle W !! Load W !! data-sort-type=&amp;quot;number&amp;quot; | &amp;#039;&amp;#039;&amp;#039;MIPS/W&amp;#039;&amp;#039;&amp;#039; !! Boundary&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mx3&amp;lt;/code&amp;gt; || Apple M4 || 10 || 74,698 || 2.9 || 24.7 || &amp;#039;&amp;#039;&amp;#039;3,024&amp;#039;&amp;#039;&amp;#039; || PDU&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mx4&amp;lt;/code&amp;gt; || Apple M4 || 10 || 74,402 || 2.6 || 28.2 || &amp;#039;&amp;#039;&amp;#039;2,641&amp;#039;&amp;#039;&amp;#039; || PDU&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mx1&amp;lt;/code&amp;gt; || Apple M1 || 8 || 42,413 || 5.8 || 18.7 || 2,269 || PDU&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;x2&amp;lt;/code&amp;gt; || CM5 (A76) || 4 || 14,194 || 2.6 || 8.4 || 1,682* || PoE&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;cx4&amp;lt;/code&amp;gt; || Ryzen 5 5600U || 12 || 48,355 || 9.9 || 32.7 || 1,479 || PDU&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;cx1&amp;lt;/code&amp;gt; || i9-13900 || 32 || &amp;#039;&amp;#039;&amp;#039;144,572&amp;#039;&amp;#039;&amp;#039; || 25.2 || 100.9 || 1,432 || PDU&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;cx3&amp;lt;/code&amp;gt; || i7-14700T || 28 || 77,010 || 17.2 || 54.2 || 1,421 || PDU&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; &amp;#039;&amp;#039;PoE figure — not directly comparable to the PDU rows. Corrected, it lands ~1,450–1,630; see Caveats.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Read it as three tiers:&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Apple M4 — ~2× everything else.&amp;#039;&amp;#039;&amp;#039; And it earns that &amp;#039;&amp;#039;through&amp;#039;&amp;#039; a virtualization layer.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;CM5 and low-power x86 — tied&amp;#039;&amp;#039;&amp;#039;, once the boundary is corrected.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;The i9 is the throughput king and the efficiency loser&amp;#039;&amp;#039;&amp;#039;: 144,572 MIPS is nearly 2× the next best node, at 100.9 W to get it.&lt;br /&gt;
&lt;br /&gt;
=== Single-thread — where x86 falls apart ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Node !! CPU !! 7z single (MIPS) !! Load W !! data-sort-type=&amp;quot;number&amp;quot; | MIPS/W&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mx3&amp;lt;/code&amp;gt; || Apple M4 || 9,681 || 9.5 || &amp;#039;&amp;#039;&amp;#039;1,021&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mx4&amp;lt;/code&amp;gt; || Apple M4 || 9,529 || 9.8 || 969&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;x2&amp;lt;/code&amp;gt; || CM5 || 4,269 || 4.7 || 912*&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mx1&amp;lt;/code&amp;gt; || Apple M1 || 7,033 || 10.8 || 652&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;cx4&amp;lt;/code&amp;gt; || Ryzen 5 5600U || 7,096 || 27.8 || 255&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;cx3&amp;lt;/code&amp;gt; || i7-14700T || 6,972 || 37.6 || 186&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;cx1&amp;lt;/code&amp;gt; || i9-13900 || 9,902 || 62.8 || &amp;#039;&amp;#039;&amp;#039;158&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note what this table is &amp;#039;&amp;#039;not&amp;#039;&amp;#039; saying. On raw single-thread speed the i9 &amp;#039;&amp;#039;&amp;#039;wins&amp;#039;&amp;#039;&amp;#039; (9,902, ahead of&lt;br /&gt;
the M4&amp;#039;s 9,681). But it burns &amp;#039;&amp;#039;&amp;#039;62.8 W&amp;#039;&amp;#039;&amp;#039; to run one core, against the M4&amp;#039;s 9.8 W — the package,&lt;br /&gt;
96 GB of DRAM and an ATX PSU all stay awake to feed a single thread. The result is a &amp;#039;&amp;#039;&amp;#039;6× perf/watt&lt;br /&gt;
deficit&amp;#039;&amp;#039;&amp;#039; on exactly the kind of latency-sensitive, lightly-threaded work a home cluster spends most&lt;br /&gt;
of its life doing.&lt;br /&gt;
&lt;br /&gt;
We also caught the i9&amp;#039;s turbo behaviour: an all-core run &amp;#039;&amp;#039;&amp;#039;transiently pulled 157.6 W&amp;#039;&amp;#039;&amp;#039; at the wall&lt;br /&gt;
before settling to a 99 W plateau — the PL2 boost window, visible as a single 60 s sample.&lt;br /&gt;
&lt;br /&gt;
=== The two benchmarks disagree, and one of them is lying ===&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;This is the most portable lesson here.&amp;#039;&amp;#039;&amp;#039; The same eight machines, ranked by the same metric, two&lt;br /&gt;
respected benchmarks:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Node !! sysbench single (events/s) !! 7z single (MIPS) !! Verdict&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mx4&amp;lt;/code&amp;gt; (M4) || &amp;#039;&amp;#039;&amp;#039;13,519&amp;#039;&amp;#039;&amp;#039; || 9,529 || sysbench says M4 wins by 2.9×&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;cx1&amp;lt;/code&amp;gt; (i9-13900) || 4,690 || &amp;#039;&amp;#039;&amp;#039;9,902&amp;#039;&amp;#039;&amp;#039; || 7z says the i9 wins outright&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Both cannot be right. [https://blog.cloud-mercato.com/why-you-should-use-sysbench/ sysbench&amp;#039;s CPU&lt;br /&gt;
test is a simplistic prime-number benchmark built on 64-bit integer arithmetic, and is heavily&lt;br /&gt;
dependent on 64-bit division] — it was written with database-like integer workloads in mind, not as a&lt;br /&gt;
general CPU metric. Integer-division throughput is one of the most microarchitecture-variable&lt;br /&gt;
operations there is, so a division-bound loop is close to a worst case for cross-architecture&lt;br /&gt;
comparison.&lt;br /&gt;
&lt;br /&gt;
The public Geekbench 6 spread between these parts is roughly 1.3×, which corroborates 7z and not&lt;br /&gt;
sysbench. &amp;#039;&amp;#039;&amp;#039;We therefore treat 7z as the cross-architecture number and sysbench as unreliable for&lt;br /&gt;
that purpose.&amp;#039;&amp;#039;&amp;#039; Note the rankings still agree (M4 &amp;gt; M1 &amp;gt; CM5 &amp;gt; x86) — it is the &amp;#039;&amp;#039;magnitudes&amp;#039;&amp;#039; that&lt;br /&gt;
are untrustworthy.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Open question:&amp;#039;&amp;#039;&amp;#039; we cannot &amp;#039;&amp;#039;explain&amp;#039;&amp;#039; the 2.9× from first principles, and we are flagging that&lt;br /&gt;
rather than inventing a story. The obvious guess — that ARM divides faster — is not obviously right:&lt;br /&gt;
[https://forums.raspberrypi.com/viewtopic.php?t=243567&amp;amp;start=25 x86&amp;#039;s &amp;lt;code&amp;gt;DIV&amp;lt;/code&amp;gt; returns&lt;br /&gt;
quotient and remainder in a single instruction, while ARM64&amp;#039;s &amp;lt;code&amp;gt;UDIV&amp;lt;/code&amp;gt; returns only the&lt;br /&gt;
quotient and needs an extra &amp;lt;code&amp;gt;MSUB&amp;lt;/code&amp;gt; for the remainder] — and the prime loop needs the&lt;br /&gt;
remainder, which argues ARM should be &amp;#039;&amp;#039;disadvantaged&amp;#039;&amp;#039; here. The most likely explanation is simply&lt;br /&gt;
that Apple&amp;#039;s divider vastly outperforms Raptor Lake&amp;#039;s, but we have not verified that, and it is not&lt;br /&gt;
required for the conclusion: whatever the cause, a division-bound benchmark is the wrong tool.&lt;br /&gt;
&lt;br /&gt;
== Two things we learned about measuring, not about CPUs ==&lt;br /&gt;
&lt;br /&gt;
=== Kubernetes makes a small node&amp;#039;s power visibly lumpy ===&lt;br /&gt;
&lt;br /&gt;
The CM5 nodes&amp;#039; power wandered by ±1 W at idle — enough to matter when the entire all-core load delta&lt;br /&gt;
is only ~3 W. Our first instinct was to blame the meter. That was &amp;#039;&amp;#039;&amp;#039;wrong&amp;#039;&amp;#039;&amp;#039;, and the control test is&lt;br /&gt;
worth copying:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Device !! Mean W !! Stdev W !! What it is&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;usl-gw&amp;lt;/code&amp;gt; || 1.74 || &amp;#039;&amp;#039;&amp;#039;0.05&amp;#039;&amp;#039;&amp;#039; || Dumb constant PoE load&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pikvm&amp;lt;/code&amp;gt; || 2.37 || 0.11 || Dumb constant PoE load&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;u2&amp;lt;/code&amp;gt; || 2.75, 2.51 || 0.17, 0.21 || &amp;#039;&amp;#039;&amp;#039;CM5s, but not running k3s&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;x1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;x2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;x3&amp;lt;/code&amp;gt; || 5.14, 3.81, 3.30 || &amp;#039;&amp;#039;&amp;#039;1.69, 0.97, 0.76&amp;#039;&amp;#039;&amp;#039; || &amp;#039;&amp;#039;&amp;#039;CM5s running k3s + etcd&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The meter resolves 0.05 W. Two &amp;#039;&amp;#039;identical CM5 boards&amp;#039;&amp;#039; that are not cluster members sit at 0.17–0.21 W&lt;br /&gt;
of variation. The cluster members show 10–30× that. &amp;#039;&amp;#039;&amp;#039;The wobble is real power: k3s and etcd make a&lt;br /&gt;
small ARM node&amp;#039;s draw genuinely bursty at idle.&amp;#039;&amp;#039;&amp;#039; There is no stable &amp;quot;idle floor&amp;quot; to measure on such&lt;br /&gt;
a node, only a distribution — which is why a percentile over a verified-quiet window, rather than a&lt;br /&gt;
spot reading, is the only honest baseline.&lt;br /&gt;
&lt;br /&gt;
=== Never benchmark the machine you are working from ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;x1&amp;lt;/code&amp;gt; hosts the operator tooling that was orchestrating this very benchmark. It looked fine&lt;br /&gt;
on most tests, so we re-ran the identical benchmark on &amp;lt;code&amp;gt;x2&amp;lt;/code&amp;gt; — hardware-identical, same&lt;br /&gt;
cooling, same clock, but idle and uninvolved:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Test !! &amp;lt;code&amp;gt;x1&amp;lt;/code&amp;gt; (busy) !! &amp;lt;code&amp;gt;x2&amp;lt;/code&amp;gt; (clean) !! &amp;lt;code&amp;gt;x2&amp;lt;/code&amp;gt; advantage&lt;br /&gt;
|-&lt;br /&gt;
| sysbench single || 2,645.3 || 2,644.8 || &amp;#039;&amp;#039;&amp;#039;0.0%&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
|-&lt;br /&gt;
| 7z single || 4,158 || 4,269 || 2.7%&lt;br /&gt;
|-&lt;br /&gt;
| sysbench multi || 9,918 || 10,331 || 4.2%&lt;br /&gt;
|-&lt;br /&gt;
| 7z multi || 12,428 || 14,194 || &amp;#039;&amp;#039;&amp;#039;14.2%&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Single-thread is &amp;#039;&amp;#039;&amp;#039;identical to four significant figures&amp;#039;&amp;#039;&amp;#039; — one core of four, no contention. But&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;7z multi was off by 14.2%&amp;#039;&amp;#039;&amp;#039;, far more than the ~4% the other tests suggested, because 7z is&lt;br /&gt;
cache-hungry and the co-resident work was evicting its working set. A contaminated node does not&lt;br /&gt;
degrade uniformly: it degrades &amp;#039;&amp;#039;where the benchmark is sensitive&amp;#039;&amp;#039;. If we had only run sysbench, we&lt;br /&gt;
would have concluded the contamination was ~4% and shipped a number that was wrong by 14%.&lt;br /&gt;
&lt;br /&gt;
== Caveats ==&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Mixed measurement boundaries.&amp;#039;&amp;#039;&amp;#039; CM5s are metered at the PoE port (DC delivered, excluding the switch PSU&amp;#039;s conversion loss); everything else at the PDU (AC at the wall). The switch draws 105.1 W AC to deliver 77.2 W of PoE across all ports; allowing 15–25 W for the switch&amp;#039;s own electronics puts its PSU at ~86–96% efficient, i.e. a &amp;#039;&amp;#039;&amp;#039;×1.04–×1.17 correction&amp;#039;&amp;#039;&amp;#039; to the CM5 figures. That moves &amp;lt;code&amp;gt;x2&amp;lt;/code&amp;gt; from 1,682 to &amp;#039;&amp;#039;&amp;#039;~1,450–1,630 MIPS/W&amp;#039;&amp;#039;&amp;#039; — statistically indistinguishable from &amp;lt;code&amp;gt;cx4&amp;lt;/code&amp;gt;&amp;#039;s 1,479. &amp;#039;&amp;#039;&amp;#039;So &amp;quot;the CM5 beats low-power x86&amp;quot; is not a supportable claim; &amp;quot;they are tied&amp;quot; is.&amp;#039;&amp;#039;&amp;#039; The M4&amp;#039;s ~2× lead is far outside this correction and is unaffected.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;The Lima VM tax is unquantified.&amp;#039;&amp;#039;&amp;#039; The M4 nodes ran inside a VM and still won. We did not measure the native-vs-virtualised delta (doing so requires stopping the VM, which would have taken the node out of the cluster), so we can only say the tax is ≥ 0 and the M4&amp;#039;s true native figure &amp;#039;&amp;#039;&amp;#039;can only be better than reported&amp;#039;&amp;#039;&amp;#039;. The ~2× is a floor.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;CM5 precision is ~±6%&amp;#039;&amp;#039;&amp;#039;, not better: with ~5 samples against ~0.8 W of real burstiness, the standard error on a ~6–8 W reading is ~0.35 W. Adequate for tier placement, not for splitting a tie.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;&amp;quot;Idle&amp;quot; is as-deployed, not bare.&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;cx3&amp;lt;/code&amp;gt; permanently hosts Postgres, Plex and Thanos and never goes below 12.4 W in 30 days; &amp;lt;code&amp;gt;cx1&amp;lt;/code&amp;gt; hosts Prometheus. Their idle figures include that resident work. This is deliberate — it is what those nodes actually cost to own — but it is not a board-level idle spec.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Single run, single afternoon.&amp;#039;&amp;#039;&amp;#039; No repeat trials, so no confidence intervals beyond the within-window spread. The cluster was verified quiet first.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;musl vs glibc was eliminated&amp;#039;&amp;#039;&amp;#039; (one glibc container everywhere) but compiler/tuning differences between the Debian arm64 and amd64 builds of these tools were not.&lt;br /&gt;
&lt;br /&gt;
== Reproducing this ==&lt;br /&gt;
&lt;br /&gt;
The container is stock &amp;lt;code&amp;gt;debian:trixie-slim&amp;lt;/code&amp;gt; plus &amp;lt;code&amp;gt;apt-get install sysbench 7zip&amp;lt;/code&amp;gt;&lt;br /&gt;
(note: on current Debian the binary is &amp;lt;code&amp;gt;7z&amp;lt;/code&amp;gt;, from the &amp;lt;code&amp;gt;7zip&amp;lt;/code&amp;gt; package —&lt;br /&gt;
&amp;lt;code&amp;gt;p7zip&amp;lt;/code&amp;gt; is a removed transitional package). The benchmark logs&lt;br /&gt;
&amp;lt;code&amp;gt;BENCH_START/BENCH_END&amp;lt;/code&amp;gt; epochs around each test; power is then a range query over exactly&lt;br /&gt;
those epochs, taking the last 3 samples. Run it when the cluster is genuinely idle, one node per&lt;br /&gt;
metered domain, and re-run anything whose plateau samples disagree.&lt;br /&gt;
&lt;br /&gt;
[[Category:Infrastructure]]&lt;br /&gt;
[[Category:Benchmarks]]&lt;/div&gt;</summary>
		<author><name>Drew</name></author>
	</entry>
</feed>