summaryrefslogtreecommitdiff
path: root/DESIGN
diff options
context:
space:
mode:
authorDirk Engling <erdgeist@erdgeist.org>2026-11-09 19:29:55 +0100
committerDirk Engling <erdgeist@erdgeist.org>2026-11-09 19:29:55 +0100
commit4bdec357c08d2919028230360470df9f41c11a97 (patch)
tree54bbd746472828aeb38d6f2cb0cc067f7071015b /DESIGN
parent4eff65c7e7a3a0d227358f7dc3932b3004a99a15 (diff)
Add memory access pattern overview to the DESIGN documentHEADmaster
Diffstat (limited to 'DESIGN')
-rw-r--r--DESIGN38
1 files changed, 35 insertions, 3 deletions
diff --git a/DESIGN b/DESIGN
index f089a3d..480aa9b 100644
--- a/DESIGN
+++ b/DESIGN
@@ -108,6 +108,32 @@ single-family torrent pays for the absent family's vector header. On jemalloc
108the bins differ, so the per-shape figures do too, but the empty-torrent and 108the bins differ, so the per-shape figures do too, but the empty-torrent and
109single-allocation gains hold on both. 109single-allocation gains hold on both.
110 110
111Reading those structs for one announce is a walk down cold memory. With the
112hash in hand, the steady-state path to an existing torrent reads, in order:
113
114 step reads load
115 lock one bucket mutex cold
116 bucket header that bucket's torrent vector cold
117 torrent search a hash per probe, log2 of the bucket cold
118 peerlist the torrent's peerlist cold
119 peer search a peer per probe, log2 of the swarm cold
120 reply counts the peerlist's sizes and seeder count hot
121
122Each cold line is a separate allocation, and on a large table each is a miss.
123The hot line rode in on the peerlist step before it. The torrent search
124dominates, one miss per probe into a bucket of hundreds of thousands, with the
125peerlist pointer chase and the peer search behind it. Aging the torrent adds
126nothing in steady state: one touched this minute has a zero span and the
127cleaner returns at once. The reply counts are hot because the two family
128sizes and the seeder count share the peerlist's line. A split swarm is the
129exception, since summing its size walks the bucket headers, but those are the
130largest torrents, where handing out peers already walks the swarm.
131
132A request waits on two system calls around this, a receive and a send, each
133on the order of a handful of misses. Memory latency and kernel time are
134co-dominant. Neither hides behind the other, and no term in the table is one
135a cache would hold still.
136
111A refused announce is answered over UDP with a well formed announce for an 137A refused announce is answered over UDP with a well formed announce for an
112empty swarm rather than with the error action. BEP 15 binds a client to the 138empty swarm rather than with the error action. BEP 15 binds a client to the
113interval it is handed and says nothing about what a client should do with an 139interval it is handed and says nothing about what a client should do with an
@@ -140,7 +166,7 @@ Build hardening the shipped binary
140---------------------------------- 166----------------------------------
141 167
142The production and debug binaries carry -fstack-protector-strong, -fPIE and 168The production and debug binaries carry -fstack-protector-strong, -fPIE and
143_FORTIFY_SOURCE=2 on every platform; the GNU-style linkers also get -pie and 169_FORTIFY_SOURCE=2 on every platform. The GNU-style linkers also get -pie and
144full RELRO (-z relro,-z now). Measured cost on 170full RELRO (-z relro,-z now). Measured cost on
145the announce hot path is 300 to 305 nanoseconds, under two per cent, and the 171the announce hot path is 300 to 305 nanoseconds, under two per cent, and the
146individual flags sit inside the run-to-run noise: add_peer has few stack 172individual flags sit inside the run-to-run noise: add_peer has few stack
@@ -152,7 +178,7 @@ The link flags -pie and RELRO are gated on the operating system: Apple's
152linker rejects -z, and flags a bare -pie in the combined compile-and-link as 178linker rejects -z, and flags a bare -pie in the combined compile-and-link as
153unused, while macOS links executables PIE by default, so leaving both off 179unused, while macOS links executables PIE by default, so leaving both off
154there costs no hardening. The branch runs in the shell through a != assignment, 180there costs no hardening. The branch runs in the shell through a != assignment,
155the one form both bmake and GNU make 4 accept; $(shell) is GNU only and GNU 181the one form both bmake and GNU make 4 accept. $(shell) is GNU only and GNU
156make 3.81, which stock macOS ships, has neither. On that old make the != line 182make 3.81, which stock macOS ships, has neither. On that old make the != line
157is inert and leaves the flags empty, which is the right answer for macOS 183is inert and leaves the flags empty, which is the right answer for macOS
158anyway, so every platform resolves correctly without a make conditional. 184anyway, so every platform resolves correctly without a make conditional.
@@ -225,13 +251,19 @@ A directory for object files. bmake has no pattern rules and the Makefile
225builds under FreeBSD's make today. Building each binary in one invocation 251builds under FreeBSD's make today. Building each binary in one invocation
226clears the objects out of the tree without giving that up. 252clears the objects out of the tree without giving that up.
227 253
254A cached peer count on the torrent or the peerlist. The count is a vector's
255own size, a field in a line the peer insert has already loaded, so a cache
256would hold a second copy of a number already in reach and have to be kept in
257step with the vector it copies. Only a split swarm pays, to sum its buckets,
258and there the sum is lost against walking the swarm to answer at all.
259
228 260
229 261
230Platform differences that cost us code 262Platform differences that cost us code
231-------------------------------------- 263--------------------------------------
232 264
233SO_REUSEPORT means three different things. Linux spreads datagrams over the 265SO_REUSEPORT means three different things. Linux spreads datagrams over the
234group; FreeBSD permits the bind and needs SO_REUSEPORT_LB to spread. Darwin 266group. FreeBSD permits the bind and needs SO_REUSEPORT_LB to spread. Darwin
235hands every datagram to whichever socket bound last, so a group there starves 267hands every datagram to whichever socket bound last, so a group there starves
236all but one reader. 268all but one reader.
237 269