Skip to content

Bench: Linux series follow-up at 1.0 CPU and 512M #793

Open

Description

@HMarzban

Summary

The Linux series ran on 2026-11-14, with one REST replica at --cpus=1 --memory=512m. It answered the production question for most shapes (REPORT.md §1). This issue tracks what is still owed: shapes not run, single sessions, and sessions the OOM kill voided.

Measured

Scenario Session Verdict Result
miss-fast (open loop) 20261114T040347 void: OOM kill at miss-fast@6400 1600/s rule-valid; CPU, then memory, then kill at 6400/s
miss-fast closed loop 20261114T050553 valid 5186.73/s at c16; plateau knee at c32; best 5665.53/s at c64; no break
hit 20261114T041002 valid no knee to 12800/s (a floor)
image 20261114T041519, 20261114T041855 void: OOM kill memory.max at 100/s; kill at 100/s (run 1) and in the 200/s warm-up (run 2)
hostile 20261114T042447 void: OOM kill at hostile@96 48/s held
hang 20261114T050053 valid held at hang@20; knee at hang@40
icon 20261114T043114 valid, 1 void step 100/s rule-valid; valid steps to 3200/s
aa 20261114T043619 valid p50 shift 0.18 ms significant; p99 MDE80 2.08 ms
  • Void and lost reruns: hang 20261114T043005 and closed loop 20261114T043953 (aborted: SIGTERM, the run agent ended its turn). Hang 20261114T045241 and closed loop 20261114T045740 (XProtect and logd CPU at an edge).
  • Known limits: the VM does not charge socket and slab memory (nokmem,nosocket). The healthcheck was off. VM timer wake-ups add about 4 ms to the p99 at 200/s or less.

Cause

Owed work, not a defect.

What to change

  1. Run the shapes that did not run on Linux: miss-real, huge, herd, redis-stall and limiter. miss-real comes first, because it is the production shape.
  2. Repeat every scenario to k ≥ 2.
  3. Run hang with steps at 24, 28, 32 and 36, to place the knee between hang@20 and hang@40.
  4. Run hit above 12800/s.
  5. Run an icon session on a quiet host, so the knee scan reaches 3200/s.
  6. Get valid image, hostile and open-loop miss-fast sessions. Either run them after Link metadata: stream image relays or cap image bytes in flight #786 and Link metadata: shed cold work before the queue grows to an OOM kill #787, or stop each ramp before the kill step.
  7. Repeat aa, because its p50 shift was significant.
  8. Run the Docker-backend smokes owed on macOS: step0, aa and redis-stall.
  9. Add a parse-attributed block timer for hostile pages (REPORT.md §3).
  10. Keep the run agent alive until each session footer is written (REPORT.md §5.7 item 7).
  11. Done: LINUX-SERIES.md now says the series ran.

Decisions

  1. Change the send-lag limit inside the VM? Recommended: not yet. Count the void hit steps first, then rule.
  2. Stop a ramp at the first OOM kill? Recommended: yes, for the after runs of Link metadata: stream image relays or cap image bytes in flight #786 and Link metadata: shed cold work before the queue grows to an OOM kill #787. A kill ends the session anyway.
  3. Which Redis? Recommended: keep redis:alpine 8.8.0, recorded, as its own fact group.
  4. Measure the core speed ratio to a production vCPU? Recommended: yes, with one short CPU-bound probe on the production host. The maintainer approves, because it touches production.

Benchmark

Before

The table in Measured. LINUX-RESULTS.md holds the full step tables. The hang and closed-loop reruns are in raw/linux/logs/{hang,miss-fast-conc}-rerun2.{replay,breaks}.out.

After

For each route, report:

  • the rate where throttled_usec starts to rise;
  • the memory.current max per step, and memory.events;
  • each oom_kill, with its rate.

Condition

The Linux condition in Bench conditions below. It must say: a Linux VM on one laptop, not the production host. The core speed ratio to a production vCPU is not measured.

Content-safety checks

  • None. The bench runs under --network none and touches no production data.

UX checks

  • None. No reader-facing change.

Rollback

None needed. The work stays in local notes and the bench harness (1a0d21b7f).

Acceptance criteria

  • miss-real has a valid Linux session.
  • Every scenario has k ≥ 2 valid Linux sessions, or a note on why not.
  • The hang knee is placed between hang@20 and hang@40.
  • The Linux numbers stay in their own fact group, never mixed with macOS numbers.
  • The status lines in LINUX-SERIES.md match the runs.

Related

Bench conditions

The bench is apps/hocuspocus.server/scripts/bench-link-tolerance/ (commit 1a0d21b7f). The headline numbers are in apps/hocuspocus.server/src/modules/link-metadata/BENCHMARK.md, section Load tolerance. REPORT.md, LINUX-RESULTS.md, research-*.md and raw/ are local bench notes (Notes/local-docs/2026-11-13-link-scraper-tolerance/), not in the repo. The Linux runner is local too.

Linux condition, used by every "Linux before": one REST container at --cpus=1 --memory=512m --memory-swap=512m, in the OrbStack VM on one laptop. Kernel 7.2.12-orbstack-00394-gbecdd6130068, booted with cgroup.memory=nokmem,nosocket, so socket and slab memory are not charged. --no-healthcheck. Bun 1.4.4+38afee6c8. Redis 8.8.0 (redis:alpine) in REST's network namespace. --network none. Pooled loopback to one local origin, no DNS, no TLS. benchTree 8774a6275a05005f, srcTree a9b6ca73ca68c2ec, runnerTree 516099a8c9839eac. Measured 2026-11-14. The core speed ratio to a production vCPU is not measured.

Laptop condition, used by every "Laptop before": local, one laptop (Apple M5 Max, 18 cores, 48 GB, macOS), Bun 1.4.4+38afee6c8, native Redis 8.10.3. REST runs under the sandbox-exec fence. Traffic is plain HTTP to one local origin, pooled loopback, no DNS, no TLS. No CPU quota and no cgroup. benchTree 8774a6275a05005f, srcTree a9b6ca73ca68c2ec. Measured 2026-11-14. Never compare it with a Linux number as one series.

"(void session)" marks a value from a valid step inside a void session. On Linux the OOM kill voided those sessions. The kill is the measured break.

After method, used by every "After":

  • Base = the commit before the change. Head = the change.
  • Run ABAB, at least 3 sessions per arm, each with its control step, at n ≥ 2,000 per step.
  • The change moves srcTree, so the before must run again. Do not reuse the 2026-11-14 numbers as the before.
  • The runner takes src/ from the working tree. So it first needs a source-folder option for base (REPORT.md §5.7 item 5).
  • On Linux, start each session in a fresh REST container, and keep the run agent alive until the footer is written.
  • Quote a change only when every head session sits outside the base range. Give σ and the MDE beside it.

Paths are under apps/hocuspocus.server/src/ unless they say otherwise.

Activity

  1. added this to the v2.3.6 milestone on Nov 14, 2026
  2. modified the milestones: v2.3.6, v2.3.8 on Nov 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions