apple-design · diagram galleryapple-design · 图示案例库

Quiet diagrams. One blue. 安静的图,一处蓝。

Fourteen hand-built SVG figures in the apple-design language. Grayscale carries the structure; a single blue carries the story. Every figure answers one question first — where does the blue go — then everything else stays out of the way. Copy any of them. 十四张手工 SVG 图。灰阶承担结构,唯一的蓝色承担叙事。每张图先回答一个问题——蓝给谁——其余一切退后。每张都可直接复制。

Structure & flow 结构与流程

Architecture, orchestration, pipelines. Depth comes from soft shadows, never borders; the blue path is the one you are meant to follow. 架构、编排、流水线。层次靠柔影而不是边框;蓝色路径就是你该跟随的那条。

Presentation Services Data 1 2 Views Declarative UI Routing Deep links State Observable models Cache Edge & memory API client REST & GraphQL Auth Tokens & sessions Object store Media & backups Database Postgres cluster Queue Background jobs
Architecture · layers架构 · 分层 Four layers in soft-gray groups, white cards floating on shadows. Template: templates/diagrams/architecture.svg. 四层结构用浅灰分组,白卡靠柔影浮起。模板:templates/diagrams/architecture.svg
Coordinator plans · delegates · merges Search worker 1 · web Search worker 2 · docs Analyse worker 3 · data Analyse worker 4 · code
Hierarchy · orchestration层级 · 编排 One coordinator, four workers; the blue stroke marks the only focus card. Template: templates/diagrams/hierarchy.svg. 一个协调者四个 worker;蓝描边标出唯一的焦点卡。模板:templates/diagrams/hierarchy.svg
yes no · back-order In stock? Order Validate Charge Ship 1 2 3 4
Flow · decision流程 · 决策 Blue happy path, gray fail loop, one tinted diamond. Template: templates/diagrams/flow.svg. 蓝色主路径、灰色失败回流、唯一的 tint 菱形。模板:templates/diagrams/flow.svg
mydev_probe(pdev) return 0 devm_kzalloc ctx, GFP_KERNEL ioremap registers MMIO resource 0 request_irq mydev_isr handler register chardev cdev_add, fops ctx == NULL? IS_ERR(base)? ret < 0? no no no yes · -ENOMEM yes · PTR_ERR(base) yes · ret return -errno devm_* resources auto-freed 1 2 3 4
Function flowchart · error lanes函数流程图 · 错误车道 A driver probe() top to bottom in blue; error handling steps aside into a gray lane and shares one exit. Template: templates/diagrams/function-flowchart.svg. 驱动 probe() 从上到下走蓝色;错误处理让到灰色车道,共享一个出口。模板:templates/diagrams/function-flowchart.svg
make dtbs · runs in parallel .config + Kconfig gcc -c *.o ld vmlinux objcopy Image.gz *.dts dtc *.dtb mkimage FIT boot.itb build configuration compile per-TU object files ELF + symbols strip to binary compressed kernel board source devicetree compiler flattened blob kernel + dtb pack bootable FIT image 1 2 3 4
Build · pipeline编译 · 流程链 Kernel build from .config to boot.itb; the devicetree branch joins quietly in gray, the deliverable wears the blue stroke. Template: templates/diagrams/build-pipeline.svg. 内核编译从 .config 到 boot.itb;设备树分支以灰色安静汇入,交付物戴上蓝描边。模板:templates/diagrams/build-pipeline.svg
Edge anycast · 12 PoPs App cluster auto-scale 2–8 nodes Data encrypted at rest dispatch ×3 ×5 1 2 CDN WAF Load balancer api worker scheduler Postgres 16 Redis Object store edge cache · 98% hit rules v34 least-conn REST + SSE queue consumer cron + retries primary + replica queues · cache artifacts
Deployment · topology部署 · 拓扑 Three zones in flat gray; the blue is spent once, on the request path — load balancer into the api focus card, then down to Postgres. Replica counts sit in quiet gray chips. Template: templates/diagrams/deployment.svg. 三个区域全是平灰;蓝色只花一次,给请求主路径——负载均衡器进 api 焦点卡,再落到 Postgres。副本数装在安静的灰 chip 里。模板:templates/diagrams/deployment.svg

Hardware 硬件

Registers, SoC blocks, bus waveforms. Where anthropic spends hues, apple spends gray values — and the datasheet reads cleaner for it. 寄存器、SoC 框图、总线波形。anthropic 用色相的地方,apple 用灰阶——数据手册反而更清爽。

