|
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 |
| 108 | the bins differ, so the per-shape figures do too, but the empty-torrent and |
108 | the bins differ, so the per-shape figures do too, but the empty-torrent and |
| 109 | single-allocation gains hold on both. |
109 | single-allocation gains hold on both. |
| 110 | |
110 | |
| |
111 | Reading those structs for one announce is a walk down cold memory. With the |
| |
112 | hash 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 | |
| |
122 | Each cold line is a separate allocation, and on a large table each is a miss. |
| |
123 | The hot line rode in on the peerlist step before it. The torrent search |
| |
124 | dominates, one miss per probe into a bucket of hundreds of thousands, with the |
| |
125 | peerlist pointer chase and the peer search behind it. Aging the torrent adds |
| |
126 | nothing in steady state: one touched this minute has a zero span and the |
| |
127 | cleaner returns at once. The reply counts are hot because the two family |
| |
128 | sizes and the seeder count share the peerlist's line. A split swarm is the |
| |
129 | exception, since summing its size walks the bucket headers, but those are the |
| |
130 | largest torrents, where handing out peers already walks the swarm. |
| |
131 | |
| |
132 | A request waits on two system calls around this, a receive and a send, each |
| |
133 | on the order of a handful of misses. Memory latency and kernel time are |
| |
134 | co-dominant. Neither hides behind the other, and no term in the table is one |
| |
135 | a cache would hold still. |
| |
136 | |
| 111 | A refused announce is answered over UDP with a well formed announce for an |
137 | A refused announce is answered over UDP with a well formed announce for an |
| 112 | empty swarm rather than with the error action. BEP 15 binds a client to the |
138 | empty swarm rather than with the error action. BEP 15 binds a client to the |
| 113 | interval it is handed and says nothing about what a client should do with an |
139 | interval 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 | |
| 142 | The production and debug binaries carry -fstack-protector-strong, -fPIE and |
168 | The 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 |
| 144 | full RELRO (-z relro,-z now). Measured cost on |
170 | full RELRO (-z relro,-z now). Measured cost on |
| 145 | the announce hot path is 300 to 305 nanoseconds, under two per cent, and the |
171 | the announce hot path is 300 to 305 nanoseconds, under two per cent, and the |
| 146 | individual flags sit inside the run-to-run noise: add_peer has few stack |
172 | individual 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 |
| 152 | linker rejects -z, and flags a bare -pie in the combined compile-and-link as |
178 | linker rejects -z, and flags a bare -pie in the combined compile-and-link as |
| 153 | unused, while macOS links executables PIE by default, so leaving both off |
179 | unused, while macOS links executables PIE by default, so leaving both off |
| 154 | there costs no hardening. The branch runs in the shell through a != assignment, |
180 | there costs no hardening. The branch runs in the shell through a != assignment, |
| 155 | the one form both bmake and GNU make 4 accept; $(shell) is GNU only and GNU |
181 | the one form both bmake and GNU make 4 accept. $(shell) is GNU only and GNU |
| 156 | make 3.81, which stock macOS ships, has neither. On that old make the != line |
182 | make 3.81, which stock macOS ships, has neither. On that old make the != line |
| 157 | is inert and leaves the flags empty, which is the right answer for macOS |
183 | is inert and leaves the flags empty, which is the right answer for macOS |
| 158 | anyway, so every platform resolves correctly without a make conditional. |
184 | anyway, 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 |
| 225 | builds under FreeBSD's make today. Building each binary in one invocation |
251 | builds under FreeBSD's make today. Building each binary in one invocation |
| 226 | clears the objects out of the tree without giving that up. |
252 | clears the objects out of the tree without giving that up. |
| 227 | |
253 | |
| |
254 | A cached peer count on the torrent or the peerlist. The count is a vector's |
| |
255 | own size, a field in a line the peer insert has already loaded, so a cache |
| |
256 | would hold a second copy of a number already in reach and have to be kept in |
| |
257 | step with the vector it copies. Only a split swarm pays, to sum its buckets, |
| |
258 | and there the sum is lost against walking the swarm to answer at all. |
| |
259 | |
| 228 | |
260 | |
| 229 | |
261 | |
| 230 | Platform differences that cost us code |
262 | Platform differences that cost us code |
| 231 | -------------------------------------- |
263 | -------------------------------------- |
| 232 | |
264 | |
| 233 | SO_REUSEPORT means three different things. Linux spreads datagrams over the |
265 | SO_REUSEPORT means three different things. Linux spreads datagrams over the |
| 234 | group; FreeBSD permits the bind and needs SO_REUSEPORT_LB to spread. Darwin |
266 | group. FreeBSD permits the bind and needs SO_REUSEPORT_LB to spread. Darwin |
| 235 | hands every datagram to whichever socket bound last, so a group there starves |
267 | hands every datagram to whichever socket bound last, so a group there starves |
| 236 | all but one reader. |
268 | all but one reader. |
| 237 | |
269 | |
|