683a882f
test: a throughput leg that can see a detached session rendering
a73x 2026-08-21 18:19
Commit message
test/throughput.sh
| Old | New | ||
|---|---|---|---|
| @@ -43,6 +43,23 @@ SOLO_MAX_MS=10 | |||
| 43 | CLIENT_LINES=200000 | 43 | CLIENT_LINES=200000 |
| 44 | CLIENT_WARN_MS=60 | 44 | CLIENT_WARN_MS=60 |
| 45 | CLIENT_MAX_MS=75 | 45 | CLIENT_MAX_MS=75 |
| 46 | # Leg 3 repaints a full screen over and over with NOBODY attached. Its | ||
| 47 | # own leg because `yes` cannot see what it sees: a one-character row is | ||
| 48 | # nearly free to render, so the solo leg above stays flat through a | ||
| 49 | # regression that makes full-width output 10x slower. Real output — | ||
| 50 | # vim, logs, a build — is full-width, and the daemon renders every row | ||
| 51 | # of it to hash it. | ||
| 52 | # 2^REPAINT_DOUBLINGS frames of ~1.8KB; 13 is ~15MB. | ||
| 53 | REPAINT_DOUBLINGS=13 | ||
| 54 | # Measured either side of the fix, same box, best-of-5: 87ms with the | ||
| 55 | # detached check in place, 479ms without it. The ceiling sits near the | ||
| 56 | # good number rather than under the bad one — put it at 400 and a machine | ||
| 57 | # twice this fast runs the BROKEN build in 240ms and the gate says | ||
| 58 | # nothing. 2.3x over nominal, and the readings span 87-90. | ||
| 59 | # | ||
| 60 | # 5.5x here against 27x at 200x50: the penalty is per rendered row, and | ||
| 61 | # this leg renders 23 of 80 columns rather than 49 of 200. | ||
| 62 | REPAINT_MAX_MS=200 | ||
| 46 | # Repeats per leg; the fastest one is the reading. See the header. | 63 | # Repeats per leg; the fastest one is the reading. See the header. |
| 47 | REPS=5 | 64 | REPS=5 |
| 48 | 65 | ||
| @@ -148,4 +165,61 @@ echo "client: $CLIENT_LINES lines, attached: ${CLIENT_MS}ms (target ${CLIENT_WA | |||
| 148 | echo " Not a failure. It is the number that decides whether this feels good to use." | 165 | echo " Not a failure. It is the number that decides whether this feels good to use." |
| 149 | } | 166 | } |
| 150 | 167 | ||
| 168 | # ---- leg 3: full-width repaint, nobody attached ------------------------ | ||
| 169 | # The client from leg 2 has quit, so this is a detached session again. | ||
| 170 | # | ||
| 171 | # One frame: cursor home, then 23 rows of 79 columns. 23 and not 24 so the | ||
| 172 | # screen is REPAINTED rather than scrolled — scrolling is a different cost | ||
| 173 | # (memset and cursorScrollAbove) and it would drown the one being measured. | ||
| 174 | { | ||
| 175 | printf '\033[H' | ||
| 176 | i=0 | ||
| 177 | while [ "$i" -lt 23 ]; do | ||
| 178 | printf '%79s\n' '' | tr ' ' x | ||
| 179 | i=$((i+1)) | ||
| 180 | done | ||
| 181 | } > "$TMPD/frame" | ||
| 182 | |||
| 183 | # Doubling rather than a loop of appends: 13 cats instead of 8192. | ||
| 184 | cp "$TMPD/frame" "$TMPD/big" | ||
| 185 | i=0 | ||
| 186 | while [ "$i" -lt "$REPAINT_DOUBLINGS" ]; do | ||
| 187 | cat "$TMPD/big" "$TMPD/big" > "$TMPD/big2" | ||
| 188 | mv "$TMPD/big2" "$TMPD/big" | ||
| 189 | i=$((i+1)) | ||
| 190 | done | ||
| 191 | REPAINT_BYTES=$(wc -c < "$TMPD/big") | ||
| 192 | |||
| 193 | rm -f "$TMPD/repaint" "$TMPD/repaint.done" | ||
| 194 | "$MUXA" send --sock "$SOCK" \ | ||
| 195 | "for k in \$(seq $REPS); do A=\$(date +%s%N); cat $TMPD/big; B=\$(date +%s%N); echo \$(( (B-A)/1000000 )) >> $TMPD/repaint; done; echo ok > $TMPD/repaint.done\n" \ | ||
| 196 | > /dev/null | ||
| 197 | i=0 | ||
| 198 | while [ ! -s "$TMPD/repaint.done" ] && [ "$i" -lt 120 ]; do sleep 0.5; i=$((i+1)); done | ||
| 199 | [ -s "$TMPD/repaint.done" ] || { | ||
| 200 | echo "throughput FAIL: $REPS repaints of $REPAINT_BYTES bytes unfinished after 60s" | ||
| 201 | exit 1 | ||
| 202 | } | ||
| 203 | REPAINT_ALL="$(cat "$TMPD/repaint")" | ||
| 204 | REPAINT_MS="$(echo "$REPAINT_ALL" | sort -n | head -1)" | ||
| 205 | [ "$(echo "$REPAINT_ALL" | wc -l)" -eq "$REPS" ] || { | ||
| 206 | echo "throughput FAIL: wanted $REPS repaint readings, got: $REPAINT_ALL" | ||
| 207 | exit 1 | ||
| 208 | } | ||
| 209 | # The screen must actually be full of the frame, or a shell that never ran | ||
| 210 | # the cat would score a perfect time for doing nothing. | ||
| 211 | "$MUXA" capture --sock "$SOCK" | grep -qF 'xxxxxxxx' || { | ||
| 212 | echo "throughput FAIL: the repaint left no output on the grid" | ||
| 213 | "$MUXA" capture --sock "$SOCK" | ||
| 214 | exit 1 | ||
| 215 | } | ||
| 216 | |||
| 217 | echo "repaint: $REPAINT_BYTES bytes, detached: ${REPAINT_MS}ms (max ${REPAINT_MAX_MS}ms) [$(echo "$REPAINT_ALL" | tr '\n' ' ')]" | ||
| 218 | [ "$REPAINT_MS" -lt "$REPAINT_MAX_MS" ] || { | ||
| 219 | echo "throughput FAIL: repaint leg took ${REPAINT_MS}ms, ceiling is ${REPAINT_MAX_MS}ms" | ||
| 220 | echo " A detached session should not be rendering rows at all. Check that" | ||
| 221 | echo " sendUpdate still asks hasClientsIn BEFORE it diffs." | ||
| 222 | exit 1 | ||
| 223 | } | ||
| 224 | |||
| 151 | echo "throughput OK" | 225 | echo "throughput OK" |