Slechte benchmarks en evaluaties: Senior SWE-Bench, "napkin math" en winterbanden
1. Napkin Math: Prestatieschattingen
Een vriend van mij bestudeerde prestatie-ordes van grootte ter voorbereiding op interviews over computerprestaties en stuitte op de populaire repository https://github.com/sirupsen/napkin-math. De README bevat de volgende tabellen met prestatieschattingen:
Napkin Math prestatieschattingen
| Operatie | Latency | Throughput | 1 MiB | 1 GiB |
|---|---|---|---|---|
| Sequentiële Memory R/W (64 bytes) | 0,5 ns | 20 GiB/s (Single Thread) | 50 $\mu$s | 50 ms |
| 200 GiB/s (Threaded) | 5 $\mu$s | 5 ms | ||
| Netwerk Zelfde Zone | 10 GiB/s | 100 $\mu$s | 100 ms | |
| ├ Binnen VPC | 10 GiB/s | 100 $\mu$s | 100 ms | |
| ├ Buiten VPC | 3 GiB/s | 300 $\mu$s | 300 ms | |
| Hashing, niet crypto-safe (64 bytes) | 10 ns | 5 GiB/s | 200 $\mu$s | 200 ms |
| Random Memory R/W (64 bytes) | 20 ns | 3 GiB/s | 300 $\mu$s | 300 ms |
| Snelle Serialisatie [8] [9] † | N/A | 1 GiB/s | 1 ms | 1 s |
| Snelle Deserialisatie [8] [9] † | N/A | 1 GiB/s | 1 ms | 1 s |
| Systeemoproep (System Call) | 300 ns | N/A | N/A | N/A |
| Hashing, crypto-safe (64 bytes) | 100 ns | 1 GiB/s | 1 ms | 1 s |
| Sequentiële SSD read (8 KiB) | 1 $\mu$s | 8 GiB/s | 100 $\mu$s | 100 ms |
| Context Switch [1] [2] | 10 $\mu$s | N/A | N/A | N/A |
| Sequentiële SSD write, -fsync (8 KiB) | 2 $\mu$s | 3 GiB/s | 300 $\mu$s | 300 ms |
| TCP Echo Server (32 KiB) | 50 $\mu$s | 500 MiB/s | 2 ms | 2 s |
| Random SSD Read (8 KiB) | 100 $\mu$s | 70 MiB/s | 15 ms | 15 s |
| Decompressie [11] | N/A | 1 GiB/s | 1 ms | 1 s |
| Compressie [11] | N/A | 500 MiB/s | 2 ms | 2 s |
| Sorteren (64-bit integers) | N/A | 500 MiB/s | 2 ms | 2 s |
| Proxy: Envoy/ProxySQL/Nginx/HAProxy | 50 $\mu$s | ??? | ||
| Netwerk binnen dezelfde regio | 250 $\mu$s | 2 GiB/s | 500 $\mu$s | 500 ms |
| Premium netwerk binnen zone/VPC | 250 $\mu$s | 25 GiB/s | 50 $\mu$s | 40 ms |
| Sequentiële SSD write, +fsync (8 KiB) | 300 $\mu$s | 30 MiB/s | 30 ms | 30 s |
| {MySQL, Memcached, Redis, ..} Query | 500 $\mu$s | ??? | ||
| Serialisatie [8] [9] † | N/A | 100 MiB/s | 10 ms | 10 s |
| Deserialisatie [8] [9] † | N/A | 100 MiB/s | 10 ms | 10 s |
| Sequentiële HDD Read (8 KiB) | 10 ms | 250 MiB/s | 2 ms | 2 s |
| Random HDD Read (8 KiB) | 10 ms | 0,7 MiB/s | 2 s | 30 m |
| Blob Storage GET, if-not-match 304 | 30 ms | |||
| Blob Storage GET, 1 conn (128 KiB) | 80 ms | 100 MiB/s | 10 ms | 10 s |
| Blob Storage GET, n conn (offsets) | 80 ms | NW limit | ||
| Blob Storage LIST | 100 ms | |||
| Blob Storage PUT, 1 conn (128 KiB) | 200 ms | 100 MiB/s | 10 ms | 10 s |
| Blob Storage PUT, n conn (multipart) | 200 ms | NW limit | 10 ms | 10 s |
| Netwerk tussen regio's [6] | Varieert | 25 MiB/s | 40 ms | 40 s |
| Netwerk NA Central $\leftrightarrow$ East | 25 ms | 25 MiB/s | 40 ms | 40 s |
| Netwerk NA Central $\leftrightarrow$ West | 40 ms | 25 MiB/s | 40 ms | 40 s |
| Netwerk NA East $\leftrightarrow$ West | 60 ms | 25 MiB/s | 40 ms | 40 s |
| Netwerk EU West $\leftrightarrow$ NA East | 80 ms | 25 MiB/s | 40 ms | 40 s |
| Netwerk EU West $\leftrightarrow$ NA Central | 100 ms | 25 MiB/s | 40 ms | 40 s |
| Netwerk NA West $\leftrightarrow$ Singapore | 180 ms | 25 MiB/s | 40 ms | 40 s |
| Netwerk EU West $\leftrightarrow$ Singapore | 160 ms | 25 MiB/s | 40 ms | 40 s |
Wat is er mis met deze benchmark?
Random memory access latency
Mijn vriend Jamie merkte direct op dat random memory R/W op 20 ns staat. Omdat random memory R/W impliceert dat er een echte DRAM-read plaatsvindt (geen cache-hit), zou dit voor een grove schatting rond de 100 ns moeten liggen.
Bij nader inzien gebruikt de README de term "latency" voor zaken die dat niet zijn. In de code voor random memory read latency staat het volgende:
while test.i < test.vec.len() {
let random_index = test.order[test.i];
black_box(test.vec[random_index]);
test.i += 1;
}
Er is geen data-afhankelijkheid tussen de loop-iteraties, waardoor de geheugenleesacties parallel plaatsvinden. De latency wordt berekend door de gemiddelde tijd per toegang te nemen, maar omdat de CPU meerdere loads tegelijkertijd kan verwerken (in flight), is dit getal incorrect. Om latency correct te meten, moet men afhankelijkheden tussen loads introduceren om overlappende toegang te voorkomen.
Random SSD read
Naast de geheugenlatency viel mij de random SSD read op: 100 $\mu$s / 70 MB/s. SSD's kunnen veel sneller (of langzamer) zijn. Snelle, niet-exotische apparaten (zoals de Kioxia CD9P-R) kunnen latencies onder de 40 $\mu$s halen. Bovendien is één enkel getal voor random read latency en throughput bij schijven minder nuttig dan bij DRAM, omdat resultaten sterk variëren op basis van leesgrootte, queue-diepte en het aantal jobs.
De code voor de SSD random read is even problematisch. De offsets worden gegenereerd met:
for i in 0..(buffer.len() / page_size) {
pages.push((i * page_size + 1) as u64);
}
En vervolgens worden 8 KiB reads uitgevoerd. De volgende problemen treden op:
- De
+1zorgt ervoor dat elke read niet-uitgelijnd (unaligned) is. Met een page size van 4 KiB raakt één read drie pagina's. - Verschillende offsets kunnen dezelfde pagina's overlappen, wat leidt tot onbedoelde reads uit de page cache.
- Afhankelijk van de page size kunnen reads buiten het einde van het bestand treden en een panic veroorzaken.
Sequentiële SSD read
De code voor de sequentiële 8 KiB SSD read (opgegeven als 1 $\mu$s latency en 8 GiB/s throughput) is ook onbetrouwbaar. De code neemt een bestand van 1 GiB, flusht het en leest het herhaaldelijk. Dit resulteert in één ongecachede read, gevolgd door gecachede reads.
Op een c4-standard-48-lssd instance claimt Google een maximale throughput van 5000 MiB/s voor alle 8 schijven (625 MiB/s per schijf). Een waarde van 8 GiB/s is dus excessief en bevestigt dat de benchmark per ongeluk uit de cache leest.
Representativiteit
Het doel van "napkin math" is meestal niet om de exacte prestaties van één specifieke cloud-instance te kennen, maar om basisgetallen te hebben voor schattingen. Echter, de getallen in de sirupsen-benchmark zijn zo specifiek voor één configuratie dat ze weinig algemene waarde hebben.
Ook de waarden voor compressie en decompressie (resp. 500 MiB/s en 1 GiB/s) zijn te simplistisch. Bij het gebruik van zstd-opties zie je verschillen van meer dan twee grootte-ordes in snelheid.
Wat is nuttig om te leren?
Hoewel het kennen van dit soort getallen nuttig is, is het memoriseren van een tabel vaak minder effectief dan het begrijpen van de afleiding. Als je veel met bepaalde systemen werkt, onthoud je de relevante getallen (zoals machten van 2 of specifieke hardware-limieten) organisch. Het grootste risico is dat populaire maar incorrecte repositories zoals deze worden gebruikt door interviewers die niet weten dat de getallen onjuist zijn.
Bonus: Geheugenlatency over tijd
Uit data van instlatx64 blijkt dat geheugenlatency een tijd lang enorm verbeterde, maar dat deze verbetering is gestagneerd en in sommige gevallen zelfs is toegenomen.
Er zijn uitschieters uit de jaren '90, zoals een 83 MHz Intel Pentium Overdrive met een latency van 690 ns. Dit lijkt correct gezien de bus-timing van die tijd (circa 11 bus-cycli voor een word access), wat aantoont dat men bij het analyseren van benchmarks altijd rekening moet houden met de hardware-architectuur.
---
2. AI-coding agents: DeepSWE en Senior SWE-Bench
Algemene plausibiliteit
Zowel DeepSWE als Senior SWE-Bench voelen niet plausibel aan als samenvattingen van hoe goed coding agents in het algemeen werken. Een oppervlakkige lezing van DeepSWE suggereert dat GPT-5.5 net zo goed is als Fable 5, terwijl Senior SWE-Bench suggereert dat Opus 4.8 beter is dan GPT-5.6. Deze resultaten komen vaak niet overeen met de praktijkervaring van ervaren programmeurs.
Methodologische problemen
Veel publieke benchmarks voor coding agents zijn onbetrouwbaar. Een enkelvoudige samenvattingsscore kan misleidend zijn omdat sub-benchmarks vaak tegenstrijdige resultaten geven.
In DeepSWE zijn er 113 taken. GPT-5.5 scoort hier significant beter dan Opus 4.8. Echter, wanneer men naar de taken kijkt, blijken er nauwelijks taken tussen te zitten die representatief zijn voor echt programmeerwerk. Voor Rust-gebruikers zijn er slechts vier taken waar de resultaten verschillen, en deze zijn zeer specifiek en weinig relevant voor dagelijks gebruik.
Senior SWE-Bench en de "smaakvolle oplossing"
Senior SWE-Bench heeft naast de bovengenoemde problemen ook te maken met subjectieve beoordeling. Om als een "tasteful solve" (smaakvolle oplossing) te worden aangemerkt, moet een oplossing aan strikte criteria voldoen, waaronder een score op een rubric en een lengte die niet meer dan 2x die van de referentieoplossing is.
Arbitraire en subjectieve scoring
Dit creëert een "threshold effect" (drempelwaarde-effect). Een score van X is een pass, maar X-epsilon is een fail. Dit is willekeurig; een continue score zou eerlijker zijn.
Bij de LOC-meting (Lines of Code) zie je dit duidelijk:
- Een oplossing van 121 LOC kan "tasteful" zijn bij een referentie van 61 LOC. Eén regel extra (122 LOC) zou echter leiden tot een "fail".
- In extreme gevallen is de referentieoplossing slechts 1 LOC (gescoord als 2 LOC door toevoeging/verwijdering), waardoor de maximale grootte voor een "tasteful solve" slechts 3 LOC is.
Codekwaliteit
Kijkend naar de resultaten van een specifieke taak, scoort Opus 4.8 als "tasteful", terwijl Opus 4.7 faalt. In de praktijk is de oplossing van Opus 4.7 semantisch identiek aan de referentie; het enige verschil is dat de pipeline over meerdere regels is verdeeld voor betere leesbaarheid. Het is absurd om dit af te wijzen op basis van "smaak".
Variantie van de grader
LLM-variantie speelt ook een rol bij de beoordeling. Wanneer dezelfde resultaten tien keer door een LLM-grader (Sonnet 4.6) worden beoordeeld, wijkt het resultaat in 23% van de gevallen af van de officiële score. Als men een ander model gebruikt (zoals GPT-5.6 Sol) voor de grading, wordt het aantal "tasteful" oplossingen meer dan gehalveerd.
Conclusie over AI-benchmarks
Het is momenteel zinloos om met SOTA LLM's een objectief oordeel te vellen over "codekwaliteit". De resultaten van Senior SWE-Bench worden vaak gepresenteerd als betekenisvolle verschillen (bijv. 25,0% vs 24,4%), terwijl dit in werkelijkheid ruis is.
---
3. Koudeweer-prestaties van banden
Er wordt vaak beweerd dat all-season banden hard worden (als "hockeypucks") bij temperaturen onder de 7°C (45°F) en daardoor grip verliezen. Er is echter geen benchmark die dit ondersteunt; het is een claim die simpelweg wordt herhaald.
De resultaten van Jonathan Benson
Jonathan Benson heeft uitgebreid onderzoek gedaan naar bandenprestaties bij verschillende temperaturen:
- Droge omstandigheden: Zomerbanden hebben de beste grip tot 0°C, gevolgd door all-season banden. Winterbanden presteren in droge kou aanzienlijk slechter dan beide.
- Natte omstandigheden: Bij 2°C presteren all-season banden veel beter dan zomerbanden, maar zomerbanden presteren nog steeds beter dan winterbanden.
Let op: Benson testte met UHP (Ultra High Performance) winterbanden. "Nordische" winterbanden (die in de VS en Canada vaker worden gebruikt) presteren anders, maar zelfs vergeleken met UHP-winterbanden blijven all-season banden superieur in droge of natte condities boven de 0°C.
De claim dat all-season banden uitsluitend vanwege de kou te hard worden om grip te houden, is dus onjuist.
---
Bijlage: Aanvullingen over schijfprestaties
Peter Geoghegan, expert op het gebied van schijfprestaties, voegt het volgende toe: Er is aanzienlijke variatie in prestaties tussen vergelijkbare SSD's voor bepaalde toegangspatronen, vaak door verschillen in FTL (Flash Translation Layer) of firmware. Sommige SSD's zijn bijvoorbeeld veel beter in het sequentieel achteruit lezen.
Deze details zijn vaak ondoorzichtig voor het besturingssysteem. Voor microbenchmarking is de beste aanpak om defensief te zijn met provisioning en het regelmatig uitvoeren van TRIM. Het verkrijgen van betrouwbare getallen voor schijfprestaties vereist veel meer zorg dan simpelweg een script draaien, omdat de interactie tussen hardware, firmware en OS te complex is voor eenvoudige benchmarks.
Groetjes,