CPU subsystem Clock & reset Memory High-speed I/O Low-speed I/O clk · rst 1 2 3 Cortex-A55 ×2 L2 cache 512K GIC-600 PLL ×3 CRU AXI NoC · 64-bit @ 800 MHz APB bridge DDR4 ctrl + PHY PCIe Gen3 ×2 UART ×4 I2C ×3 SRAM 256K Boot ROM USB 3.0 GbE MAC SPI ×2 GPIO L1 32K I/D per core unified · ECC interrupt distributor core · ddr · peri gate · soft reset system interconnect · QoS arbitration · 4 masters AXI-to-APB · 100 MHz DDR4-3200 · 32-bit + ECC root complex · MSI-X 16550A-compat 400 kHz Fast-mode on-chip scratch 64K mask ROM xHCI dual-role RGMII · TSO mode 0-3 · DMA 4 banks ×32
SoC · block diagramSoC · 内部框图 Subsystems as borderless gray groups; one blue path traces CPU through the NoC to DDR. Template: templates/diagrams/soc-block.svg. 子系统是无边框灰组;唯一的蓝色路径从 CPU 经 NoC 到 DDR。模板:templates/diagrams/soc-block.svg
Multi-die interconnect and address map window onto the other space direct ld / st path Node 0 · socket one coherent domain Node 1 · socket one coherent domain DDR5 Host CPU die Accelerator die DDR5 Host CPU die Accelerator die 512 GB 64 core · 2.4 GHz 96 GB HBM3 · on-package 512 GB 64 core · 2.4 GHz 96 GB HBM3 · on-package DDR5 · 8 ch DDR5 · 8 ch CXL 3.0 · 64 GB/s CXL 3.0 · 64 GB/s fabric · 400 GB/s fabric · 400 GB/s Fabric switch 8 port · non-blocking CPU core · ld / st Accel core · ld / st Host physical address space Device physical address space DDR5 · 512 GB Accel HBM window MMIO 0x0000_0000 0x80_0000_0000 HBM3 · 96 GB Host DDR window reserved 0x0000_0000 0x18_0000_0000 CXL.mem · HDM decoder
interconnect · address map互连拓扑 · 地址空间映射 Topology above, one address space per viewpoint below, and a single blue path carrying the whole point: a CPU core reaches the hatched accelerator window with a plain store, so a pointer crosses without a copy. The accelerator reaches host DDR the same way — grey, because a page has one focus. The two strips never merge: the same DRAM is 0x80_0000_0000 to the host and 0x18_0000_0000 to the device. Segment widths are not to scale. Template: templates/diagrams/interconnect-map.svg. 上半是拓扑,下半是每个视角各一条地址空间,唯一那条蓝线就是全图的结论:CPU 核用一条普通 store 就写得到斜纹那一段,指针可以直接递过去,不用拷贝。加速器访问 host DDR 走的是同一个机制——画成灰的,因为一页只留一个焦点。两条带永不合并:同一块 DRAM 在 host 眼里是 0x80_0000_0000,在设备眼里是 0x18_0000_0000。段宽不按比例。模板:templates/diagrams/interconnect-map.svg
Protocol layering · peer view peer agreement · no wire the only real wire this transfer Transaction layer Transaction layer Data link layer Data link layer Physical layer Physical layer TLP generator builds header + payload Flow control credit based TLP parser decodes header Flow control returns credits Seq num + LCRC one per packet Replay buffer holds until ACK LCRC check drops on mismatch ACK / NAK gen a DLLP, never a TLP 128b/130b + scrambler block sync TX driver differential pair Descrambler + decode recovers symbols RX equalizer CDR + de-emphasis requester completer TLP · end to end DLLP · hop by hop no line here either the real one runs below PCIe lane ×4 · 32 GT/s 1 2 3 4 5 6
protocol layering · peer view协议分层 · 对等视角 The two grey dashed lines are agreements, not wires — nothing carries a TLP from one transaction layer straight to the other. Dashes are reserved here for exactly that: a connection that does not exist. The only solid horizontal line is the lane along the bottom, and the blue path numbered 1 to 6 is the one transfer this page is about: down every layer, across once, up every layer. That is why an analyser taps the lane and never the transaction layer. Template: templates/diagrams/protocol-stack.svg. 两条灰虚线是约定,不是线 —— 没有任何东西把 TLP 从一侧的传输层直接送到另一侧。虚线在这里正是留给"根本不存在的那条连接"。全图唯一一条横向实线是最底下那根 lane;蓝色那条编号 1→6 的路径,是这一页要讲的这一笔传输:一层层下去,过一次线,再一层层上来。协议分析仪只能挂在 lane 上、挂不到传输层,原因就在这张图里。模板:templates/diagrams/protocol-stack.svg
Address map · two viewpoints not DRAM direct mapping reclaim · this remap PCIe MMIO · 64-bit BAR windows of every device DRAM · reclaimed the gigabyte that was shadowed DRAM · direct 12 GiB MMIO hole PCI · LAPIC · IOAPIC · flash DRAM · direct 3 GiB, legacy region at the bottom DRAM 4 – 16 GiB reachable at its own address DRAM 3 – 4 GiB shadowed by the hole — needs a remap DRAM 0 – 3 GiB reachable at its own address System physical DIMM physical · 16 GiB total 0x40_0000_0000 TOUUD 0x4_4000_0000 REMAPBASE 0x4_0000_0000 0x1_0000_0000 TOLUD 0xC000_0000 0x0000_0000 TOM 16G 4G 3G 0x0 direct direct reclaim · same DRAM segment heights are not to scale · low addresses at the bottom
address map · two viewpoints地址映射 · 两个视角 Every boundary gets its own leader line, because a boundary is an address while a region is a range — write 4 GiB inside a region and start, end and size all stay readable. Symbol names are set bold, literal constants monospace: TOLUD is a name, 0xC000_0000 is only what it equals on this board. Blue goes to one thing — the remap and the two segments it joins: the gigabyte shadowed by the MMIO hole reappears above TOUUD, same DRAM, a second address. Heights are not to scale; low addresses at the bottom. Template: templates/diagrams/address-map.svg. 每条边界各拉一条引线,因为边界是一个地址、区域是一段范围 —— 把 4 GiB 写在某段中间,起点 / 终点 / 大小三种读法都成立。符号名用粗体,字面常量用等宽:TOLUD 是名字,0xC000_0000 只是它在这块板上等于多少。蓝色只给一件事 —— 那条重映射线和它连起的两段:被 MMIO 空洞盖住的那 1 GiB,在 TOUUD 之上重新露面,同一块 DRAM,第二个门牌号。高度不按比例,低地址在下。模板:templates/diagrams/address-map.svg
Glyph sheet · copy one <g> at a time Queue finite depth, in order Byte stream serialized bytes, not addresses Slots a place something plugs into Port tab an interface owned by this die Device card pluggable board · model text, no logo AC coupling a capacitor, not “isolation” Sync clock-domain crossing only Hatch a window onto another space out in TLP header + payload PCIe ×16 slots Host CPU die 64 core IMC 200 GbE NIC 2 × QSFP56 D+ D− sync clk A clk B BAR0 window
glyph sheet构件字形集 A rounded rectangle can stand for anything, so on its own it says nothing. Each glyph here is a noun with one fixed meaning: comb teeth promise a bounded in-order queue, ruler ticks promise serialized bytes, a tab straddling a boundary promises the interface belongs to that die. Draw one where the thing is not actually there and the figure states something false. Blue marks the one live state per glyph — the write pointer, the populated slot, the link LED. Vendor logos stay out: model text keeps the file editable. Template: templates/diagrams/glyphs.svg. 一个圆角矩形能代表任何东西,所以它单独出现时什么也没说。这里每个字形都是一个意义固定的名词:梳齿承诺"深度有限、按序进出",尺状刻度承诺"这是被序列化的字节",骑在边界上的小标签承诺"这个接口属于这块 die"。在没有那样东西的地方画上它,就是在图上写了一句假话。蓝色每个字形只点一处"活着"的状态 —— 写指针、插了卡的那个槽、link 起来的 LED。厂商 logo 一律不进:写型号文字,文件才改得动。模板:templates/diagrams/glyphs.svg
UART_CTRL offset 0x04 · reset 0x0010_0301 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 BAUD_DIV PARITY STOP DATA8 FIFO_TH RX_EN TX_EN BAUD_DIV FIFO_TH TX_EN / RX_EN RW RW RW baud = clk / (16 · div) — divisor sampled at frame start, write while TX_EN = 0 TX_IRQ asserts when FIFO fill level drops below threshold (0–15 entries) transmit / receive enables — reset 0x0301 starts TX only, driver sets RX_EN at probe
Register · bit fields寄存器 · 位域 Hairline bit lattice, fields in two gray values, and the enable bits — the ones you actually flip — in blue. Template: templates/diagrams/register-bitfield.svg. 细线位格,字段用两档灰区分,真正要翻的使能位给蓝色。模板:templates/diagrams/register-bitfield.svg
SPI mode 0 · CPOL=0 CPHA=0 · clocks elided MX25L6433F flash · JEDEC ID read (0x9F) command phase · MOSI drives data phase · MISO drives SCLK CS_N MOSI MISO 0x9F 0x00 0xC2 0x20 tCSS tSU ≥ 5 ns t0 t1 t2 t3 t4 t5 t6 t7 t8 data-valid window high-Z (not driven) sampling edge · SCLK rising transfer window · CS_N low SCLK 25 MHz · bit period 40 ns
Waveform · bus timing波形 · 总线时序 An SPI transaction with data lanes in three grays; chip-select is blue because the transfer window is the story. Template: templates/diagrams/hw-timing-waveform.svg. SPI 传输,数据信号用三档灰;片选给蓝色——传输窗口才是叙事主角。模板:templates/diagrams/hw-timing-waveform.svg

