Skip to content

Latest commit

 

History

History
143 lines (121 loc) · 7.14 KB

performance-loop.md

File metadata and controls

143 lines (121 loc) · 7.14 KB

Performance loop (v2.6.0)

You run unattended for hours. Each wake-up does one item: measure, fix, verify, commit, record. The tracker is the memory between wake-ups, because your context is compacted along the way. Follow AGENTS.md in full; this file only adds to it.

Where

  • Work only in /home/vasylt/Code/rusting/RustingEngine-performance on branch lane/performance. Never edit, commit to, merge into or push main or any other lane's folder. The owner merges.
  • Tracker: performanceImprovement.md in the lane, committed with the work.

Step 0: setup (only when the lane has no tracker yet)

  1. cd /home/vasylt/Code/rusting/RustingEngine-performance, check that git status is clean, then git rebase main.
  2. Copy /home/vasylt/Code/rusting/RustingEngine/performanceImprovement.md into the lane. Append a ## Loop log section at the end, then commit it alone: "Add the v2.6.0 performance plan".

Each wake-up

  1. Orient. Run cd to the lane. If git status is not clean, a previous wake-up was cut off. Read the last ## Loop log entry and either finish that item or git stash push -m "<ID> interrupted" and log it. Then run git rebase main. On a conflict that is not trivial, run git rebase --abort, log it, and continue on the current base.

  2. Pick. Take the first open (- [ ]) item in the order of "Order and lanes", then by phase. Skip:

    • items in "Owner decisions" (see below),
    • items marked [-] (blocked) or [x] (done),
    • items another lane holds (scripts/lane.sh claims).

    Claim it with scripts/lane.sh claim "<ID>". Before you continue, read every file the item touches and trace the real flow end to end. Line numbers in the tracker drift.

  3. Measure before. Use the command in the item's gate or verify line. Otherwise use the closest benchmark below. Record the exact command and the result.

  4. Fix. Make the smallest change that removes the cost at its root.

    • Add no dependency.
    • Keep the physics determinism rules. The bit-identical guards in "Ground rules" must pass unchanged, unless the item says it re-records them.
    • Golden images stay unchanged, unless the item is a declared quality trade.
    • Every change in editor scene edits goes through the snapshot undo.
    • Add the smallest test that fails if the gain regresses (a counter, a call count, an allocation or byte count) when the item has no test yet.
  5. Measure after, with the same command. Take the median of 3 runs for times. Counters need one run.

  6. Full check. Run every command in the AGENTS.md full check, with the gpu-tests run through flock /tmp/rusting-gpu.lock.

  7. Decide.

    • It passes and the number moved: tick the item [x] in the tracker. Under the item, add Done: with the before and after numbers, the command, and the test names. Add one line to the CHANGELOG.md [Unreleased] ### Changed section when users can feel the change. Commit one item per commit, and end the message with Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>. Then run scripts/lane.sh done "<ID>".
    • The check fails and you cannot fix it inside the item, or the gain is under the noise: run git stash push -m "<ID> <reason>". Mark the item [-] with one Blocked: line naming the reason and the stash. Commit only the tracker, drop the claim, and move on. Never loop on one item: after 3 failed attempts, block it.
    • The item is too big for one commit (most of Phase 3): split it into <ID>a, <ID>b and so on under the item. Do the first part now.
  8. Log. Append one line to ## Loop log: date and time, ID, result, commit hash, and the next item.

  9. Continue. Call ScheduleWakeup with delaySeconds: 60, then end the turn.

Discovery sweep (every 5 committed items, and when the list runs dry)

You must also find work that is not in the tracker yet.

  1. Run the benchmark set below, and compare it with the Baseline and Round 2 tables.
  2. Profile the worst case with Nsight Systems on a frame-pointer build: RUSTFLAGS="-C force-frame-pointers=yes" cargo build --release --example <name>, then nsys profile --sample=cpu --trace=vulkan,osrt -o <scratch>/<name> <binary> .... Read the top self and inclusive functions with nsys stats.
  3. Read code that no round has audited yet. grep for these patterns:
    • clone() in per-frame loops
    • Vec::new, collect or format! in per-frame or per-tick paths
    • HashMap with SipHash on hot paths
    • linear find or position scans on large lists
    • world.query without a cached state
    • work done every frame with no change check
  4. For each new cost above 2% of a frame or step, or above 1 MB a frame, append an item with prefix P (P1, P2, …) under ## Found by the loop in the tracker. Use the same form as the other items: the problem with a file and line, the evidence number, the fix, and a gate.
  5. Commit the tracker alone ("Add loop findings P-P").

Benchmarks

Write every output to target/perf-loop/, never to benchmarks/. render_bench compares against an existing JSON file, and writes the file when it does not exist. Use a new file name per run, or delete the old file.

flock /tmp/rusting-gpu.lock cargo run --release --example render_bench -- eco target/perf-loop/<ID>-<n>-eco.json
flock /tmp/rusting-gpu.lock cargo run --release --example render_bench -- high target/perf-loop/<ID>-<n>-high.json
flock /tmp/rusting-gpu.lock cargo run --release --example render_bench -- eco target/perf-loop/<ID>-<n>-bears.json --bears 50000 --bear-updates 50
flock /tmp/rusting-gpu.lock env RUSTING_PERF=1 cargo run --release --features window --example physics_bench -- falling 100000
cargo run --release --example physics_suite
  • The GPU is shared with jobs outside the lock. Before timing, run nvidia-smi --query-compute-apps=pid,process_name --format=csv. Note any other job next to the numbers. Counters (bytes, draws, dispatches, calls) are exact, so trust them over times.
  • /tmp is a 16 GB tmpfs. Keep Nsight files in the session scratchpad, and delete them after you read them. Keep target/perf-loop/ under 1 GB.

Owner decisions: measure, never implement

X1, X5, X17 and any new dependency or build-profile change need the owner's approval. Run the measurement the tracker names (for X5, the LD_PRELOAD jemalloc and tcmalloc runs), write the result under the item, and leave it [ ]. Treat any other change that needs a format break, a re-recorded hash, or a visible quality loss the same way, unless the item already approves it.

Stop

Call ScheduleWakeup with stop: true when one of these is true:

  • The list is finished. Every item outside "Owner decisions" is [x] or [-], and a discovery sweep found nothing new.
  • The build is blocked. main cannot build, or the GPU lock or driver stays broken for 3 wake-ups in a row.

Before stopping, write a ## Loop summary to the tracker and commit it. It lists:

  • the acceptance gates, each with the old number, the new number, and pass or fail,
  • the blocked items and why,
  • the owner decisions with their measurements.