Graph: fabricate overview of timing scales
Content generated by Knowledge-Technology - collect information with the help of Claude - validate my own measurements with sources from the net - find a suitable form for the presentation - instructed Claude to build a SVG with a logarithmic time scale - instructed Claude to summarise the findings as Asciidoc table
This commit is contained in:
parent
7650da5d67
commit
f46f117eda
5 changed files with 1210 additions and 147 deletions
|
|
@ -49,9 +49,7 @@
|
|||
<node CREATED="1784566743858" ID="ID_374363115" MODIFIED="1784566748447" TEXT="Verwendung von KI">
|
||||
<node CREATED="1784566749890" ID="ID_208298802" MODIFIED="1784566821115" TEXT="Leitlinien nach Alexandrescu">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
hab dafür zwar keinen Beleg (jenseits von ein paar Videos), aber ich nehme hier den Namen »Alexandrescu« in Gebrauch, um etwas — für sich selbst plausibles — auch mit Autorität sagen zu können
|
||||
|
|
@ -107,16 +105,13 @@
|
|||
<node CREATED="1785790716243" ID="ID_1869514045" MODIFIED="1785790725942" TEXT="muß »Synchronisation« eigens behandeln">
|
||||
<node CREATED="1785791037159" ID="ID_396828809" MODIFIED="1785791086458" TEXT="hier »trennt sich die Spreu vom Weizen«">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
die allermeisten Entwickler heutzutage gehen niemals über diese Schwelle, und verstecken sich deshalb hinter Frameworks
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1785791092863" ID="ID_709044928" MODIFIED="1785791103479" TEXT="es ist viel Halbwissen unterwegs"/>
|
||||
</node>
|
||||
|
|
@ -160,9 +155,7 @@
|
|||
<node CREATED="1785529171087" ID="ID_1945346295" MODIFIED="1785529186416" TEXT="want speedy response to new arrangements"/>
|
||||
<node CREATED="1785529228286" ID="ID_1074909901" MODIFIED="1785529301885" TEXT="integrate very expensive workloads">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
raw video with very high quality parameters; elaborate processing stack
|
||||
|
|
@ -205,9 +198,7 @@
|
|||
<node CREATED="1785537107740" ID="ID_1255119744" MODIFIED="1785537135326" TEXT="and especially for Video ⟶ a new twist...."/>
|
||||
<node CREATED="1785536747451" ID="ID_1634555006" MODIFIED="1785537079438">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
I/O is no longer slow — and <i>that's the problem</i>
|
||||
|
|
@ -370,7 +361,101 @@
|
|||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1754271487261" ID="ID_1152628369" MODIFIED="1779389322292" TEXT="Inhalte aufbereiten">
|
||||
<icon BUILTIN="flag-pink"/>
|
||||
<node CREATED="1754271622745" ID="ID_1711166940" MODIFIED="1754271624175" TEXT="Texte"/>
|
||||
<node CREATED="1754271624646" ID="ID_52826289" MODIFIED="1754271626857" TEXT="Grafik"/>
|
||||
<node CREATED="1754271624646" ID="ID_52826289" MODIFIED="1754271626857" TEXT="Grafik">
|
||||
<node CREATED="1785817833206" ID="ID_327257827" MODIFIED="1785817840819" TEXT="Diagramm "Time Scales"">
|
||||
<node CREATED="1785817842583" ID="ID_306380330" MODIFIED="1785817861311" TEXT="Idee: möchte die gewaltigen Zeitspannen visualisieren">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1785817863252" ID="ID_299103430" MODIFIED="1785817884168" TEXT="möchte klarmachen, warum wir es mit »Stockwerken« zu tun haben"/>
|
||||
<node CREATED="1785817885505" ID="ID_1002287440" MODIFIED="1785817898591" TEXT="brauche ein Framework, in dem ich die vierschiednen Zahlen einordnen kann"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1785817904306" ID="ID_1762091251" MODIFIED="1785817932470" STYLE="fork" TEXT="diese Idee mit Claude ausarbeiten....">
|
||||
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||
<icon BUILTIN="wizard"/>
|
||||
<node CREATED="1785817934211" ID="ID_1193226285" MODIFIED="1785817983642" TEXT="lasse Claude die Timings aufsammeln aus dem anderen Diskussionsthread">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
habe jetzt einen ziemlich langen Thread mit Recherche / Hintergrundwissen für mich; in dem Rahmen sind die diversen Zeitangaben bereits alle aufgetaucht
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1785817989939" ID="ID_1738971982" MODIFIED="1785818000822" TEXT="lasse Zahlen nochmal überprüfen und mir einige Quellen suchen"/>
|
||||
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1785818001802" ID="ID_420827912" MODIFIED="1785818058289" STYLE="fork" TEXT="Vorschlag von Claude: plausibel machen durch Analogie: 1 clock-tick ≙ 1 sec">
|
||||
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1785818059596" ID="ID_1473752885" MODIFIED="1785818077088" TEXT="Geil">
|
||||
<icon BUILTIN="ksmiletris"/>
|
||||
</node>
|
||||
<node CREATED="1785818061762" ID="ID_1056499967" MODIFIED="1785818074164" TEXT="das sind alle Goldhamlster Deutschlands aneinandergereicht"/>
|
||||
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1785818084662" ID="ID_1277933693" MODIFIED="1785818095365" TEXT="werde das als separates Slide bringen">
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1785818213769" ID="ID_1124818051" MODIFIED="1785818244989" TEXT="lasse mir einen Vorschlag machen, mit reduzierter Auswahl und didaktisch-verkürzten Titeln"/>
|
||||
<node CREATED="1785818246457" ID="ID_249476374" MODIFIED="1785818250452" TEXT="einige wenige Korrekturen"/>
|
||||
<node CREATED="1785818251079" ID="ID_306091121" MODIFIED="1785818264085" TEXT="diskutiere Tabellenform vs. Diagramm"/>
|
||||
<node CREATED="1785818264742" ID="ID_1640435583" MODIFIED="1785818276130" TEXT="lasse Claude ausrechnen, ob das Diagramm lesbar ist">
|
||||
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1785818298026" ID="ID_987123563" MODIFIED="1785818345795" STYLE="fork" TEXT="Vorschlag Claude: aufbrechen in »Stockwerke«">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Interessante Idee ... Claude greift also mein Framing vom ersten Prompt wieder auf ... erscheint mir sehr plausibel
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||
<icon BUILTIN="wizard"/>
|
||||
</node>
|
||||
<node CREATED="1785818347664" ID="ID_1543794705" MODIFIED="1785818898650" TEXT="damit ließe sich das in 4 »Stockwerke« unterbringen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Das hat Claude interessanterweise erst gesehen, nachdem ich an den längsten Zeitspannen etwas getweakt hatte. Mir war aufgefallen 1000sec ≈ 15min ⟹ damit kommen wir mit einer Sekunden-Skala als 4.Zeile gut aus
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1785818395777" ID="ID_1984967393" MODIFIED="1785818581196" TEXT="Idee: teile auf in »Maschine« — »Mensch«">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...das ergab sich aus der Konversation: im Grunde reichen die ganzen Maschinen-relevanten Zeiten hoch bis 10ms / etwa an dem Punkt beginnen Timings, die vom Menschen wahrnehmbar sind.
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1785818286987" ID="ID_346780786" MODIFIED="1785818292938" TEXT="Entscheidung für ein Diagramm">
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1785818430680" ID="ID_662868064" MODIFIED="1785818900154" TEXT="lasse Claude ein geeignetes SVG generieren">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1785818441734" ID="ID_953591500" MODIFIED="1785818447505" TEXT="nach meinen Vorgaben..."/>
|
||||
<node CREATED="1785818447838" ID="ID_161232521" MODIFIED="1785818484948" TEXT="generiert ein zunächst sichtbares "scaffold""/>
|
||||
<node CREATED="1785818487850" ID="ID_206426899" MODIFIED="1785818500771" TEXT="dann jeweils einen transparenten Layer für jedes »Stockwerk«"/>
|
||||
<node CREATED="1785818501622" ID="ID_613662939" MODIFIED="1785818517560" TEXT="ein Dim-Layer den man zuschalten kann, wenn man in den "menschlichen"-Bereich geht"/>
|
||||
<node BACKGROUND_COLOR="#ece0bb" CREATED="1785818702064" ID="ID_540432980" MODIFIED="1785818738052" TEXT="Claude schreibt tatsächlich ein Python-Programm, das er mir auch mitgibt">
|
||||
<icon BUILTIN="ksmiletris"/>
|
||||
<node CREATED="1785863757380" ID="ID_1079327219" MODIFIED="1785863764251" TEXT="Compile-Check">
|
||||
<node CREATED="1785863765224" ID="ID_24534958" MODIFIED="1785863774760" TEXT="python3 -m py_compile gen-time-scales-diagram.py">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1785818905823" ID="ID_1365657985" MODIFIED="1785861408296" TEXT="Diagramm grafisch ausfeilen und an Seitenlayout anpassen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1754874947759" ID="ID_920995429" MODIFIED="1754874949169" TEXT="Code">
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1754875923722" FOLDED="true" ID="ID_1802306052" MODIFIED="1779389626734" TEXT="Hau-zu">
|
||||
<icon BUILTIN="idea"/>
|
||||
|
|
@ -578,9 +663,7 @@
|
|||
<node CREATED="1723038081191" ID="ID_1463117390" MODIFIED="1779388529297" TEXT="außerdem: Image »erfahrener Experte«"/>
|
||||
<node CREATED="1753133297344" ID="ID_1778242194" MODIFIED="1784566420704" TEXT="Recherche für Lumiera: wir brauchen ein eigenes IO-Framework">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Es war von Anfang an klar, daß wir <i>speziell dieses Thema selber unter Kontrolle bringen </i>müssen.
|
||||
|
|
@ -621,16 +704,13 @@
|
|||
<node CREATED="1723508279705" ID="ID_1768919179" MODIFIED="1723508290155" TEXT="daß ich hier einen durchaus eigenwilligen Weg gehe"/>
|
||||
<node CREATED="1784566608876" ID="ID_1680364545" MODIFIED="1785790359493" TEXT="daß die eigentlichen Probleme für Lumiera ungelöst sind">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Damit meine ich, ob der Ansatz mit symbolisch repräsentierten externen Fähigkeiten überhaupt aufgeht, und ob es tatsächlich gelingt, ein Werkzeug-Paradigma auf der Basis von Placements zu schaffen. Und, last but not least, ob ich Leute finden, die mich unterstützen und sich diese Vision aneignen
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1785790294093" ID="ID_1612420528" MODIFIED="1785790618638" TEXT="innerer Widerspruch bezüglich »Audience«">
|
||||
<linktarget COLOR="#9c3f50" DESTINATION="ID_1612420528" ENDARROW="Default" ENDINCLINATION="-1002;67;" ID="Arrow_ID_1857563368" SOURCE="ID_642718439" STARTARROW="None" STARTINCLINATION="-316;34;"/>
|
||||
|
|
@ -638,16 +718,13 @@
|
|||
<node CREATED="1785790510700" ID="ID_94720075" MODIFIED="1785790531089" TEXT="aber ich richte mich gezielt an diese — weil es eigentlich um Lumiera geht"/>
|
||||
<node CREATED="1785790544447" ID="ID_652954139" MODIFIED="1785790586779">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
der Talk kommt <i>fachlich</i> daher — ist aber eigentlich ein <i>Narrativ</i>  und <i>allgemeines Lehrstück</i>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -658,9 +735,7 @@
|
|||
<node CREATED="1753885985959" ID="ID_1416320830" MODIFIED="1753886099702" TEXT="VBlank-Sync">
|
||||
<node CREATED="1784562447086" ID="ID_1448869178" MODIFIED="1784562583608" TEXT="in der Design-Diskussion kurz berührt">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
ich habe zur Vorbereitung meine anfänglichen Ideen in einer Konversation mit Claude validiert....
|
||||
|
|
@ -1255,11 +1330,35 @@
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1785860775384" ID="ID_1509658937" LINK="https://claude.ai/share/8fa0fb6e-992b-40a1-adce-f03f3f748edb" MODIFIED="1785861103377" STYLE="fork">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
<b>Recherche / Background</b> - Konversation mit <u>Claude</u>
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||
<linktarget COLOR="#25bbd3" DESTINATION="ID_1509658937" ENDARROW="Default" ENDINCLINATION="-1299;65;" ID="Arrow_ID_1234011492" SOURCE="ID_402484787" STARTARROW="None" STARTINCLINATION="-369;0;"/>
|
||||
<font NAME="SansSerif" SIZE="14"/>
|
||||
<icon BUILTIN="wizard"/>
|
||||
<node COLOR="#335352" CREATED="1785860960381" ID="ID_333032086" MODIFIED="1785861084358" TEXT="lang laufender Thread — parallel zu meinen eigenen Recherchen">
|
||||
<font NAME="SansSerif" SIZE="11"/>
|
||||
</node>
|
||||
<node COLOR="#335352" CREATED="1785860994323" ID="ID_525300724" MODIFIED="1785861084358" TEXT="Ausgangspunkt war meine eigene Unsicherheit im Begriffsgebrauch">
|
||||
<font NAME="SansSerif" SIZE="11"/>
|
||||
</node>
|
||||
<node COLOR="#335352" CREATED="1785861008363" ID="ID_1530707411" MODIFIED="1785861084358" TEXT="habe mir dann Details erklären lassen, die ich nur ungefär wußte">
|
||||
<font NAME="SansSerif" SIZE="11"/>
|
||||
</node>
|
||||
<node COLOR="#335352" CREATED="1785861023766" ID="ID_391668172" MODIFIED="1785861084356" TEXT="gegen Ende wurde es eine Debatte zu Unix/Design-Philosophien">
|
||||
<font NAME="SansSerif" SIZE="11"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1784562284612" ID="ID_1770923455" MODIFIED="1785373442117" TEXT="Performance-Aspekte">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Ich verfüge über vertieftes Wissen und einiges an Erfahrung in diesen Bereichen, sollte aber meine Kenntnisse überprüfen und festigen, um auch auf Fragen eingehen zu können. Im Besonderen zu Kernel-nahen Themen weiß ich ehr wenig.
|
||||
|
|
@ -1299,9 +1398,7 @@
|
|||
<node CREATED="1784903760129" ID="ID_1989117356" MODIFIED="1784905020228" TEXT="das war die erste Mainstream-Sprache mit einem Memory-Model"/>
|
||||
<node CREATED="1784903786078" ID="ID_1216686049" LINK="https://gee.cs.oswego.edu/dl/jmm/cookbook.html" MODIFIED="1784905020228">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Doug Lea's "<b>JSR-133 Cookbook for Compiler Writers</b>"
|
||||
|
|
@ -1312,9 +1409,7 @@
|
|||
</node>
|
||||
<node CREATED="1784903807771" ID="ID_904190729" MODIFIED="1784905020229" TEXT="Adve & Gharachorloo, "Shared Memory Consistency Models: A Tutorial" (1996)">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Gilt als Quelle für Doug Lea
|
||||
|
|
@ -1332,9 +1427,7 @@
|
|||
<node CREATED="1784903888398" ID="ID_863086016" MODIFIED="1784905020229" TEXT="Common names">
|
||||
<node CREATED="1784903888399" ID="ID_12480073" MODIFIED="1784905020229" TEXT="LoadLoad read-read fence">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
loads before must complete before loads after
|
||||
|
|
@ -1344,9 +1437,7 @@
|
|||
</node>
|
||||
<node CREATED="1784903888399" ID="ID_296525436" MODIFIED="1784905020229" TEXT="StoreStore write-write fence">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
stores before must become visible before stores after
|
||||
|
|
@ -1356,9 +1447,7 @@
|
|||
</node>
|
||||
<node CREATED="1784903888399" ID="ID_655305278" MODIFIED="1784905020229" TEXT="LoadStore read-write fence">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
loads before must complete before stores after
|
||||
|
|
@ -1368,9 +1457,7 @@
|
|||
</node>
|
||||
<node CREATED="1784903888400" ID="ID_636786121" MODIFIED="1784905020229" TEXT="StoreLoad write-read fence">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
stores before must become visible before loads after
|
||||
|
|
@ -1393,9 +1480,7 @@
|
|||
<icon BUILTIN="wizard"/>
|
||||
<node CREATED="1784904935445" ID="ID_1352377610" MODIFIED="1784905006877">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
"barrier/fence is hardware vocabulary for a specific machine instruction; memory_order is C++'s hardware-independent vocabulary for a guarantee; the compiler's job is to translate one into the other — and 'fence' in the standard specifically means the standalone
|
||||
|
||||
|
|
@ -1411,9 +1496,7 @@
|
|||
<node CREATED="1784908320566" ID="ID_1732195522" MODIFIED="1784908327105" TEXT="Reactor / Proactor">
|
||||
<node CREATED="1784908328417" ID="ID_1472819180" LINK="https://en.wikipedia.org/wiki/Pattern-Oriented_Software_Architecture" MODIFIED="1784908462711">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
<a rel="mw:WikiLink" href="https://en.wikipedia.org/wiki/Douglas_C._Schmidt" title="Douglas C. Schmidt">Douglas C. Schmidt</a><br /><u>Pattern-Oriented Software Architecture Volume 2</u>:<br />Patterns for Concurrent and Networked Objects
|
||||
|
|
@ -1453,9 +1536,7 @@
|
|||
</node>
|
||||
<node CREATED="1784906198381" ID="ID_1790908983" MODIFIED="1784906267764">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
ABER: gemeinsamer Speicherzugriff <b>kostet immer</b>
|
||||
|
|
@ -1470,9 +1551,7 @@
|
|||
</node>
|
||||
<node CREATED="1784906268926" ID="ID_66218233" MODIFIED="1784906290776">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
ABER: der Compiler kann auch <b>umordnen</b>
|
||||
|
|
@ -1484,9 +1563,7 @@
|
|||
</node>
|
||||
<node COLOR="#435e98" CREATED="1784906855164" ID="ID_301489633" MODIFIED="1784906865587">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Bezug zu <b>liburing</b>
|
||||
|
|
@ -1512,9 +1589,7 @@
|
|||
</node>
|
||||
<node CREATED="1784907202617" ID="ID_673513114" MODIFIED="1784907235721" TEXT="Kosten hängen praktisch nicht von anderen Threads ab">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
weil die Benchmark-Thread(s) warm
|
||||
|
|
@ -1544,9 +1619,7 @@
|
|||
</node>
|
||||
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1784907639420" ID="ID_421389218" MODIFIED="1784907652689" STYLE="fork">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
"A synchronization primitive's instruction-level cost is what a hot microbenchmark measures; its systemic cost — coherence traffic under contention, and blocking/wake latency when it isn't contended — is what your production tail latency measures, and the two can differ by two to four orders of magnitude."
|
||||
</body>
|
||||
|
|
@ -1556,9 +1629,7 @@
|
|||
</node>
|
||||
<node CREATED="1784908696776" ID="ID_1195619223" MODIFIED="1784908716530">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Verbindung zum <b>Proactor</b>
|
||||
|
|
@ -1582,9 +1653,7 @@
|
|||
<node CREATED="1784909034361" ID="ID_1332104626" MODIFIED="1784909049037" TEXT="Claude ordnet das ehr als »Duty-cycle« ein"/>
|
||||
<node CREATED="1784909107922" ID="ID_901244335" MODIFIED="1784909111887">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
<strong http-equiv="content-type" content="text/html; charset=utf-8">server-vacation</strong> model
|
||||
|
|
@ -1596,9 +1665,7 @@
|
|||
</node>
|
||||
<node CREATED="1784908878383" ID="ID_1154107045" MODIFIED="1784909008360" TEXT="Hinweis auf Submission SQPOLL">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
man kann einen Kernel-Thread konfiguieren, der die Submission-Queue pollt. Dort konfiguriert man eine Einschlafe-Periode. Wenn der Poller schläft, setzt er ein Bit und muß von der Applikation explizit wieder reaktiviert werden.
|
||||
|
|
@ -1622,9 +1689,7 @@
|
|||
<node CREATED="1785373651891" ID="ID_852212282" MODIFIED="1785373656476" TEXT="der Mechanismus ist generisch">
|
||||
<node CREATED="1785373696131" ID="ID_1324517392" MODIFIED="1785373774336">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Windows has <code http-equiv="content-type" content="text/html; charset=utf-8" class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]"><font face="Monospaced" color="#733a3a">WaitOnAddress</font></code><font face="Monospaced" color="#733a3a">/<code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">WakeByAddressSingle</code>/<code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">WakeByAddressAll</code></font>
|
||||
|
|
@ -1634,9 +1699,7 @@
|
|||
</node>
|
||||
<node CREATED="1785373716197" ID="ID_1245015075" MODIFIED="1785373788200">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
FreeBSD has <code http-equiv="content-type" content="text/html; charset=utf-8" class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]"><font face="Monospaced" color="#7a5454">_umtx_op</font></code>
|
||||
|
|
@ -1654,9 +1717,7 @@
|
|||
<node CREATED="1785373860741" ID="ID_1986824982" MODIFIED="1785373862088" TEXT="futex(FUTEX_WAKE, addr, n)">
|
||||
<node CREATED="1785373863108" ID="ID_1980037133" MODIFIED="1785373891097">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
weckt n threads auf,
|
||||
|
|
@ -1671,9 +1732,7 @@
|
|||
</node>
|
||||
<node CREATED="1785373936627" ID="ID_261363018" MODIFIED="1785373963603">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
beachte: der <i>uncontended-case</i> bleibt <b>komplett im userspace</b>
|
||||
|
|
@ -1729,9 +1788,7 @@
|
|||
<node CREATED="1785376300386" ID="ID_366808888" MODIFIED="1785376310031" TEXT="und kann vom userspace nicht manipuliert werden"/>
|
||||
<node CREATED="1785376310664" ID="ID_1139400273" MODIFIED="1785376386487" TEXT="das stellt die Integrität des Kernels sicher">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
man kann nur aufrufen, was der Kernel an Einsprungspunkten bietet; eigentlicher Kernel-Code ist nicht vom Userpace zugänglich
|
||||
|
|
@ -1744,9 +1801,7 @@
|
|||
<node CREATED="1785376387374" ID="ID_10839834" MODIFIED="1785376421394" TEXT="im Kernel dann gibt es einen entry-Stup (sichert weiteren Prozessor-State)"/>
|
||||
<node CREATED="1785376444393" ID="ID_1935728415" MODIFIED="1785376496241" TEXT="Page-Table swap / hier passieren Meltdown-Mititgations">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...um Ausspionieren des Kernel via speculative execution zu verhindern
|
||||
|
|
@ -1809,9 +1864,7 @@
|
|||
<node CREATED="1785460704814" ID="ID_431321839" MODIFIED="1785460714572" TEXT="warum hat Linux so lange gebraucht?">
|
||||
<node CREATED="1785460715693" ID="ID_1245470107" MODIFIED="1785460751768" TEXT="man hat nicht »geschlafen«">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
man hat die Herausforderung durch die SSDs zeitnah erkannt und mit tiefgreifenden internen Umbauten begonnen
|
||||
|
|
@ -1824,9 +1877,7 @@
|
|||
<node CREATED="1785460833117" ID="ID_335280595" MODIFIED="1785460858629" TEXT="das scheitert daran, daß man dann sukzessive viele Kernel-Strukturen aufdoppeln müßte"/>
|
||||
<node CREATED="1785460866904" ID="ID_1886883732" MODIFIED="1785460932865" TEXT="oder (wie bei libaio) daß jedes einzelne Subsystem eine "non-blocking"-Variante bieten müßte">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...was nicht realisierbar ist, und deshalb ist der Ansatz von libaio stecken geblieben und bleibt auf einige Randfälle begrenzt (und noch schlimmer, kann jederzeit auf blocking waits zurückfallen)
|
||||
|
|
@ -1849,9 +1900,7 @@
|
|||
<node CREATED="1785461094856" ID="ID_521796255" MODIFIED="1785461114055" TEXT="deshalb hatte BSD bisher noch keine brennende Notwendigkeit, etwas zu tun"/>
|
||||
<node CREATED="1785461139724" ID="ID_997488870" MODIFIED="1785461163800">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
FreeBSD: <b>linuxulator</b> wird erzwingen, daß man io_uring einfach nachbaut
|
||||
|
|
@ -1874,9 +1923,7 @@
|
|||
<node CREATED="1785461219863" ID="ID_537546788" MODIFIED="1785461231348" TEXT="der Paradigmenwechsel: es verwendet keinen Syscall">
|
||||
<node CREATED="1785461254333" ID="ID_334883335" MODIFIED="1785461261299">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Stichwort: <b>seccomp</b>
|
||||
|
|
@ -1891,9 +1938,7 @@
|
|||
<node CREATED="1785461370936" ID="ID_1804212027" MODIFIED="1785461389925" TEXT="was machen die Cloud-Provider?">
|
||||
<node CREATED="1785461391129" ID="ID_1602564687" MODIFIED="1785461409560" TEXT="Google deaktiviert es für seinen eigenen Code">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
u.a. auf Android
|
||||
|
|
@ -1908,9 +1953,7 @@
|
|||
<node CREATED="1785466404044" ID="ID_562222456" MODIFIED="1785466426860" TEXT="der Hauptautor (Axboe) entwickelt ein neues Sicherheitsframework"/>
|
||||
<node CREATED="1785466427380" ID="ID_841041241" MODIFIED="1785466459628" TEXT="es beruht auf classic BPF (nicht eBPF)">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Grund ist: eBPF erfordert höhere Privilegien
|
||||
|
|
@ -1920,9 +1963,7 @@
|
|||
</node>
|
||||
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1785466487794" ID="ID_13728980" MODIFIED="1785466521731" STYLE="fork" TEXT="Claude findet das bemerkenswert">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<h3 http-equiv="content-type" content="text/html; charset=utf-8" dir="ltr" class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold">
|
||||
Where it stands now — and a lovely structural irony
|
||||
|
|
@ -1964,16 +2005,13 @@
|
|||
<node CREATED="1785804799556" ID="ID_1705484855" MODIFIED="1785804939678" TEXT="Großrechner">
|
||||
<node CREATED="1785804803735" ID="ID_1712110487" MODIFIED="1785804939678" TEXT="hatten schon in den 60ern echtes Async-processing">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Stichwort: Channel Programs
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1785804820899" ID="ID_1792223474" MODIFIED="1785804939678" TEXT="damals war die Core extrem teuer, und die Peripherie billig"/>
|
||||
</node>
|
||||
|
|
@ -1981,14 +2019,11 @@
|
|||
<node CREATED="1785804891691" ID="ID_570139726" MODIFIED="1785804939678" TEXT="DEC und VMS"/>
|
||||
<node CREATED="1785804904554" ID="ID_565305668" MODIFIED="1785804939678" TEXT="AST: Asynchronous System Traps">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
a completion routine the system delivers by interrupting your thread. Results land in an I/O Status Block; you synchronize with event flags. Submit, continue, get called back.
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1785805001938" ID="ID_1225715009" MODIFIED="1785805004288" TEXT="Dave Cutler">
|
||||
|
|
@ -2027,16 +2062,13 @@
|
|||
<node CREATED="1785805498849" ID="ID_1654664703" MODIFIED="1785805536048" TEXT="Erlang, Aktoren, Goroutines, Coroutinen"/>
|
||||
<node CREATED="1785805586557" ID="ID_945535370" MODIFIED="1785805615976" TEXT="»function coloration« leicht gemacht">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
d.h. das Problem mit den <i>coloured functions</i> wird nicht gelöst, aber der Schmerz wird reduziert
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -2067,9 +2099,7 @@
|
|||
<node CREATED="1785806906727" ID="ID_290906212" MODIFIED="1785806928635" TEXT="sein erster Artikel was als satirische Überzeichnung gedacht"/>
|
||||
<node CREATED="1785806929283" ID="ID_1833959351" MODIFIED="1785807147619">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
nachdem der Artikel so stark eingeschlagen hat,
|
||||
|
|
@ -2078,8 +2108,7 @@
|
|||
hat er selber, unter einem Pseudonym, eine Replik geschrieben
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<node CREATED="1785807193346" ID="ID_977154454" LINK="http://dreamsongs.com/Files/worse-is-worse.pdf" MODIFIED="1785807201901" TEXT=""Worse is Better is Worse""/>
|
||||
</node>
|
||||
<node CREATED="1785807148579" ID="ID_1979393125" LINK="https://dreamsongs.com/Essays.html" MODIFIED="1785807160610" TEXT="Essays von Richard Gabriel">
|
||||
|
|
@ -4005,9 +4034,7 @@
|
|||
<icon BUILTIN="back"/>
|
||||
<node CREATED="1784226890979" ID="ID_473596944" MODIFIED="1784562049044" TEXT="ffplay">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
ffplay -f rawvideo -pixel_format rgb24 -video_size 1200x675 -framerate 50 demovideo-1200.raw
|
||||
|
|
@ -4018,9 +4045,7 @@
|
|||
</node>
|
||||
<node CREATED="1784226921919" ID="ID_1975886749" MODIFIED="1784562062109" TEXT="vlc">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
vlc --demux rawvideo --rawvid-width=1200 --rawvid-height=675 --rawvid-fps=50 --rawvid-chroma=RV24 --vout=opengl demovideo-1200.raw
|
||||
|
|
@ -4350,6 +4375,61 @@
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1785860391030" ID="ID_1841666778" MODIFIED="1785860400265" TEXT="Research-Sektion auf Lumiera.org">
|
||||
<node CREATED="1785860406146" ID="ID_17114163" MODIFIED="1785860420192" TEXT="Overview"/>
|
||||
<node CREATED="1785860425383" ID="ID_468739218" MODIFIED="1785860427904" TEXT="Resources">
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1785860434326" ID="ID_1458908971" MODIFIED="1785860443825" TEXT="TimeScales">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1785860445180" ID="ID_153676570" MODIFIED="1785860464957" STYLE="fork" TEXT="Informationen zusammengetragen mit Claude">
|
||||
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||
<icon BUILTIN="wizard"/>
|
||||
<node CREATED="1785860471809" ID="ID_402484787" MODIFIED="1785861103377" TEXT="teilweise bereits im Background/Recherche-Chat">
|
||||
<arrowlink COLOR="#25bbd3" DESTINATION="ID_1509658937" ENDARROW="Default" ENDINCLINATION="-1299;65;" ID="Arrow_ID_1234011492" STARTARROW="None" STARTINCLINATION="-369;0;"/>
|
||||
</node>
|
||||
<node CREATED="1785861111621" ID="ID_1704710749" MODIFIED="1785861189290" TEXT="habe meine eigenen Erfahrungswerte validieren lassen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
alle meine eigenen Erfahrungen und Richtwerte konnten vollumfänglich bestätigt werden; manche Meßwerte kann ich nun besser einordnen, z.B. durch die Unterscheidung in hott-pressed und systemic-cost. Erheblich dazugelernt habe ich bezüglich <b>Futex</b>es
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1785861193146" ID="ID_387177535" LINK="#ID_1762091251" MODIFIED="1785861228218" TEXT="habe daraus ein Diagramm bauen lassen">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node CREATED="1785861229354" ID="ID_162556201" MODIFIED="1785861244236" TEXT="außerdem: alle Zahlenwerte in Tabelle konsolidiert">
|
||||
<node CREATED="1785861248495" ID="ID_677703208" MODIFIED="1785861264545" TEXT="Richtwerte(Zeit/Latenz)"/>
|
||||
<node CREATED="1785861265022" ID="ID_256243482" MODIFIED="1785861266825" TEXT="Bedeutung"/>
|
||||
<node CREATED="1785861267284" ID="ID_1608529429" MODIFIED="1785861270480" TEXT="Quellen als Fußnoten"/>
|
||||
<node CREATED="1785861270940" ID="ID_1066989785" MODIFIED="1785861302195" TEXT="Spalte »gefühlte Zeit«">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
wenn ein Clock-cycle eine Sekunde dauern würde....
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="ksmiletris"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1785861304416" ID="ID_1042454460" MODIFIED="1785861317095" TEXT="lasse einge Abschnitte mit Erläuterungen generieren"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1785861321077" ID="ID_1405791777" MODIFIED="1785861334834" TEXT="Dokument formal/technisch fertigstellen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1785861335967" ID="ID_493138343" MODIFIED="1785861342325" TEXT="Quellen nochmal gegenchecken">
|
||||
<icon BUILTIN="flag-pink"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1785861381365" ID="ID_1527233926" MODIFIED="1785861393616" TEXT="Text überarbeiten / ergänzen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1785860420848" ID="ID_1771994994" MODIFIED="1785860424896" TEXT="Demo-Code"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1781400461948" FOLDED="true" ID="ID_1876863038" MODIFIED="1783362593603" TEXT="Laptop">
|
||||
<icon BUILTIN="go"/>
|
||||
|
|
|
|||
245
FrOSCon26/drawings/gen-time-scales-diagram.py
Normal file
245
FrOSCon26/drawings/gen-time-scales-diagram.py
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Generate the FrOSCon io_uring talk 'time scales' wrapped-log-scale diagram.
|
||||
|
||||
Page: 254 x 142.9 mm (== LibreOffice Impress 16:9 slide, 25.4 x 14.29 cm)
|
||||
User unit == 1 mm.
|
||||
|
||||
Structure: four bands, each spanning exactly three decades (1 -> 1000 of its
|
||||
unit), all at identical horizontal scale. Each band is a separate Inkscape
|
||||
layer so the whole thing can be exported step by step (Export > Page) and
|
||||
stacked as transparent overlays in Impress.
|
||||
|
||||
@note Code generated 8/2026 by Claude -- prompted by Ichthyostega
|
||||
"""
|
||||
import math
|
||||
|
||||
W, H = 254.0, 142.9
|
||||
|
||||
X0, X1 = 34.0, 240.0 # axis: value 1 .. value 1000
|
||||
DEC = (X1 - X0) / 3.0 # mm per decade
|
||||
AXIS_END = 243.5 # slight overshoot + chevron
|
||||
|
||||
BANDS_Y = [40.0, 75.0, 102.0, 120.0]
|
||||
|
||||
# ---- colours -------------------------------------------------------------
|
||||
C_AXIS = "#555555"
|
||||
C_MINOR = "#b3b3b3"
|
||||
C_MACH = "#14507d"
|
||||
C_HUMAN = "#b4530a"
|
||||
C_VAL_M = "#4a7ba6"
|
||||
C_VAL_H = "#c98342"
|
||||
C_MUTED = "#8a8a8a"
|
||||
C_TITLE = "#222222"
|
||||
|
||||
# ---- type ----------------------------------------------------------------
|
||||
F_NAME, F_VAL, F_BAND, F_TITLE, F_NOTE, F_DISC = 3.8, 3.2, 5.5, 8.0, 3.6, 3.0
|
||||
FONT = "DejaVu Sans, Verdana, sans-serif"
|
||||
|
||||
# tier offsets relative to band axis Y
|
||||
UP1_NAME, UP1_VAL, UP1_STUB = -10.3, -6.5, -5.0
|
||||
UP2_NAME, UP2_VAL, UP2_STUB = -18.3, -14.5, -13.0
|
||||
LO1_NAME, LO1_VAL, LO1_STUB = 11.2, 7.5, 5.0
|
||||
BRACKET_Y = 4.0
|
||||
|
||||
|
||||
def X(v):
|
||||
return X0 + DEC * math.log10(v)
|
||||
|
||||
|
||||
def esc(s):
|
||||
return (s.replace("&", "&").replace("<", "<").replace(">", ">"))
|
||||
|
||||
|
||||
def text(x, y, s, size, fill, anchor="middle", weight="normal"):
|
||||
return (f'<text x="{x:.2f}" y="{y:.2f}" font-family="{FONT}" '
|
||||
f'font-size="{size}" font-weight="{weight}" fill="{fill}" '
|
||||
f'text-anchor="{anchor}">{esc(s)}</text>')
|
||||
|
||||
|
||||
def line(x1, y1, x2, y2, stroke, w, dash=None):
|
||||
d = f' stroke-dasharray="{dash}"' if dash else ""
|
||||
return (f'<path d="M {x1:.2f},{y1:.2f} L {x2:.2f},{y2:.2f}" '
|
||||
f'stroke="{stroke}" stroke-width="{w}" fill="none"{d}/>')
|
||||
|
||||
|
||||
# ==========================================================================
|
||||
# entry data
|
||||
# ==========================================================================
|
||||
# tier: 'up1' | 'up2' | 'lo1'
|
||||
# kind: 'machine' | 'human'
|
||||
# span: (v_lo, v_hi) -> draw a bracket instead of a dot
|
||||
BANDS = [
|
||||
dict(unit="1 ns", ay=BANDS_Y[0], layer="ns", entries=[
|
||||
dict(v=1, name="L1 cache", val="1 ns", tier="up1", kind="machine"),
|
||||
dict(v=4, name="L2 cache", val="4 ns", tier="up1", kind="machine"),
|
||||
dict(v=10, name="full memory barrier", val="10 ns", tier="up2", kind="machine"),
|
||||
dict(v=15, name="L3 cache", val="15 ns", tier="up1", kind="machine"),
|
||||
dict(v=100, name="DRAM access", val="100 ns", tier="up1", kind="machine"),
|
||||
dict(span=(50, 100), name="contended cache line", val="50-100 ns",
|
||||
tier="lo1", kind="machine"),
|
||||
dict(offscale=True, name="1 clock cycle", val="\u2248 0.3 ns",
|
||||
tier="lo1", kind="machine"),
|
||||
]),
|
||||
dict(unit="1 \u00b5s", ay=BANDS_Y[1], layer="us", entries=[
|
||||
dict(v=1, name="system call", val="1 \u00b5s", tier="up1", kind="machine"),
|
||||
dict(v=2, name="context switch", val="2 \u00b5s", tier="up2", kind="machine"),
|
||||
dict(v=50, name="OS timer slack", val="50 \u00b5s", tier="up1", kind="machine"),
|
||||
dict(span=(10, 30), name="thread wake-up", val="10-30 \u00b5s",
|
||||
tier="lo1", kind="machine"),
|
||||
dict(span=(50, 100), name="SSD read", val="50-100 \u00b5s",
|
||||
tier="lo1", kind="machine"),
|
||||
]),
|
||||
dict(unit="1 ms", ay=BANDS_Y[2], layer="ms", entries=[
|
||||
dict(v=10, name="disk seek", val="10 ms", tier="up1", kind="machine"),
|
||||
dict(v=40, name="one frame @ 25 fps", val="40 ms", tier="up1", kind="machine"),
|
||||
dict(v=10, name="barely noticeable", val="10 ms", tier="lo1", kind="human"),
|
||||
dict(v=100, name="UI feels sluggish", val="100 ms", tier="lo1", kind="human"),
|
||||
]),
|
||||
dict(unit="1 s", ay=BANDS_Y[3], layer="s", entries=[
|
||||
dict(v=1, name="\u201cit\u2019s thinking\u2026\u201d", val="1 s",
|
||||
tier="lo1", kind="human"),
|
||||
dict(v=180, name="another coffee", val="3 min", tier="lo1", kind="human"),
|
||||
dict(v=900, name="go do something else", val="\u2248 15 min",
|
||||
tier="lo1", kind="human", anchor="end", ax=250.0),
|
||||
]),
|
||||
]
|
||||
|
||||
|
||||
# ==========================================================================
|
||||
# scaffold
|
||||
# ==========================================================================
|
||||
def band_axis(ay, unit):
|
||||
o = []
|
||||
o.append(line(X0, ay, AXIS_END, ay, C_AXIS, 0.6))
|
||||
# continuation chevron
|
||||
o.append(f'<path d="M {AXIS_END-2.4:.2f},{ay-1.6:.2f} L {AXIS_END:.2f},{ay:.2f} '
|
||||
f'L {AXIS_END-2.4:.2f},{ay+1.6:.2f}" stroke="{C_AXIS}" '
|
||||
f'stroke-width="0.6" fill="none"/>')
|
||||
# ticks
|
||||
for d in range(3):
|
||||
base = 10 ** d
|
||||
for m in range(1, 10):
|
||||
v = base * m
|
||||
x = X(v)
|
||||
if m == 1:
|
||||
o.append(line(x, ay - 3.0, x, ay + 3.0, C_AXIS, 0.6))
|
||||
else:
|
||||
o.append(line(x, ay - 1.6, x, ay + 1.6, C_MINOR, 0.25))
|
||||
o.append(line(X(1000), ay - 3.0, X(1000), ay + 3.0, C_AXIS, 0.6))
|
||||
o.append(text(32.0, ay + 2.0, unit, F_BAND, C_MUTED, "end", "600"))
|
||||
return o
|
||||
|
||||
|
||||
def scaffold():
|
||||
o = []
|
||||
o.append(text(10.0, 15.0, "Time scales", F_TITLE, C_TITLE, "start", "600"))
|
||||
o.append(text(244.0, 12.5, "each row spans three decades", F_NOTE, C_MUTED, "end"))
|
||||
o.append(text(244.0, 17.0, "one row down = \u00d7 1000", F_NOTE, C_MUTED, "end"))
|
||||
for b in BANDS:
|
||||
o += band_axis(b["ay"], b["unit"])
|
||||
o.append(text(10.0, 137.0,
|
||||
"Order of magnitude only \u2014 contemporary desktop / laptop x86. "
|
||||
"Expect \u00b1 2\u20133\u00d7; the ratios are the point.",
|
||||
F_DISC, C_MUTED, "start"))
|
||||
return o
|
||||
|
||||
|
||||
# ==========================================================================
|
||||
# entries
|
||||
# ==========================================================================
|
||||
def render_entry(e, ay):
|
||||
kind = e.get("kind", "machine")
|
||||
cn = C_MACH if kind == "machine" else C_HUMAN
|
||||
cv = C_VAL_M if kind == "machine" else C_VAL_H
|
||||
tier = e["tier"]
|
||||
anchor = e.get("anchor", "middle")
|
||||
o = []
|
||||
|
||||
if tier == "up1":
|
||||
ny, vy, sy = ay + UP1_NAME, ay + UP1_VAL, ay + UP1_STUB
|
||||
elif tier == "up2":
|
||||
ny, vy, sy = ay + UP2_NAME, ay + UP2_VAL, ay + UP2_STUB
|
||||
else:
|
||||
ny, vy, sy = ay + LO1_NAME, ay + LO1_VAL, ay + LO1_STUB
|
||||
|
||||
if e.get("offscale"):
|
||||
# dashed stub running off the left-hand end of the scale
|
||||
y = ay + BRACKET_Y + 0.5
|
||||
o.append(line(X0, y, 22.5, y, cn, 0.5, dash="1.6,1.2"))
|
||||
o.append(f'<path d="M 25.4,{y-1.6:.2f} L 22.0,{y:.2f} L 25.4,{y+1.6:.2f}" '
|
||||
f'stroke="{cn}" stroke-width="0.6" fill="none"/>')
|
||||
ax = 22.0
|
||||
o.append(text(ax, vy, e["val"], F_VAL, cv, "start"))
|
||||
o.append(text(ax, ny, e["name"], F_NAME, cn, "start", "600"))
|
||||
return o
|
||||
|
||||
if "span" in e:
|
||||
x1, x2 = X(e["span"][0]), X(e["span"][1])
|
||||
by = ay + BRACKET_Y
|
||||
o.append(line(x1, by, x2, by, cn, 0.7))
|
||||
o.append(line(x1, by, x1, ay, cn, 0.7))
|
||||
o.append(line(x2, by, x2, ay, cn, 0.7))
|
||||
ax = e.get("ax", (x1 + x2) / 2.0)
|
||||
else:
|
||||
x = X(e["v"])
|
||||
o.append(f'<circle cx="{x:.2f}" cy="{ay:.2f}" r="1.3" fill="{cn}"/>')
|
||||
stub_from = ay - 2.0 if tier.startswith("up") else ay + 2.0
|
||||
o.append(line(x, stub_from, x, sy, cn, 0.4))
|
||||
ax = e.get("ax", x)
|
||||
|
||||
o.append(text(ax, vy, e["val"], F_VAL, cv, anchor))
|
||||
o.append(text(ax, ny, e["name"], F_NAME, cn, anchor, "600"))
|
||||
return o
|
||||
|
||||
|
||||
# ==========================================================================
|
||||
# assemble
|
||||
# ==========================================================================
|
||||
def layer(lid, label, body, display="inline"):
|
||||
return (f'<g inkscape:groupmode="layer" id="{lid}" '
|
||||
f'inkscape:label="{label}" style="display:{display}">\n '
|
||||
+ "\n ".join(body) + "\n</g>")
|
||||
|
||||
|
||||
def build():
|
||||
layers = []
|
||||
layers.append(layer("layer-1-scaffold", "1 - scaffold", scaffold()))
|
||||
|
||||
for i, b in enumerate(BANDS):
|
||||
if b["layer"] == "ms":
|
||||
mach = [x for e in b["entries"] if e["kind"] == "machine"
|
||||
for x in render_entry(e, b["ay"])]
|
||||
hum = [x for e in b["entries"] if e["kind"] == "human"
|
||||
for x in render_entry(e, b["ay"])]
|
||||
layers.append(layer("layer-4-ms-machine", "4 - ms band (machine)", mach))
|
||||
layers.append(layer("layer-5-ms-human", "5 - ms band (human)", hum))
|
||||
elif b["layer"] == "ns":
|
||||
body = [x for e in b["entries"] for x in render_entry(e, b["ay"])]
|
||||
layers.append(layer("layer-2-ns", "2 - ns band", body))
|
||||
elif b["layer"] == "us":
|
||||
body = [x for e in b["entries"] for x in render_entry(e, b["ay"])]
|
||||
layers.append(layer("layer-3-us", "3 - us band", body))
|
||||
else:
|
||||
body = [x for e in b["entries"] for x in render_entry(e, b["ay"])]
|
||||
layers.append(layer("layer-6-s", "6 - s band (human)", body))
|
||||
|
||||
dim = [f'<rect x="0" y="22" width="{W}" height="67" fill="#ffffff" '
|
||||
f'fill-opacity="0.74"/>']
|
||||
layers.append(layer("layer-7-dim", "7 - dim ns+us (optional)", dim,
|
||||
display="none"))
|
||||
|
||||
return f'''<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
width="{W}mm" height="{H}mm" viewBox="0 0 {W} {H}" version="1.1">
|
||||
<sodipodi:namedview inkscape:document-units="mm" units="mm"/>
|
||||
<title>Time scales - ns to minutes, wrapped logarithmic</title>
|
||||
{chr(10).join(layers)}
|
||||
</svg>
|
||||
'''
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
open("/mnt/user-data/outputs/time-scales.svg", "w").write(build())
|
||||
print("written")
|
||||
230
FrOSCon26/drawings/time-scales.svg
Normal file
230
FrOSCon26/drawings/time-scales.svg
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
width="254.0mm" height="142.9mm" viewBox="0 0 254.0 142.9" version="1.1">
|
||||
<sodipodi:namedview inkscape:document-units="mm" units="mm"/>
|
||||
<title>Time scales - ns to minutes, wrapped logarithmic</title>
|
||||
<g inkscape:groupmode="layer" id="layer-1-scaffold" inkscape:label="1 - scaffold" style="display:inline">
|
||||
<text x="10.00" y="15.00" font-family="DejaVu Sans, Verdana, sans-serif" font-size="8.0" font-weight="600" fill="#222222" text-anchor="start">Time scales</text>
|
||||
<text x="244.00" y="12.50" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.6" font-weight="normal" fill="#8a8a8a" text-anchor="end">each row spans three decades</text>
|
||||
<text x="244.00" y="17.00" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.6" font-weight="normal" fill="#8a8a8a" text-anchor="end">one row down = × 1000</text>
|
||||
<path d="M 34.00,40.00 L 243.50,40.00" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<path d="M 241.10,38.40 L 243.50,40.00 L 241.10,41.60" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<path d="M 34.00,37.00 L 34.00,43.00" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<path d="M 54.67,38.40 L 54.67,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 66.76,38.40 L 66.76,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 75.34,38.40 L 75.34,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 82.00,38.40 L 82.00,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 87.43,38.40 L 87.43,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 92.03,38.40 L 92.03,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 96.01,38.40 L 96.01,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 99.52,38.40 L 99.52,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 102.67,37.00 L 102.67,43.00" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<path d="M 123.34,38.40 L 123.34,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 135.43,38.40 L 135.43,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 144.01,38.40 L 144.01,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 150.66,38.40 L 150.66,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 156.10,38.40 L 156.10,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 160.70,38.40 L 160.70,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 164.68,38.40 L 164.68,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 168.19,38.40 L 168.19,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 171.33,37.00 L 171.33,43.00" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<path d="M 192.00,38.40 L 192.00,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 204.10,38.40 L 204.10,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 212.67,38.40 L 212.67,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 219.33,38.40 L 219.33,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 224.77,38.40 L 224.77,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 229.36,38.40 L 229.36,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 233.35,38.40 L 233.35,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 236.86,38.40 L 236.86,41.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 240.00,37.00 L 240.00,43.00" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<text x="32.00" y="42.00" font-family="DejaVu Sans, Verdana, sans-serif" font-size="5.5" font-weight="600" fill="#8a8a8a" text-anchor="end">1 ns</text>
|
||||
<path d="M 34.00,75.00 L 243.50,75.00" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<path d="M 241.10,73.40 L 243.50,75.00 L 241.10,76.60" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<path d="M 34.00,72.00 L 34.00,78.00" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<path d="M 54.67,73.40 L 54.67,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 66.76,73.40 L 66.76,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 75.34,73.40 L 75.34,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 82.00,73.40 L 82.00,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 87.43,73.40 L 87.43,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 92.03,73.40 L 92.03,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 96.01,73.40 L 96.01,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 99.52,73.40 L 99.52,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 102.67,72.00 L 102.67,78.00" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<path d="M 123.34,73.40 L 123.34,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 135.43,73.40 L 135.43,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 144.01,73.40 L 144.01,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 150.66,73.40 L 150.66,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 156.10,73.40 L 156.10,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 160.70,73.40 L 160.70,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 164.68,73.40 L 164.68,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 168.19,73.40 L 168.19,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 171.33,72.00 L 171.33,78.00" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<path d="M 192.00,73.40 L 192.00,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 204.10,73.40 L 204.10,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 212.67,73.40 L 212.67,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 219.33,73.40 L 219.33,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 224.77,73.40 L 224.77,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 229.36,73.40 L 229.36,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 233.35,73.40 L 233.35,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 236.86,73.40 L 236.86,76.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 240.00,72.00 L 240.00,78.00" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<text x="32.00" y="77.00" font-family="DejaVu Sans, Verdana, sans-serif" font-size="5.5" font-weight="600" fill="#8a8a8a" text-anchor="end">1 µs</text>
|
||||
<path d="M 34.00,102.00 L 243.50,102.00" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<path d="M 241.10,100.40 L 243.50,102.00 L 241.10,103.60" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<path d="M 34.00,99.00 L 34.00,105.00" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<path d="M 54.67,100.40 L 54.67,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 66.76,100.40 L 66.76,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 75.34,100.40 L 75.34,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 82.00,100.40 L 82.00,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 87.43,100.40 L 87.43,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 92.03,100.40 L 92.03,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 96.01,100.40 L 96.01,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 99.52,100.40 L 99.52,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 102.67,99.00 L 102.67,105.00" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<path d="M 123.34,100.40 L 123.34,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 135.43,100.40 L 135.43,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 144.01,100.40 L 144.01,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 150.66,100.40 L 150.66,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 156.10,100.40 L 156.10,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 160.70,100.40 L 160.70,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 164.68,100.40 L 164.68,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 168.19,100.40 L 168.19,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 171.33,99.00 L 171.33,105.00" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<path d="M 192.00,100.40 L 192.00,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 204.10,100.40 L 204.10,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 212.67,100.40 L 212.67,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 219.33,100.40 L 219.33,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 224.77,100.40 L 224.77,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 229.36,100.40 L 229.36,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 233.35,100.40 L 233.35,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 236.86,100.40 L 236.86,103.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 240.00,99.00 L 240.00,105.00" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<text x="32.00" y="104.00" font-family="DejaVu Sans, Verdana, sans-serif" font-size="5.5" font-weight="600" fill="#8a8a8a" text-anchor="end">1 ms</text>
|
||||
<path d="M 34.00,120.00 L 243.50,120.00" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<path d="M 241.10,118.40 L 243.50,120.00 L 241.10,121.60" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<path d="M 34.00,117.00 L 34.00,123.00" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<path d="M 54.67,118.40 L 54.67,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 66.76,118.40 L 66.76,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 75.34,118.40 L 75.34,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 82.00,118.40 L 82.00,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 87.43,118.40 L 87.43,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 92.03,118.40 L 92.03,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 96.01,118.40 L 96.01,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 99.52,118.40 L 99.52,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 102.67,117.00 L 102.67,123.00" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<path d="M 123.34,118.40 L 123.34,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 135.43,118.40 L 135.43,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 144.01,118.40 L 144.01,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 150.66,118.40 L 150.66,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 156.10,118.40 L 156.10,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 160.70,118.40 L 160.70,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 164.68,118.40 L 164.68,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 168.19,118.40 L 168.19,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 171.33,117.00 L 171.33,123.00" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<path d="M 192.00,118.40 L 192.00,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 204.10,118.40 L 204.10,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 212.67,118.40 L 212.67,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 219.33,118.40 L 219.33,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 224.77,118.40 L 224.77,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 229.36,118.40 L 229.36,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 233.35,118.40 L 233.35,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 236.86,118.40 L 236.86,121.60" stroke="#b3b3b3" stroke-width="0.25" fill="none"/>
|
||||
<path d="M 240.00,117.00 L 240.00,123.00" stroke="#555555" stroke-width="0.6" fill="none"/>
|
||||
<text x="32.00" y="122.00" font-family="DejaVu Sans, Verdana, sans-serif" font-size="5.5" font-weight="600" fill="#8a8a8a" text-anchor="end">1 s</text>
|
||||
<text x="10.00" y="137.00" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.0" font-weight="normal" fill="#8a8a8a" text-anchor="start">Order of magnitude only — contemporary desktop / laptop x86. Expect ± 2–3×; the ratios are the point.</text>
|
||||
</g>
|
||||
<g inkscape:groupmode="layer" id="layer-2-ns" inkscape:label="2 - ns band" style="display:inline">
|
||||
<circle cx="34.00" cy="40.00" r="1.3" fill="#14507d"/>
|
||||
<path d="M 34.00,38.00 L 34.00,35.00" stroke="#14507d" stroke-width="0.4" fill="none"/>
|
||||
<text x="34.00" y="33.50" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.2" font-weight="normal" fill="#4a7ba6" text-anchor="middle">1 ns</text>
|
||||
<text x="34.00" y="29.70" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.8" font-weight="600" fill="#14507d" text-anchor="middle">L1 cache</text>
|
||||
<circle cx="75.34" cy="40.00" r="1.3" fill="#14507d"/>
|
||||
<path d="M 75.34,38.00 L 75.34,35.00" stroke="#14507d" stroke-width="0.4" fill="none"/>
|
||||
<text x="75.34" y="33.50" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.2" font-weight="normal" fill="#4a7ba6" text-anchor="middle">4 ns</text>
|
||||
<text x="75.34" y="29.70" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.8" font-weight="600" fill="#14507d" text-anchor="middle">L2 cache</text>
|
||||
<circle cx="102.67" cy="40.00" r="1.3" fill="#14507d"/>
|
||||
<path d="M 102.67,38.00 L 102.67,27.00" stroke="#14507d" stroke-width="0.4" fill="none"/>
|
||||
<text x="102.67" y="25.50" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.2" font-weight="normal" fill="#4a7ba6" text-anchor="middle">10 ns</text>
|
||||
<text x="102.67" y="21.70" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.8" font-weight="600" fill="#14507d" text-anchor="middle">full memory barrier</text>
|
||||
<circle cx="114.76" cy="40.00" r="1.3" fill="#14507d"/>
|
||||
<path d="M 114.76,38.00 L 114.76,35.00" stroke="#14507d" stroke-width="0.4" fill="none"/>
|
||||
<text x="114.76" y="33.50" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.2" font-weight="normal" fill="#4a7ba6" text-anchor="middle">15 ns</text>
|
||||
<text x="114.76" y="29.70" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.8" font-weight="600" fill="#14507d" text-anchor="middle">L3 cache</text>
|
||||
<circle cx="171.33" cy="40.00" r="1.3" fill="#14507d"/>
|
||||
<path d="M 171.33,38.00 L 171.33,35.00" stroke="#14507d" stroke-width="0.4" fill="none"/>
|
||||
<text x="171.33" y="33.50" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.2" font-weight="normal" fill="#4a7ba6" text-anchor="middle">100 ns</text>
|
||||
<text x="171.33" y="29.70" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.8" font-weight="600" fill="#14507d" text-anchor="middle">DRAM access</text>
|
||||
<path d="M 150.66,44.00 L 171.33,44.00" stroke="#14507d" stroke-width="0.7" fill="none"/>
|
||||
<path d="M 150.66,44.00 L 150.66,40.00" stroke="#14507d" stroke-width="0.7" fill="none"/>
|
||||
<path d="M 171.33,44.00 L 171.33,40.00" stroke="#14507d" stroke-width="0.7" fill="none"/>
|
||||
<text x="161.00" y="47.50" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.2" font-weight="normal" fill="#4a7ba6" text-anchor="middle">50-100 ns</text>
|
||||
<text x="161.00" y="51.20" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.8" font-weight="600" fill="#14507d" text-anchor="middle">contended cache line</text>
|
||||
<path d="M 34.00,44.50 L 22.50,44.50" stroke="#14507d" stroke-width="0.5" fill="none" stroke-dasharray="1.6,1.2"/>
|
||||
<path d="M 25.4,42.90 L 22.0,44.50 L 25.4,46.10" stroke="#14507d" stroke-width="0.6" fill="none"/>
|
||||
<text x="22.00" y="47.50" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.2" font-weight="normal" fill="#4a7ba6" text-anchor="start">≈ 0.3 ns</text>
|
||||
<text x="22.00" y="51.20" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.8" font-weight="600" fill="#14507d" text-anchor="start">1 clock cycle</text>
|
||||
</g>
|
||||
<g inkscape:groupmode="layer" id="layer-3-us" inkscape:label="3 - us band" style="display:inline">
|
||||
<circle cx="34.00" cy="75.00" r="1.3" fill="#14507d"/>
|
||||
<path d="M 34.00,73.00 L 34.00,70.00" stroke="#14507d" stroke-width="0.4" fill="none"/>
|
||||
<text x="34.00" y="68.50" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.2" font-weight="normal" fill="#4a7ba6" text-anchor="middle">1 µs</text>
|
||||
<text x="34.00" y="64.70" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.8" font-weight="600" fill="#14507d" text-anchor="middle">system call</text>
|
||||
<circle cx="54.67" cy="75.00" r="1.3" fill="#14507d"/>
|
||||
<path d="M 54.67,73.00 L 54.67,62.00" stroke="#14507d" stroke-width="0.4" fill="none"/>
|
||||
<text x="54.67" y="60.50" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.2" font-weight="normal" fill="#4a7ba6" text-anchor="middle">2 µs</text>
|
||||
<text x="54.67" y="56.70" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.8" font-weight="600" fill="#14507d" text-anchor="middle">context switch</text>
|
||||
<circle cx="150.66" cy="75.00" r="1.3" fill="#14507d"/>
|
||||
<path d="M 150.66,73.00 L 150.66,70.00" stroke="#14507d" stroke-width="0.4" fill="none"/>
|
||||
<text x="150.66" y="68.50" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.2" font-weight="normal" fill="#4a7ba6" text-anchor="middle">50 µs</text>
|
||||
<text x="150.66" y="64.70" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.8" font-weight="600" fill="#14507d" text-anchor="middle">OS timer slack</text>
|
||||
<path d="M 102.67,79.00 L 135.43,79.00" stroke="#14507d" stroke-width="0.7" fill="none"/>
|
||||
<path d="M 102.67,79.00 L 102.67,75.00" stroke="#14507d" stroke-width="0.7" fill="none"/>
|
||||
<path d="M 135.43,79.00 L 135.43,75.00" stroke="#14507d" stroke-width="0.7" fill="none"/>
|
||||
<text x="119.05" y="82.50" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.2" font-weight="normal" fill="#4a7ba6" text-anchor="middle">10-30 µs</text>
|
||||
<text x="119.05" y="86.20" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.8" font-weight="600" fill="#14507d" text-anchor="middle">thread wake-up</text>
|
||||
<path d="M 150.66,79.00 L 171.33,79.00" stroke="#14507d" stroke-width="0.7" fill="none"/>
|
||||
<path d="M 150.66,79.00 L 150.66,75.00" stroke="#14507d" stroke-width="0.7" fill="none"/>
|
||||
<path d="M 171.33,79.00 L 171.33,75.00" stroke="#14507d" stroke-width="0.7" fill="none"/>
|
||||
<text x="161.00" y="82.50" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.2" font-weight="normal" fill="#4a7ba6" text-anchor="middle">50-100 µs</text>
|
||||
<text x="161.00" y="86.20" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.8" font-weight="600" fill="#14507d" text-anchor="middle">SSD read</text>
|
||||
</g>
|
||||
<g inkscape:groupmode="layer" id="layer-4-ms-machine" inkscape:label="4 - ms band (machine)" style="display:inline">
|
||||
<circle cx="102.67" cy="102.00" r="1.3" fill="#14507d"/>
|
||||
<path d="M 102.67,100.00 L 102.67,97.00" stroke="#14507d" stroke-width="0.4" fill="none"/>
|
||||
<text x="102.67" y="95.50" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.2" font-weight="normal" fill="#4a7ba6" text-anchor="middle">10 ms</text>
|
||||
<text x="102.67" y="91.70" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.8" font-weight="600" fill="#14507d" text-anchor="middle">disk seek</text>
|
||||
<circle cx="144.01" cy="102.00" r="1.3" fill="#14507d"/>
|
||||
<path d="M 144.01,100.00 L 144.01,97.00" stroke="#14507d" stroke-width="0.4" fill="none"/>
|
||||
<text x="144.01" y="95.50" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.2" font-weight="normal" fill="#4a7ba6" text-anchor="middle">40 ms</text>
|
||||
<text x="144.01" y="91.70" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.8" font-weight="600" fill="#14507d" text-anchor="middle">one frame @ 25 fps</text>
|
||||
</g>
|
||||
<g inkscape:groupmode="layer" id="layer-5-ms-human" inkscape:label="5 - ms band (human)" style="display:inline">
|
||||
<circle cx="102.67" cy="102.00" r="1.3" fill="#b4530a"/>
|
||||
<path d="M 102.67,104.00 L 102.67,107.00" stroke="#b4530a" stroke-width="0.4" fill="none"/>
|
||||
<text x="102.67" y="109.50" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.2" font-weight="normal" fill="#c98342" text-anchor="middle">10 ms</text>
|
||||
<text x="102.67" y="113.20" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.8" font-weight="600" fill="#b4530a" text-anchor="middle">barely noticeable</text>
|
||||
<circle cx="171.33" cy="102.00" r="1.3" fill="#b4530a"/>
|
||||
<path d="M 171.33,104.00 L 171.33,107.00" stroke="#b4530a" stroke-width="0.4" fill="none"/>
|
||||
<text x="171.33" y="109.50" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.2" font-weight="normal" fill="#c98342" text-anchor="middle">100 ms</text>
|
||||
<text x="171.33" y="113.20" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.8" font-weight="600" fill="#b4530a" text-anchor="middle">UI feels sluggish</text>
|
||||
</g>
|
||||
<g inkscape:groupmode="layer" id="layer-6-s" inkscape:label="6 - s band (human)" style="display:inline">
|
||||
<circle cx="34.00" cy="120.00" r="1.3" fill="#b4530a"/>
|
||||
<path d="M 34.00,122.00 L 34.00,125.00" stroke="#b4530a" stroke-width="0.4" fill="none"/>
|
||||
<text x="34.00" y="127.50" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.2" font-weight="normal" fill="#c98342" text-anchor="middle">1 s</text>
|
||||
<text x="34.00" y="131.20" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.8" font-weight="600" fill="#b4530a" text-anchor="middle">“it’s thinking…”</text>
|
||||
<circle cx="188.86" cy="120.00" r="1.3" fill="#b4530a"/>
|
||||
<path d="M 188.86,122.00 L 188.86,125.00" stroke="#b4530a" stroke-width="0.4" fill="none"/>
|
||||
<text x="188.86" y="127.50" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.2" font-weight="normal" fill="#c98342" text-anchor="middle">3 min</text>
|
||||
<text x="188.86" y="131.20" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.8" font-weight="600" fill="#b4530a" text-anchor="middle">another coffee</text>
|
||||
<circle cx="236.86" cy="120.00" r="1.3" fill="#b4530a"/>
|
||||
<path d="M 236.86,122.00 L 236.86,125.00" stroke="#b4530a" stroke-width="0.4" fill="none"/>
|
||||
<text x="250.00" y="127.50" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.2" font-weight="normal" fill="#c98342" text-anchor="end">≈ 15 min</text>
|
||||
<text x="250.00" y="131.20" font-family="DejaVu Sans, Verdana, sans-serif" font-size="3.8" font-weight="600" fill="#b4530a" text-anchor="end">go do something else</text>
|
||||
</g>
|
||||
<g inkscape:groupmode="layer" id="layer-7-dim" inkscape:label="7 - dim ns+us (optional)" style="display:none">
|
||||
<rect x="0" y="22" width="254.0" height="67" fill="#ffffff" fill-opacity="0.74"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 23 KiB |
264
FrOSCon26/research/TimeScales.txt
Normal file
264
FrOSCon26/research/TimeScales.txt
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
Time Scales
|
||||
===========
|
||||
:Author: Lumiera Project
|
||||
:toc:
|
||||
|
||||
Anyone reasoning about I/O, threading or real-time media processing eventually
|
||||
needs a feeling for _how long things take_. The trouble is that the relevant
|
||||
durations span more than twelve orders of magnitude -- from a single CPU clock
|
||||
cycle up to the point where a human gives up waiting. Numbers on that scale
|
||||
resist intuition, and so we tend to reason about ``fast'' and ``slow'' without
|
||||
noticing that the two words can be separated by a factor of a million.
|
||||
|
||||
The following table collects the figures that matter in this context. It is
|
||||
meant as a rough orientation, not as a benchmark result.
|
||||
|
||||
NOTE: All values are order-of-magnitude figures for contemporary desktop and
|
||||
laptop x86 hardware. Expect a deviation of 2--3{nbsp}x depending on
|
||||
microarchitecture, memory configuration, kernel version and load. The
|
||||
_ratios_ are the point, not the digits.
|
||||
|
||||
The last column rescales everything by a single constant factor, chosen so
|
||||
that one CPU clock cycle (≙ 0.3{nbsp}ns at 3.3{nbsp}GHz) becomes one second
|
||||
of human time. This is the most effective way we know to convey what a cache
|
||||
miss or a disk seek actually costs from the machine's point of view.
|
||||
|
||||
|
||||
Overview Table
|
||||
--------------
|
||||
|
||||
[width="100%",cols="12%,26%,40%,22%",options="header"]
|
||||
|=========================================================================
|
||||
| Figure | Item | Remarks | Felt as (1{nbsp}cycle{nbsp}≙{nbsp}1{nbsp}s)
|
||||
|
||||
4+^s| Nanoseconds -- inside the CPU
|
||||
|
||||
| 0.3{nbsp}ns | one clock cycle | at 3.3{nbsp}GHz; the machine's own time quantum | *1 second*
|
||||
| ~1{nbsp}ns | L1 cache hit | about 4 cycles, fully pipelined | ≈{nbsp}3 seconds
|
||||
| ~1.5{nbsp}ns | `sfence` | store fence, ≈{nbsp}5 cycles; rarely needed on x86 | ≈{nbsp}5 seconds
|
||||
| ~2.7{nbsp}ns | `lfence` | ≈{nbsp}9 cycles; no ordering semantics on x86 beyond blocking speculation | ≈{nbsp}9 seconds
|
||||
| ~4{nbsp}ns | L2 cache hit | ≈{nbsp}12--15 cycles | ≈{nbsp}13 seconds
|
||||
| ~5{nbsp}ns | `lock add $0,(%rsp)` | the actual `smp_mb()` on Linux; ≈{nbsp}half the cost of `mfence` footnoteref:[lkml,LKML thread "[PATCH 3/4] x86,asm: Re-work smp_store_mb()", Nov 2015. Davidlohr Bueso measures XCHG against MFENCE on Ivy Bridge; Linus Torvalds reports that on Haswell "lock addq" costs pretty much exactly half of MFENCE, and explains that locked operations were the ones CPU designers had reason to optimise -- https://lkml.iu.edu/hypermail/linux/kernel/1511.0/01052.html] | ≈{nbsp}17 seconds
|
||||
| ~5{nbsp}ns | branch misprediction | pipeline refill | ≈{nbsp}17 seconds
|
||||
| ~10{nbsp}ns | `mfence` / full barrier | ≈{nbsp}23--33 cycles; comparable to a `lock`-prefixed RMW footnoteref:[downs,Travis Downs, "A Concurrency Cost Hierarchy", 6 July 2020, see the discussion of "vanilla" versus "non-vanilla" instructions: on x86 plain accesses and non-atomic read-modify-writes are cheap while LOCK-prefixed RMWs are an order of magnitude slower, with MFENCE comparable to a locked instruction -- https://travisdowns.github.io/blog/2020/07/06/concurrency-costs.html] | ≈{nbsp}33 seconds
|
||||
| ~15{nbsp}ns | L3 cache hit | shared, hence variable | ≈{nbsp}50 seconds
|
||||
| ~13{nbsp}ns | DRAM, open row | a plain load that happens to hit an already-activated row footnoteref:[cxl,Measured values in Table III of: Performance Characterizations and Usage Guidelines of Samsung CXL Memory Module Hybrid Prototype, arXiv:2503.22017. Local DDR5 median latency 122.9 ns under Intel MLC pointer chasing versus 13.1 ns for a plain load; methodology (rdtsc, 10 000 repetitions, median) described in section III-C -- https://arxiv.org/pdf/2503.22017] | ≈{nbsp}43 seconds
|
||||
| ~14{nbsp}ns | DRAM, first access | device-level figure; essentially unchanged from DDR4 to DDR5 footnote:[Measurement-oriented analysis of DDR5 sub-channel architecture; the relevant passage is in section "Latency Implications", noting that both DDR4 and DDR5 sit at approximately 14 ns first-access latency at their respective standard speeds. arXiv:2605.08725 -- https://arxiv.org/pdf/2605.08725]
|
||||
| ≈{nbsp}47 seconds
|
||||
| 40--100{nbsp}ns | contended cache line | core-to-core transfer; strongly topology dependent (same CCX / cross CCX / cross socket) | 2--5 minutes
|
||||
| ~100{nbsp}ns | DRAM random access | full miss through the whole hierarchy; 122.9{nbsp}ns measured by pointer chasing on DDR5 footnoteref:[cxl] | *≈{nbsp}5 minutes*
|
||||
|
||||
4+^s| Nanoseconds to microseconds -- entering the kernel
|
||||
|
||||
| ~25{nbsp}ns | syscall via vDSO | not a real trap; almost as cheap as a function call footnoteref:[arkanis,"Measurements of system call performance and overhead", Arkanis Development, 5 Jan 2017 -- compares a plain function call against getpid() issued via the syscall instruction and via the vDSO -- https://arkanis.de/weblog/2017-01-05-measurements-of-system-call-performance-and-overhead/] | ≈{nbsp}1.5 minutes
|
||||
| 70--100{nbsp}ns | syscall trap, bare | `getpid()` on a mitigation-free host footnoteref:[gms,Georg Sauthoff, "On the Costs of Syscalls", 30 Aug 2021. Median of 100 repetitions across a heterogeneous set of hosts; the conclusion is that user-kernel mode switches cost on the order of a few hundred nanoseconds on all hosts, with the fastest host switching modes in under 100 ns, and that the higher figures are explained by CPU-bug mitigations being enabled by default -- https://gms.tf/on-the-costs-of-syscalls.html] | 4--6 minutes
|
||||
| 200--600{nbsp}ns | syscall trap, mitigated | ``a few hundred nanoseconds'' on typical hosts with CPU-bug mitigations enabled footnoteref:[gms] | 11--33 minutes
|
||||
| ~1{nbsp}µs | syscall doing real work | the round figure we use for the diagram | *≈{nbsp}1 hour*
|
||||
| ~2{nbsp}µs | context switch | scheduler plus cold cache on the new task | ≈{nbsp}2 hours
|
||||
|
||||
4+^s| Microseconds -- the operating system
|
||||
|
||||
| 10--30{nbsp}µs | thread wake-up | IRQ handling, `try_to_wake_up()`, scheduling onto a CPU footnoteref:[lkmlwake,Michal Schmidt, reply in the thread "nanosleep() accuracy", linux-kernel mailing list, 17 Aug 2007: the point being that a process always carries non-zero wake-up latency covering interrupt processing, waking and scheduling, and that 10-30 us is not unreasonable -- https://lkml.iu.edu/hypermail/linux/kernel/0708.2/0423.html] | 9{nbsp}hours -- 1{nbsp}day
|
||||
| ~31--57{nbsp}µs | scheduling latency, avg | `cyclictest` at `SCHED_FIFO` 95 with memory locked footnoteref:[rhel,Sample cyclictest output and interpretation in: Finding Realtime Linux Kernel Latencies, Clark Williams (Red Hat), section "Using cyclictest" -- https://people.redhat.com/williams/latency-howto/rt-latency-howto.txt] | 1--2 days
|
||||
| ~59--90{nbsp}µs | scheduling latency, max | same run; the tail is what hurts footnoteref:[rhel] | 2--3.5 days
|
||||
| *50{nbsp}µs* | *OS timer slack, default* | the kernel may delay a timed wake-up by this much, deliberately, to coalesce wakeups footnoteref:[slack,Primary documentation: `man 7 time`, section "High-resolution timers", and `man 2 prctl`, description of PR_SET_TIMERSLACK. The 50 us default for non-realtime threads is stated explicitly in: Metronome -- adaptive and precise intermittent packet retrieval in DPDK, section II (discussion of nanosleep limits), arXiv:2103.13263 -- https://arxiv.org/pdf/2103.13263 ; a practical encounter with the same default, including the /proc interface, is documented in OpenJDK issue JDK-8307766 -- https://bugs.openjdk.org/browse/JDK-8307766] | *≈{nbsp}2 days*
|
||||
| 1{nbsp}ns | OS timer slack, minimum | via `prctl(PR_SET_TIMERSLACK)` or `/proc/PID/timerslack_ns` footnoteref:[slack] | ≈{nbsp}3 seconds
|
||||
| ~9{nbsp}µs | SSD read, best case | Optane / Z-NAND class at QD1 footnoteref:[anand,AnandTech, review of the Samsung 983 ZET (Z-NAND), page 3, "QD1 Random Read Performance" -- explains why queue depth 1 exposes best-case access latency, and reports an average of just under 9 us for an Optane drive against 16 us for the Z-NAND based 983 ZET -- https://at-web1.www.anandtech.com/show/13951/the-samsung-983-zet-znand-ssd-review/3] | ≈{nbsp}8 hours
|
||||
| 20--70{nbsp}µs | NVMe SSD 4K random read | typical contemporary drive footnoteref:[simply,Summary of the storage latency hierarchy: a modern NVMe SSD serves a random 4K read in roughly 20-70 us, a SATA SSD in 100-200 us, and a spinning disk in 5-10 ms. simplyblock glossary entry "NVMe Latency" -- https://simplyblock.io/glossary/nvme-latency/] | 1--3 days
|
||||
| 50--100{nbsp}µs | NVMe SSD, interrupt path | what you see without polling | *2--4 days*
|
||||
| 100--200{nbsp}µs | SATA SSD 4K random read | the interface costs, not just the medium footnoteref:[simply] | 4--8 days
|
||||
| 100{nbsp}µs -- 1{nbsp}ms | deep C-state exit | wake from C6 and below; worse when many cores wake at once | 4{nbsp}days -- 5{nbsp}weeks
|
||||
|
||||
4+^s| Milliseconds -- where machine and human meet
|
||||
|
||||
| 5--10{nbsp}ms | rotating disk, seek + rotation | 7200{nbsp}rpm; the number that has not improved in decades footnoteref:[simply] | *6{nbsp}months -- 1{nbsp}year*
|
||||
| ~10{nbsp}ms | barely noticeable latency | the threshold below which a human stops perceiving delay | ≈{nbsp}1 year
|
||||
| 20{nbsp}ms | one frame @{nbsp}50{nbsp}fps | | ≈{nbsp}2 years
|
||||
| 40{nbsp}ms | one frame @{nbsp}25{nbsp}fps | our actual deadline | *≈{nbsp}4 years*
|
||||
| ~100{nbsp}ms | UI starts to feel sluggish | | ≈{nbsp}11 years
|
||||
|
||||
4+^s| Seconds and beyond -- the human
|
||||
|
||||
| ~1{nbsp}s | ``the software takes time to respond'' | acceptable, but noticed | *≈{nbsp}1 century*
|
||||
| ~3{nbsp}min | ``time for another cup of coffee'' | | ≈{nbsp}19 000 years
|
||||
| ~15{nbsp}min | ``can't wait, I'll do something else'' | ≙{nbsp}1000{nbsp}s, which conveniently closes the fourth decade block | ≈{nbsp}95 000 years
|
||||
|=========================================================================
|
||||
|
||||
|
||||
The Memory Wall
|
||||
---------------
|
||||
|
||||
For roughly two decades, CPU clock rates have hovered around 3{nbsp}GHz while
|
||||
DRAM access latency has stayed near 60--100{nbsp}ns. The consequence is
|
||||
arithmetic: a cache miss that cost a handful of cycles on early-1990s hardware
|
||||
now costs several hundred. The processor did not merely get faster than
|
||||
memory -- it got faster than memory _by a growing margin_, and the entire
|
||||
cache hierarchy exists to paper over that gap. Note in the table above that
|
||||
the raw device-level latency of DDR5 is barely distinguishable from DDR4;
|
||||
the generational improvements went into bandwidth, not into latency.
|
||||
|
||||
Once several cores share one memory subsystem, a single uniform path to memory
|
||||
becomes the bottleneck. The answer was to move the memory controller onto the
|
||||
CPU die and attach memory per socket -- and, with chiplet designs, effectively
|
||||
per die group. This is what NUMA (non-uniform memory access) describes: memory
|
||||
that ``belongs'' to the core you are running on is reached quickly, while
|
||||
memory belonging to a neighbour costs noticeably more. The practical upshot is
|
||||
that thread placement and memory placement are no longer independent concerns,
|
||||
and that a scheduler which migrates a worker between cores may silently convert
|
||||
local accesses into remote ones.
|
||||
|
||||
Cores also keep private caches, and a store performed on one core does not
|
||||
become visible to another core at the moment the instruction retires: it first
|
||||
lands in that core's store buffer. Cache coherence guarantees that the cores
|
||||
eventually agree on the content of a cache line, but it says nothing about
|
||||
_when_, nor about the order in which several independent writes become visible.
|
||||
This is what memory fences are for -- they constrain the order, and thereby
|
||||
allow one core to reason about what an adjacent core has already done. The cost
|
||||
shows up in the table twice: an uncontended fence is roughly the price of an
|
||||
L3 hit, whereas a cache line actually bouncing between two cores costs about as
|
||||
much as going to DRAM. It is worth internalising that the expensive part is
|
||||
usually not the synchronisation primitive itself, but the coherence traffic it
|
||||
provokes.
|
||||
|
||||
x86 implements a comparatively strong model, _Total Store Order_ (TSO): of the
|
||||
four possible reorderings, only StoreLoad is permitted. Acquire and release
|
||||
semantics are therefore free on x86 -- they compile to plain `MOV` -- and only
|
||||
sequential consistency requires an actual instruction. ARM and POWER are
|
||||
weakly ordered and consequently offer a more differentiated set of barriers:
|
||||
ARM distinguishes `DMB` from the heavier `DSB`, and provides graded load
|
||||
acquire flavours such as `LDAR` and `LDAPR`; POWER separates the heavyweight
|
||||
`sync` from the cheaper `lwsync`. The trap for the unwary is that C++
|
||||
`memory_order` distinctions which cost nothing on x86 have a real price on
|
||||
ARM -- and, worse, that under-synchronised code can appear perfectly correct
|
||||
on x86 and fail on ARM.
|
||||
|
||||
|
||||
Crossing into the Kernel
|
||||
------------------------
|
||||
|
||||
A system call is not a function call: it is a controlled trap. The `syscall`
|
||||
instruction switches the processor to privilege level 0, and the kernel entry
|
||||
path then swaps to the kernel `GS` base, switches stacks, and saves the user
|
||||
register state. Since the Meltdown/Spectre family of vulnerabilities, that
|
||||
sequence also includes a page-table switch (KPTI writes `CR3`, with the
|
||||
attendant TLB consequences) and one or more branch-prediction barriers --
|
||||
retpolines, IBPB or IBRS depending on hardware and configuration. On return,
|
||||
the whole dance runs in reverse.
|
||||
|
||||
The direct cost is measurable: a minimal syscall such as `getpid()` amounts to
|
||||
little more than two mode switches, and lands in the region of a hundred
|
||||
nanoseconds on a fast host without mitigations, rising to several hundred once
|
||||
mitigations are enabled.footnoteref:[gms] The indirect cost is harder to see
|
||||
and frequently larger. Kernel entry code and the syscall handler evict
|
||||
user-space data from L1 and L2, and disturb the branch predictors; the
|
||||
application resumes with a cold working set and pays for it in misses that no
|
||||
syscall benchmark will attribute to the syscall. This is precisely why the
|
||||
interesting question is rarely ``how expensive is one syscall'' but rather
|
||||
``how many syscalls does this design require per unit of work'' -- which is
|
||||
the question `io_uring` was built to answer.
|
||||
|
||||
|
||||
Operating System Slack
|
||||
----------------------
|
||||
|
||||
A thread that asks to sleep for a specific duration will not, in general, wake
|
||||
at that instant. Part of this is unavoidable: an interrupt must be handled, the
|
||||
sleeping task must be moved to the run queue, and the scheduler must actually
|
||||
place it on a CPU, which together account for something in the range of
|
||||
10--30{nbsp}µs.footnoteref:[lkmlwake]
|
||||
|
||||
The larger part, however, is deliberate. Linux maintains a per-thread _timer
|
||||
slack_ value, and the kernel is free to delay a timed wake-up by up to that
|
||||
amount in order to coalesce several wake-ups into one and thereby let the CPU
|
||||
stay in a low-power state longer. For every thread not running under a
|
||||
real-time scheduling policy, the default is 50{nbsp}µs.footnoteref:[slack]
|
||||
This is not imprecision; it is a power-versus-precision trade that the kernel
|
||||
makes on the application's behalf, and it can be adjusted -- down to
|
||||
1{nbsp}ns -- via `prctl(PR_SET_TIMERSLACK)` or the per-process
|
||||
`/proc/PID/timerslack_ns` interface.
|
||||
|
||||
The distinction worth carrying away is between _resolution_ and _accuracy_.
|
||||
Since Linux 2.6.21 the high-resolution timer subsystem reports nanosecond
|
||||
resolution, and `clock_getres()` will happily confirm it. The accuracy with
|
||||
which a `nanosleep()` actually returns is a different quantity altogether, two
|
||||
to three orders of magnitude coarser, and dominated by slack, wake-up latency
|
||||
and -- if the core had gone idle -- C-state exit time. Any design that assumes
|
||||
it can steer a worker thread with microsecond-scale sleeps should be checked
|
||||
against these figures first.
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Footnote definitions are attached at first use above via footnoteref.
|
||||
// Repeated references reuse the id; see AsciiDoc footnoteref macro.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Sources
|
||||
-------
|
||||
|
||||
The footnotes above carry the precise locations. Collected here as a reading
|
||||
list, roughly in order of usefulness for further work.
|
||||
|
||||
- Travis Downs, *A Concurrency Cost Hierarchy* --
|
||||
https://travisdowns.github.io/blog/2020/07/06/concurrency-costs.html +
|
||||
The best single entry point on why synchronisation costs what it costs.
|
||||
|
||||
- LKML thread, *[PATCH 3/4] x86,asm: Re-work smp_store_mb()* (Nov 2015) --
|
||||
https://lkml.iu.edu/hypermail/linux/kernel/1511.0/01052.html +
|
||||
Kernel developers measuring `MFENCE` against `XCHG` and `lock addq`.
|
||||
|
||||
- Georg Sauthoff, *On the Costs of Syscalls* (Aug 2021) --
|
||||
https://gms.tf/on-the-costs-of-syscalls.html +
|
||||
Careful cross-host microbenchmark of the mode-switch cost.
|
||||
|
||||
- *Measurements of system call performance and overhead* (Jan 2017) --
|
||||
https://arkanis.de/weblog/2017-01-05-measurements-of-system-call-performance-and-overhead/ +
|
||||
Function call versus `syscall` instruction versus vDSO.
|
||||
|
||||
- Brendan Gregg, *KPTI/KAISER Meltdown Initial Performance Regressions* --
|
||||
https://www.brendangregg.com/blog/2018-02-09/kpti-kaiser-meltdown-performance.html +
|
||||
Relates mitigation overhead to syscall rate, context switch rate and working
|
||||
set size -- the systemic view rather than the per-call view.
|
||||
|
||||
- Clark Williams (Red Hat), *Finding Realtime Linux Kernel Latencies* --
|
||||
https://people.redhat.com/williams/latency-howto/rt-latency-howto.txt +
|
||||
Walks through a `cyclictest` run and how to read its output.
|
||||
|
||||
- `man 7 time` and `man 2 prctl` (PR_SET_TIMERSLACK) +
|
||||
Primary documentation for timer slack. The 50{nbsp}µs default is stated in
|
||||
https://arxiv.org/pdf/2103.13263 (Metronome, DPDK packet retrieval) and
|
||||
encountered in practice in https://bugs.openjdk.org/browse/JDK-8307766
|
||||
|
||||
- *Performance Characterizations ... Samsung CXL Memory Module Hybrid
|
||||
Prototype*, arXiv:2503.22017 -- https://arxiv.org/pdf/2503.22017 +
|
||||
Table III contains a well-documented measurement of plain local DDR5.
|
||||
|
||||
- *Single 32-bit Sub-Channel DDR5 DIMMs*, arXiv:2605.08725 --
|
||||
https://arxiv.org/pdf/2605.08725 +
|
||||
Useful for the point that DDR5 did not improve absolute latency over DDR4.
|
||||
|
||||
- simplyblock glossary, *NVMe Latency* --
|
||||
https://simplyblock.io/glossary/nvme-latency/ +
|
||||
Compact summary of the NVMe / SATA SSD / rotating disk hierarchy.
|
||||
|
||||
- AnandTech, *Samsung 983 ZET (Z-NAND) review*, page 3 --
|
||||
https://at-web1.www.anandtech.com/show/13951/the-samsung-983-zet-znand-ssd-review/3 +
|
||||
Explains why queue depth 1 exposes best-case access latency.
|
||||
|
||||
|
||||
A Note on Microbenchmarks
|
||||
-------------------------
|
||||
|
||||
One caveat deserves to be stated separately, because it explains why published
|
||||
figures for synchronisation primitives vary so wildly. A hot microbenchmark
|
||||
keeps every thread runnable and every core out of idle by construction. Under
|
||||
those conditions an uncontended atomic operation or a mutex acquisition costs
|
||||
single-digit to low-three-digit nanoseconds, and a benchmark will faithfully
|
||||
report that. What such a benchmark structurally cannot observe is the cost of
|
||||
_blocking_ -- of a thread actually parking and later being woken -- because
|
||||
pressing the benchmark is precisely what prevents that from happening.
|
||||
|
||||
The instruction-level cost of a synchronisation primitive is what a hot
|
||||
microbenchmark measures. Its systemic cost -- coherence traffic under
|
||||
contention, and blocking and wake-up latency when it is not contended -- is
|
||||
what production tail latency measures. The two can differ by two to four orders
|
||||
of magnitude, and the table above spans both regimes for exactly that reason.
|
||||
244
FrOSCon26/research/core2core.cpp
Normal file
244
FrOSCon26/research/core2core.cpp
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
* core2core.cpp — measure core-to-core latency by cache-line ping-pong.
|
||||
*
|
||||
* Code generated 8/2026 by Claude -- prompted by Ichthyostega
|
||||
* Context: FrOSCon-26 talk on IO_URING
|
||||
*
|
||||
* Two threads are pinned to two specific logical CPUs and share a single
|
||||
* cache line holding two atomic counters. Thread A stores i, then spins
|
||||
* until thread B has answered with i; thread B does the mirror image.
|
||||
* Each round trip therefore forces the line to migrate twice: A -> B and
|
||||
* back. The one-way latency reported is half the measured round trip.
|
||||
*
|
||||
* What this actually measures is the cost of a *contended* cache line —
|
||||
* the coherence traffic, not the atomic instruction. An uncontended
|
||||
* atomic on a line already held in M state costs a couple of nanoseconds;
|
||||
* the numbers here are one to two orders of magnitude larger, and that
|
||||
* difference is the whole point.
|
||||
*
|
||||
* build: g++ -O2 -std=c++17 -pthread -o core2core core2core.cpp
|
||||
* run: ./core2core # full matrix over all allowed CPUs
|
||||
* ./core2core 3 9 # just the pair (3,9)
|
||||
*
|
||||
* Linux only (uses pthread_setaffinity_np / sched_getaffinity).
|
||||
*
|
||||
* Reading the results
|
||||
* -------------------
|
||||
* * SMT siblings of one physical core: lowest of all, often 5–20 ns.
|
||||
* They share L1/L2, so almost nothing migrates. Cross-check which
|
||||
* CPUs are siblings with lscpu -e or lscpu -p=CPU,CORE,SOCKET.
|
||||
* * Cores on the same die / CCX / cluster: typically 25–50 ns.
|
||||
* * Across an AMD CCX or CCD boundary, or across sockets: 70–150 ns
|
||||
* and upwards. On a multi-socket machine the cross-socket figure
|
||||
* can exceed local DRAM latency.
|
||||
*
|
||||
* Getting numbers you can trust
|
||||
* -----------------------------
|
||||
* * Set the CPU governor to performance; on an idle laptop the cores
|
||||
* will otherwise be clocked down and the figures inflate.
|
||||
* sudo cpupower frequency-set -g performance
|
||||
* * Run on an otherwise idle machine. The tool reports the minimum
|
||||
* over several repetitions, which filters most interference, but it
|
||||
* cannot filter a busy system.
|
||||
* * Do not read more than two significant digits into the result.
|
||||
*/
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr std::size_t CACHELINE = 64; // deliberately hard-coded; see note below
|
||||
|
||||
/** the two counters live in one cache line, so a store by either side
|
||||
* invalidates the other side's copy. `alignas` keeps neighbouring data
|
||||
* out of that line, so we measure our own ping-pong and nothing else. */
|
||||
struct alignas(CACHELINE) PingPong
|
||||
{
|
||||
std::atomic<std::uint64_t> a{0};
|
||||
std::atomic<std::uint64_t> b{0};
|
||||
char pad[CACHELINE - 2 * sizeof(std::atomic<std::uint64_t>)]{};
|
||||
};
|
||||
|
||||
static_assert (sizeof(PingPong) == CACHELINE, "PingPong must occupy exactly one line");
|
||||
|
||||
|
||||
bool pin_to (int cpu)
|
||||
{
|
||||
cpu_set_t set;
|
||||
CPU_ZERO (&set);
|
||||
CPU_SET (cpu, &set);
|
||||
return 0 == pthread_setaffinity_np (pthread_self(), sizeof(set), &set);
|
||||
}
|
||||
|
||||
|
||||
std::vector<int> available_cpus()
|
||||
{
|
||||
std::vector<int> cpus;
|
||||
cpu_set_t set;
|
||||
CPU_ZERO (&set);
|
||||
if (0 == sched_getaffinity (0, sizeof(set), &set))
|
||||
for (int i = 0; i < CPU_SETSIZE; ++i)
|
||||
if (CPU_ISSET (i, &set))
|
||||
cpus.push_back (i);
|
||||
return cpus;
|
||||
}
|
||||
|
||||
|
||||
/** one ping-pong run between two pinned threads.
|
||||
* @return round-trip time per iteration in nanoseconds, or -1 on failure */
|
||||
double one_run (PingPong& pp, int cpuA, int cpuB,
|
||||
std::uint64_t warmup, std::uint64_t iters)
|
||||
{
|
||||
using Clock = std::chrono::steady_clock;
|
||||
|
||||
pp.a.store (0, std::memory_order_relaxed);
|
||||
pp.b.store (0, std::memory_order_relaxed);
|
||||
|
||||
std::atomic<int> ready {0};
|
||||
std::atomic<bool> go {false};
|
||||
std::atomic<bool> ok {true};
|
||||
|
||||
const std::uint64_t total = warmup + iters;
|
||||
|
||||
std::thread responder{[&]
|
||||
{
|
||||
if (not pin_to (cpuB)) { ok.store (false); }
|
||||
ready.fetch_add (1, std::memory_order_release);
|
||||
while (not go.load (std::memory_order_acquire))
|
||||
;
|
||||
for (std::uint64_t i = 1; i <= total; ++i)
|
||||
{
|
||||
while (pp.a.load (std::memory_order_acquire) != i)
|
||||
;
|
||||
pp.b.store (i, std::memory_order_release);
|
||||
}
|
||||
}};
|
||||
|
||||
Clock::time_point t0, t1;
|
||||
|
||||
std::thread initiator{[&]
|
||||
{
|
||||
if (not pin_to (cpuA)) { ok.store (false); }
|
||||
ready.fetch_add (1, std::memory_order_release);
|
||||
while (not go.load (std::memory_order_acquire))
|
||||
;
|
||||
for (std::uint64_t i = 1; i <= total; ++i)
|
||||
{
|
||||
if (i == warmup + 1) // caches and predictors are warm now
|
||||
t0 = Clock::now();
|
||||
pp.a.store (i, std::memory_order_release);
|
||||
while (pp.b.load (std::memory_order_acquire) != i)
|
||||
;
|
||||
}
|
||||
t1 = Clock::now();
|
||||
}};
|
||||
|
||||
while (ready.load (std::memory_order_acquire) < 2)
|
||||
;
|
||||
go.store (true, std::memory_order_release);
|
||||
|
||||
initiator.join();
|
||||
responder.join();
|
||||
|
||||
if (not ok.load())
|
||||
return -1.0;
|
||||
|
||||
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds> (t1 - t0);
|
||||
return double(elapsed.count()) / double(iters);
|
||||
}
|
||||
|
||||
|
||||
/** @return best (minimum) one-way latency in ns over @p reps repetitions */
|
||||
double measure_pair (int cpuA, int cpuB, int reps,
|
||||
std::uint64_t warmup, std::uint64_t iters)
|
||||
{
|
||||
PingPong pp;
|
||||
double best = std::numeric_limits<double>::infinity();
|
||||
for (int r = 0; r < reps; ++r)
|
||||
{
|
||||
double rtt = one_run (pp, cpuA, cpuB, warmup, iters);
|
||||
if (rtt < 0) return -1.0;
|
||||
if (rtt < best) best = rtt;
|
||||
}
|
||||
return best / 2.0; // round trip covers two line migrations
|
||||
}
|
||||
|
||||
} // namespace (anon)
|
||||
|
||||
|
||||
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
constexpr int REPS = 5;
|
||||
constexpr std::uint64_t WARMUP = 2000;
|
||||
constexpr std::uint64_t ITERS = 20000;
|
||||
|
||||
if (argc == 3)
|
||||
{ // single pair
|
||||
int a = std::atoi (argv[1]);
|
||||
int b = std::atoi (argv[2]);
|
||||
if (a == b)
|
||||
{
|
||||
std::fprintf (stderr, "the two CPUs must differ "
|
||||
"(both threads spin, they cannot share one core)\n");
|
||||
return 1;
|
||||
}
|
||||
double ns = measure_pair (a, b, REPS, WARMUP, ITERS);
|
||||
if (ns < 0)
|
||||
{
|
||||
std::fprintf (stderr, "could not pin to CPU %d / %d\n", a, b);
|
||||
return 1;
|
||||
}
|
||||
std::printf ("CPU %d <-> CPU %d : %.1f ns one-way (%.1f ns round trip)\n",
|
||||
a, b, ns, 2 * ns);
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto cpus = available_cpus();
|
||||
if (cpus.size() < 2)
|
||||
{
|
||||
std::fprintf (stderr,
|
||||
"need at least two available CPUs, found %zu.\n"
|
||||
"(inside a restricted container, check the cpuset)\n",
|
||||
cpus.size());
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::printf ("core-to-core latency, one-way, nanoseconds\n");
|
||||
std::printf ("minimum of %d runs x %llu iterations; %zu CPUs available\n\n",
|
||||
REPS, (unsigned long long)ITERS, cpus.size());
|
||||
|
||||
// header
|
||||
std::printf (" ");
|
||||
for (std::size_t j = 0; j + 1 < cpus.size(); ++j)
|
||||
std::printf ("%6d", cpus[j]);
|
||||
std::printf ("\n");
|
||||
|
||||
for (std::size_t i = 1; i < cpus.size(); ++i)
|
||||
{
|
||||
std::printf ("%5d ", cpus[i]);
|
||||
for (std::size_t j = 0; j < i; ++j)
|
||||
{
|
||||
double ns = measure_pair (cpus[i], cpus[j], REPS, WARMUP, ITERS);
|
||||
if (ns < 0) std::printf (" -");
|
||||
else std::printf ("%6.0f", ns);
|
||||
std::fflush (stdout);
|
||||
}
|
||||
std::printf ("\n");
|
||||
}
|
||||
|
||||
std::printf ("\nlowest values are usually SMT siblings; check with lscpu -e\n");
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in a new issue