Silicon & code 芯片与代码

Seven figures for what is inside the package and what the code's data points at. Grayscale carries the structure; the one blue is spent on whatever the figure is actually about — the address windows here, the traced request there. Never on both. 七张图,画封装里面长什么样、代码里的数据指向哪。结构交给灰阶;唯一的蓝留给这张图真正要讲的那一样——这里是地址窗口,那里是被追踪的那次访问。不会两样都给。

SYSTEM TOPOLOGY · PCIe HIERARCHY OVER ITS ADDRESS SPACE DRAM device MMIO window owns this BAR DDR4 · 2 DIMM DDR4 · 2 DIMM ch0 · 3200 MT/s ch1 · 3200 MT/s ch2 · 3200 MT/s ch3 · 3200 MT/s SoC PACKAGE one coherent domain IMC IMC Core 0Core 1 Core 2Core 3 ROOT COMPLEX · BUS 00 RP0 · 00:1c.0 RP1 · 00:1c.4 RP2 · 00:1d.0 Gen4 x4 · BUS 01 Gen4 x8 · BUS 02 Gen3 x1 · BUS 06 x4 · BUS 03 x4 · BUS 04 PCIe SWITCH 1 upstream · 2 downstream · BUS 02 NVMe SSDAccelerator GPUNetwork 01:00.0 · BAR0 16 KiB 03:00.0 · BAR0 256 MiB 04:00.0 · BAR0 512 MiB 06:00.0 · BAR0 128 KiB DRAM · 0 – 2 GiB nvme accel gpu nic DRAM · 4 GiB and up 0x0000_0000 PCI MMIO window · 32-bit 0x1_0000_0000 not to scale
system topology · address windows板级拓扑 · 地址窗口 The PCIe tree and the physical address space in one frame. Every wire carries its link width and bus number, every device card its BDF and BAR size, and a dashed leader drops from each card onto its own segment of the bar. Split these into two figures and the reader has to hold the mapping in their head — which is exactly the part that goes wrong. Template: templates/diagrams/system-topology.svg. PCIe 树和物理地址空间画在同一张图里。每根线标接口宽度和总线号,每张设备卡标 BDF 和 BAR 大小,虚线引线从卡落到地址条上属于它的那一段。拆成两张图,读者就得自己在脑子里做这个映射——而出错的恰恰是这一步。模板:templates/diagrams/system-topology.svg
DIE FLOORPLAN · TILE MESH core cache slice IO tile mesh · ring stop this request UPI ×20 2 links · 10.4 GT/s PCIe ×16 Gen5 · 32 GT/s DMI ×8 to PCH PCIe ×16 Gen5 · 32 GT/s CHA · LLC 3 MiB Core 0 CHA · LLC 3 MiB Core 1 CHA · LLC 2 MiB Core 2 CHA · LLC 3 MiB Core 3 CHA · LLC 2 MiB Core 4 CHA · LLC 2 MiB Core 5 CHA · LLC 3 MiB Core 6 CHA · LLC 3 MiB Core 7 CHA · LLC 2 MiB Core 8 CHA · LLC 3 MiB Core 9 CHA · LLC 3 MiB Core 10 CHA · LLC 2 MiB Core 11 CHA · LLC 3 MiB Core 12 CHA · LLC 3 MiB Core 13 CHA · LLC 2 MiB Core 14 CHA · LLC 2 MiB Core 15 CHA · LLC 3 MiB Core 16 CHA · LLC 2 MiB Core 17 CHA · LLC 3 MiB Core 18 CHA · LLC 3 MiB Core 19 MC 0 MC 1 DDR5 · 3 ch DDR5 · 3 ch 1 2 3 COMPUTE DIE · 20 tiles · 5 × 4 mesh a tile joins the mesh at its ring stop, not at its edge
die floorplan · tile mesh片内布局 · 瓦片网格 Twenty tiles, each a core under its own cache slice, joined by mesh rails whose crossings are the ring stops. A tile joins the mesh at its stop, not at its edge — that distinction is why one request's latency depends on how many stops it crosses. Badges 1 to 3 trace a single miss out to the memory controller. Template: templates/diagrams/die-floorplan.svg. 二十块瓦片,每块是一个核加它自己那片缓存,瓦片之间跑互连轨,交叉点就是站点。瓦片挂在自己的站点上、不是连在轨边上——一次访问的延迟取决于跳了几站,靠的就是这个区别。徽章 1–3 追一次未命中一路走到内存控制器。模板:templates/diagrams/die-floorplan.svg
DATAPATH · 4-WAY SET-ASSOCIATIVE LOOKUP comparator multiplexer OR gate 4712 116 50 TAG · 36 bits SET INDEX · 6 BLOCK OFFSET · 6 6 → 64 decoder · one wordline per set 36 4 V · TAG ARRAY DATA ARRAY · SET 41 way 0 1 0x0004_A1C 64 B line · way 0 = way 1 0 0x00F1_2B8 64 B line · way 1 = way 2 1 0x0004_A1C 64 B line · way 2 = way 3 1 0x0091_7D0 64 B line · way 3 = 4:1 ≥1 word → load unit HIT a miss is this line staying low A B C D E way 1 is invalid, so its comparator can never assert — the valid bit is an input to the match, not a decoration
datapath · comparators, mux, gate数据通路 · 比较器与选择器 A four-way set-associative lookup drawn at gate level: the address splits, a decoder picks the set, four comparators race, and the match lines both drive the multiplexer and feed the OR gate that raises HIT. Way 1 is invalid, so its comparator can never assert — that one deliberate dead lane is what makes the valid bit legible. Badges A to E. Template: templates/diagrams/datapath.svg. 四路组相联查找画到器件一级:地址拆分、译码器选中一组、四个比较器同时比、匹配线一边驱动多路选择器一边进或门抬起 HIT。way 1 的 valid 是 0,它的比较器永远不会成立——故意留死这一路,valid 位才讲得清。徽章 A–E。模板:templates/diagrams/datapath.svg
PACKET ENCAPSULATION · ONE BYTE RULER, THREE LAYERS 8 px = 1 byte · bars are to scale with each other Transaction layer TLP header 16 B data payload 64 B 80 B · what the requester actually meant to send Data link layer the 80 B above, untouched + SeqNum 2 B + LCRC 4 B 86 B · replay needs the number, the receiver needs the CRC Physical layer · framing the 86 B above, untouched + STP 1 B + END 1 B 88 B · now it has a beginning and an end on the wire BYTE STRIPING · x4 LINK Lane 0 byte 0 byte 4 byte 8 Lane 1 byte 1 byte 5 byte 9 Lane 2 byte 2 byte 6 byte 10 Lane 3 byte 3 byte 7 byte 11 SerDes · 128b/130b · 32 GT/s per lane byte n leaves on lane n mod 4
packet encapsulation · byte ruler逐层封装 · 字节标尺 One packet down three layers on a single byte ruler at eight pixels per byte, so each bar's width is its byte count. Two dashed guidelines pin the original eighty bytes: everything a lower layer adds appears outside them, never inside. Fields narrower than their own label get bracketed out to the margin rather than shrunk. Template: templates/diagrams/packet-encap.svg. 同一个报文走过三层,画在一把 8 px/字节的标尺上,所以每根条的宽度就是它的字节数。两条竖虚线钉住最初那 80 字节:下层加的东西一律长在外面,绝不进到里面。窄到装不下标签的字段用括线引到边上写,不缩字号。模板:templates/diagrams/packet-encap.svg
ANNOTATED CONSOLE · PCI ENUMERATION, ONE FAILING DEVICE real output, marked up · never retyped ttyS0 · 115200 8N1 · dmesg | grep -E 'pci|accel|nvme' [ 0.412903] PCI: MMCONFIG for domain 0000 [bus 00-ff] [ 0.418772] pci_bus 0000:00: root bus resource [mem 0x90000000-0xafffffff window] [ 0.431065] pci 0000:00:1c.0: PCI bridge to [bus 01] [ 0.436210] pci 0000:01:00.0: [144d:a80a] type 00 class 0x010802 [ 0.441642] pci 0000:01:00.0: BAR 0: assigned [mem 0x90000000-0x90003fff 64bit] [ 0.447318] pci 0000:00:1c.4: PCI bridge to [bus 02-04] [ 0.451900] pci 0000:02:02.0: bridge window [mem 0xa0100000-0xa01fffff] [ 0.458233] pci 0000:04:00.0: [1de5:1001] type 00 class 0x120000 [ 0.462117] pci 0000:04:00.0: reg 0x10: [mem 0x00000000-0x0fffffff 64bit pref] [ 0.476551] pci 0000:04:00.0: BAR 0: no space for [mem size 0x10000000 64bit pref] [ 0.481990] pci 0000:04:00.0: BAR 0: failed to assign [mem size 0x10000000] [ 0.488412] accel 0000:04:00.0: probe failed with error -12 [ 2.441642] nvme nvme0: 4/0/0 default/read/poll queues [ 2.509377] nvme0n1: p1 p2 / # 1 2 3 4 5 1 The only window there is Everything on this root bus has to fit in 0x9000_0000–0xafff_ffff — 512 MiB. Read this line before you read any BAR line. 2 Firmware already froze the window The bridge down to bus 04 got a 1 MiB window at boot. Nothing behind that bridge can ever be larger, whatever the parent has spare. 3 What the device is asking for reg 0x10 reads back 0x0fff_ffff, so BAR0 wants 256 MiB — 256× the window it must live in. This line is the request, not the result. 4 −12 is −ENOMEM, not a driver bug The resource was never assigned, so pci_iomap() in probe() had nothing to map. Fixing the driver cannot fix this; the window has to grow. 5 The healthy one, for contrast Four lines later nvme got its BAR and its queues. Keep a known-good stretch in the same figure — it is what tells you the log itself is fine.
annotated console · real output终端实录 · 原样标注 Fourteen lines of real PCI enumeration, marked up and never retyped. Five badges pin lines to notes; the highlight blocks sit under the glyphs and are positioned from character indices, because every line is pinned to an exact textLength. The story: a 256 MiB BAR behind a bridge window firmware sized at 1 MiB, and the minus twelve that follows. The healthy NVMe lines stay in frame on purpose. Template: templates/diagrams/terminal-annotated.svg. 十四行真实的 PCI 枚举输出,只加标注、一个字符不改。五个徽章把行钉到右栏说明;高亮块画在文字下面,位置由字符下标算出来——每行都用 textLength 锁死了字符步进。讲的事:一个 256 MiB 的 BAR 挂在 firmware 只给了 1 MiB 的桥窗口后面,接着就是 -12。正常的 nvme 那几行是故意留在画面里的。模板:templates/diagrams/terminal-annotated.svg
STRUCT GRAPH · WHICH FIELD HOLDS WHICH POINTER pointer field · every arrow starts here, not at the edge of the box mm->mm_mt maple tree, keyed by vm_start · replaced the VMA list and rbtree in 6.1 slot 0 0x5566_1000+ slot 1 0x5566_9000+ slot 2 0x7ffd_0000+ struct task_struct pid pid_t comm[16] char mm mm_struct * active_mm mm_struct * files files_struct * struct mm_struct mm_users atomic_t mm_count atomic_t pgd → page tables mmap_base unsigned long mm_mt maple_tree map_count int · 42 VMAs struct vm_area_struct vm_start 0x5566_1000 vm_end 0x5566_9000 vm_flags VM_READ|VM_EXEC vm_pgoff 0 vm_file file * vm_ops vm_operations_struct * anon_vma NULL until first COW struct vm_area_struct vm_start 0x5566_9000 vm_end 0x5566_b000 vm_flags VM_READ|VM_WRITE struct vm_area_struct vm_start 0x7ffd_0000 vm_end 0x7ffd_2000 vm_flags VM_GROWSDOWN struct file f_inode inode * f_mapping address_space * f_op file_operations * struct vm_operations_struct .fault filemap_fault .map_pages filemap_map_pages .open / .close NULL field names from include/linux/mm_types.h and sched.h at v6.6 rows are in reading order, not struct offset order
struct graph · pointer fields结构体指针图 · 字段级 task_struct to mm_struct to the maple tree to three VMAs, with every arrow leaving the field that actually holds the pointer and landing on the target's title bar. Start precise, end whole — that asymmetry is the point. One sibling is drawn in full, the other two keep only what tells them apart. Names checked against include/linux/mm_types.h at v6.6. Template: templates/diagrams/struct-graph.svg. task_struct → mm_struct → maple tree → 三个 VMA,每根箭头从真正持有指针的那一行出发,落在目标卡片的标题栏上。起点精确到字段、终点是整个对象——这个不对称就是重点。兄弟对象只详画一个,其余只留区分它们的那几行。字段名对过 v6.6 的 include/linux/mm_types.h。模板:templates/diagrams/struct-graph.svg
BUS FABRIC · TWO RAILS, ONE TRACED READ master slave APB peripheral this read CPU cluster 4 × A78 · AXI master 0 DMA engine 16 ch · AXI master 1 GPU / VPU AXI master 2 AXI4 · 128-bit · AW W B AR R APB · 32-bit 128 32 32 arbiter SRAM 256 KiB · 0x0000_0000 AXI → APB bridge protocol converter USB3 · GbE high-speed IP DDR4 controller 0x8000_0000 · 4 GiB UART0 I2C0 SPI0 GPIO WDT 1 2 3 4 every drop carries its own width; the rail carries the name of the channels riding it rails are a drawing, not a topology claim · a real AXI NoC is switched
bus fabric · rails and widths总线挂载 · 位宽 Masters above the rail, slaves below, the bridge dropping to a narrower rail with its own peripherals. Each drop carries its width as a slash and a number; the rail carries the names of the channels riding it. One read is traced out solid and back dashed, twelve pixels clear of the rail — at eight it vanished into it. The footer says out loud that rails are a drawing, not a topology claim. Template: templates/diagrams/bus-fabric.svg. 主设备在轨上方、从设备在下方,桥再往下接一条更窄的轨和它自己的外设。每条引下线用斜杠加数字标位宽,轨上写跑在它上面的通道名。一次读事务去程实线、回程虚线,离轨 12 px——8 px 时实测糊进轨里看不见。图脚明写:轨是一种画法,不是拓扑论断。模板:templates/diagrams/bus-fabric.svg

Calls & timing 调用与时序

Six figures, each spending its single blue on whatever that figure is actually about — the edge grep cannot find, the frame that faulted, the sixty-five microseconds a worker waits, the new frame and its deadline, the core everyone is waiting on, the reset line and the constraint people get wrong. Never on the biggest box. 六张图,每一张都把唯一的那点蓝花在这张图真正要讲的事上——grep 找不到的那条边、出错的那一帧、worker 等的那 65 µs、新的一帧和它的 deadline、大家在等的那个核、复位线和最常被做短的那条约束。不给最大的那个框。

CALL GRAPH · THREE DRIVERS, FIVE KINDS OF EDGE direct call · same stack through an ops table async handoff · context changes hardware event completion travels back DRM CORE VENDOR DISPLAY DRIVER PANEL + BACKLIGHT in-tree one module two modules queue_work() .atomic_flush .prepare · core reaches the panel over that driver back into core plain exported symbol complete(&flip_done) wakes the worker DSI frame-done IRQ drm_mode_atomic_ioctl() userspace asked for a new frame process drm_atomic_commit() validates, then hands the work over process commit_tail() the queued work item runs here kworker drm_crtc_handle_vblank() core bookkeeping, then wakes waiters hardirq qz_crtc_atomic_flush() latches the new framebuffer address qz_dsi_send_frame() kicks the display DMA qz_dsi_irq() acks, then calls core hardirq qz_panel_prepare() power rails, reset, init sequence backlight_enable() a different module entirely cross-driver grep finds the solid black edges. It cannot find the blue ones (the target is a struct member, resolved at runtime) or the gold one (the target runs later, on another thread).
call graph · five kinds of edge调用关系图 · 五种边 Three drivers, and every edge drawn by kind: a thin solid arrow is a direct call on the same stack, a hollow head means the target is a struct member resolved at runtime, a gold dashed arrow is an asynchronous handoff that changes execution context, a lightning bolt is a hardware event, a dotted arrow is a completion travelling back. The point is the last line: grep only finds the solid black ones. Template: templates/diagrams/call-graph.svg. 三个驱动,每条边按种类画:细实线是同栈直接调用,空心箭头表示目标是运行时才定的结构体成员,金色虚线是换了执行上下文的异步交接,闪电是硬件事件,点线是完成通知往回走。结论在图脚:grep 只找得到黑色实线那几条。模板:templates/diagrams/call-graph.svg
CALL STACK · AND WHERE IT STOPS BEING A CALL CHAIN newest frame on top · the way the kernel prints it Unable to handle kernel NULL pointer dereference at 0x18 this work item kworker skeleton qz_dsi_write_reg +0x2c/0x80 #0 [drm_quartz] qz_panel_prepare +0x64/0x120 #1 [panel_quartz] drm_panel_prepare +0x28/0x50 #2 drm_atomic_helper_commit_modeset_enables +0x2a8/0x430 #3 commit_tail +0xa4/0x180 #4 process_one_work +0x1d8/0x430 #5 worker_thread +0x150/0x460 #6 kthread +0x110/0x11c #7 ret_from_fork +0x10/0x20 #8 the chain of “who called me” ends here drm_atomic_commit() ran queue_work() earlier, in another context. Not on this stack. Where it died 0x2c into an 0x80-byte function. Feed that offset to addr2line, not the raw PC — modules relocate. The boundary worth noticing Frames 0-1 are out-of-tree, 2-4 are core. The bug is almost always on the side with the module tag. Learn the skeletons by sight process_one_work / worker_thread — workqueue. call_timer_fn — timer. rcu_do_batch — RCU. el0_svc_common — a syscall from userspace. Each one marks a cut like this one. A stack answers “how did I get here” only inside one context. Every async boundary — work, timer, IRQ, RCU callback — cuts it, and the cut is invisible unless you know the skeleton frames by sight.
call stack · where it stops being a chain调用栈 · 断在哪里 A nine-frame oops backtrace with a fault line across it. Below the line is the kworker skeleton, which is not a caller chain in any useful sense — process_one_work called whatever was queued, not this. The caller you actually want ran queue_work() earlier in another context, and it is drawn as a dashed ghost card off to the side because it is not on this stack at all. Template: templates/diagrams/call-stack.svg. 九帧 oops backtrace,中间横着一条断层线。线以下是 kworker 骨架,那不是调用链——`process_one_work` 调用的是队列里排到的任何东西。你真正要找的调用者早些时候在别的上下文里跑了 `queue_work()`,它被画成旁边一张虚线幽灵卡,因为它根本不在这张栈上。模板:templates/diagrams/call-stack.svg
RUNTIME TIMELINE · ONE COMPLETION, FOUR CONTEXTS time in µs · one CPU · measured with trace_printk hardirq irq disabled · must not sleep softirq still atomic · may run on any CPU kworker a real thread · may sleep user thread the process that asked blocked in read() since before this frame qz_dma_irq() dma_tasklet() · drain descriptors dma_refill_work() · alloc + re-arm read() returns device raises IRQ tasklet_schedule() complete() queue_work() 0 25 50 75 100 125 150 µs IRQ → handler · 8 µs raise → tasklet · 6 µs queue_work() → worker actually runs · 65 µs Same handoff, two primitives, an order of magnitude apart: the tasklet runs on the way out of the interrupt, the worker waits for the scheduler like any other thread. Draw the gap, not the arrow. An arrow says “then this happens”; only the gap says when — and every latency bug lives in a gap somebody drew as an arrow. If the tasklet lane ever runs longer than MAX_SOFTIRQ_TIME the rest is pushed into ksoftirqd, and this lane turns into a fifth one that competes for the CPU.
runtime timeline · four contexts运行时泳道 · 四个上下文 One DMA completion handed along hardirq, softirq, kworker and the user thread on a shared microsecond axis. Three brackets under the axis carry the numbers: 8 µs from interrupt to handler, 6 µs from raising the tasklet to running it, and 65 µs from queue_work() to the worker actually running. A workqueue is not a slightly slower tasklet — it is an order of magnitude later, because the worker waits for the scheduler like any other thread. Template: templates/diagrams/runtime-timeline.svg. 一次 DMA 完成依次走过硬中断、软中断、kworker 和用户线程,共用一根微秒轴。轴下三条括线给数字:中断到 handler 8 µs,raise 到 tasklet 跑起来 6 µs,`queue_work()` 到 worker 真跑 65 µs。workqueue 不是「慢一点的 tasklet」,是晚一个数量级——worker 就是个普通线程,要排队等调度。模板:templates/diagrams/runtime-timeline.svg
FRAME PIPELINE · GPU → DDR → DMA → DSI → PANEL, ONE 60 Hz PERIOD front buffer · fb A back buffer · fb B CPU · compositor builds the atomic commit GPU renders into the back buffer DDR serves both at once display DMA · CRTC scans out, line by line DSI · D-PHY 4 lanes · 1 Gbps each LCD driver IC holds the pixels on the glass 1 2 3 4 5 atomic commit render frame N+1 → fb B write fb B read fb A · every line, all frame long scanout fb A · 1080 lines one burst per line · HS entry, payload, HS exit showing frame N N+1 VSYNC TE 0 2 4 6 8 10 12 14 16 18 ms slack 6.9 ms · cross ④ and the panel repeats frame N ① vsync IRQ latches the framebuffer address · ② GPU signals its fence · ③ page flip queued ④ scanout done, frame-done IRQ · ⑤ next vsync, fb B goes live the deadline is a vsync edge, not a config value
frame pipeline · one 60 Hz period一帧的数据通路 · 60 Hz Six hardware lanes over one frame period with vsync and TE underneath on the same axis. The memory lane is split in two because it serves both at once — the GPU writing the back buffer and scanout reading the front buffer — and that contention is why scanout underruns when the GPU is busy. Badge 1 the vsync interrupt latches the framebuffer address, badge 2 the GPU signals its fence, badge 3 the page flip is queued, badge 4 scanout finishes, badge 5 the next vsync makes the back buffer live. Cross badge 5 and the panel simply repeats the frame. Template: templates/diagrams/frame-pipeline.svg. 六条硬件泳道铺在一个帧周期上,下面同轴画 vsync 和 TE。内存那条拆成两根小条,因为它同时在服务两边——GPU 在写后台缓冲、扫描输出在读前台缓冲——GPU 一忙扫描输出就 underrun,原因就是这个争用。徽章 1 vsync 中断锁住帧缓冲地址,2 GPU 发出 fence,3 翻页入队,4 扫描输出结束,5 下一个 vsync 让后台缓冲上台。越过徽章 5,面板就重复上一帧。模板:templates/diagrams/frame-pipeline.svg
CROSS-CORE CALLS · WHO WAITS FOR WHOM IPI · wakes another core's hardirq acknowledgement CPU 0 holds the lock, sends the IPI CPU 1 wants the same lock CPU 2 idle, answers at once CPU 3 irqs off in a long section spin_lock() flush_tlb_mm() · waits for every ack unlock spinning · burning cycles, not sleeping acquires flush_tlb_func() irqs off · a long critical section of its own flush_tlb_func() smp_call_function_many() the last ack — the one CPU 0 was waiting for 0 5 10 15 20 25 30 35 40 µs CPU 0 blocked 24 µs — set by the slowest responder, not the average CPU 1 spun 30 µs for a lock it could not have influenced One core with interrupts disabled sets the pace for every core that needs an ack from it. That is the whole reason long irqs-off sections are a system property, not a local one. Per-CPU data needs none of this: no other core can name the variable, so there is no lock, no IPI and no ack — provided the thread cannot migrate between get_cpu() and put_cpu(). Draw the ack arrows, not just the IPI arrows. A fan-out alone reads as fire-and-forget; the acks are what turn it into a wait.
cross-core calls · who waits for whom跨核调用 · 谁在等谁 Four CPU lanes on one microsecond axis. CPU 0 holds a spinlock and sends an IPI to the others, then waits for every acknowledgement. CPU 3 had interrupts disabled for a long stretch, so its ack arrives last and sets how long CPU 0 blocks. Draw the ack arrows, not just the fan-out: a fan-out alone reads as fire-and-forget, and the acks are what turn it into a wait. Template: templates/diagrams/multicore-calls.svg. 四条 CPU 泳道共用一根微秒轴。CPU 0 拿着自旋锁、向其余核发 IPI,然后等每一个应答。CPU 3 有一段长时间关中断,它的应答最晚到,于是 CPU 0 阻塞多久由它说了算。应答箭头必须画出来:只画扇出读作发完就走,画上应答才成为一次等待。模板:templates/diagrams/multicore-calls.svg
PANEL POWER SEQUENCE · RAILS, RESET, COMMANDS, BACKLIGHT not to scale · the brackets carry the real numbers panel_funcs->prepare() enable() owned by VCC_IO 1.8 V · always first VCC_3V3 3.3 V panel supply VDD_MIPI D-PHY rail REFCLK 24 MHz RESET_N active low DSI link lane state undriven LP-11 · ready for commands DCS init sequence init seq on BL_EN PWM + enable t1 ≥ 10 ms · supplies stable → reset release t2 ≥ 10 µs t3 ≥ 5 ms · reset → first DCS t4 ≥ 120 ms · sleep-out → backlight REFCLK must already be running when reset rises, or the panel latches its state from a clock that is not there. Power-down is the exact reverse of this figure, every step. Each broken constraint has its own bench symptom: t1 short → panel never answers; t3 short → the init sequence is swallowed; t4 short → a white flash at every boot — the one people ship.
panel power sequence上电时序 · 屏 Rails, clock, reset, link state, init commands and backlight, laid out by event rather than by linear time — the constraints span four orders of magnitude, so a true-scale axis would render the 10 µs reset pulse as zero pixels. The brackets carry the real numbers with their inequality signs, and the bar along the top says which panel callback owns which stretch. Power-down is the exact reverse, every step, including the waits. Template: templates/diagrams/power-sequence.svg. 电源轨、时钟、复位、链路状态、初始化命令、背光,按事件排而不按线性时间——约束跨了四个数量级,按真实比例画的话 10 µs 那段复位脉冲是 0 像素。括线带着不等号给真实数字,顶上那条横条说明每一段归哪个面板回调管。下电是严格逆序,每一步都要,包括那些等待。模板:templates/diagrams/power-sequence.svg

Runtime 运行时

Time-ordered views: who talks to whom, who runs where, where the data lands. Blue follows the one thing you are tracing. 按时间展开的视图:谁和谁通信、谁在哪个核上跑、数据落在哪。蓝色始终跟着你正在追踪的那一个对象。

Client browser app Gateway auth · rate limit Worker runs the job Postgres primary db POST /v1/messages schedule(run) INSERT run · queued ack · 12 ms stream tokens 200 OK · SSE 1 2 3 4 5 6
Sequence · api时序 · API Requests in blue, returns in dashed gray, activation bars floating on shadows. Follow the badges: ④ is the one to notice — the gateway acks at 12 ms, long before the worker has produced a token, so the client waits on a stream instead of on the whole run. Template: templates/diagrams/sequence.svg. 请求走蓝色,返回走灰虚线,激活条靠柔影浮起。按编号读,值得注意的是 :网关在 12 ms 就应答了,那时 worker 一个 token 都还没产出——客户端于是等的是一条流,不是整次运行。模板:templates/diagrams/sequence.svg
CFS run view · 12 ms window trace-cmd record -e sched_switch -e sched_migrate_task IRQ · eth0 CPU 0 CPU 1 CPU 2 app: render irq/eth0 idle idle kworker/u8 idle kworker/u8 idle kworker/u8 idle migrate · load balance idle app: render idle 0 2 4 6 8 10 12 ms task block · CFS / workqueue idle app: render · traced task axis marks every 2 ms · HZ=1000
Scheduler · timeline调度 · 时间线 Three CPU lanes; the traced task wears blue across cores and its migration arrow shows the load balancer at work. Template: templates/diagrams/sched-timeline.svg. 三条 CPU 泳道;被追踪的任务跨核保持蓝色,迁移箭头画出负载均衡的动作。模板:templates/diagrams/sched-timeline.svg
kfifo — lockless ring buffer, size = 16 single producer / single consumer · len = in − out = 7 data free in = 37 new data lands here out = 30 next read 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 idx & (size − 1) kfifo_in(): copy, smp_wmb(), in += len kfifo_out(): smp_rmb(), out += len
Algorithm · data structure算法 · 数据结构 A kfifo ring buffer: tinted cells hold data, the blue pointer marks where new bytes land. Template: templates/diagrams/algorithm-ringbuffer.svg. kfifo 环形缓冲:tint 格存数据,蓝色指针标出新字节落点。模板:templates/diagrams/algorithm-ringbuffer.svg
today v0.9Jan v1.0Mar v1.5May v2.0Q3 v2.5Q4 v3.0next year shipped upcoming
Timeline · milestones时间线 · 里程碑 Shipped milestones in ink, upcoming ones hollow, one blue marker for now. Template: templates/diagrams/timeline.svg. 已交付的里程碑用墨色,未到的用空心,唯一的蓝色标记现在。模板:templates/diagrams/timeline.svg
start success pause resume error · retry ≤ 2 reset 1 2 Idle Running Done Paused Failed awaiting job executing steps all gates green operator hold retries exhausted
State machine · lifecycle状态机 · 生命周期 Blue belongs to the happy path: entry through Idle and the Running focus card to Done. Pause, resume and error stay gray; the reset loop is the one dashed return. Template: templates/diagrams/state-machine.svg. 蓝色只属于 happy path:从入口经 Idle 和 Running 焦点卡到 Done。pause、resume、error 全留灰;reset 回流是全图唯一的虚线。模板:templates/diagrams/state-machine.svg