Skip to content

docs: performance plan for the cursor ray and traffic spawn spikes (#43) - #545

Merged
ZaneThurston merged 3 commits into
mainfrom
docs/plano-desempenho
Oct 28, 2026
Merged

ZaneThurston merged 3 commits into
mainfrom
docs/plano-desempenho

Conversation

@ZaneThurston

@ZaneThurston ZaneThurston commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

What changes for the player?

Nothing. Documentation only: docs/PERFORMANCE_PLAN.md.

How to test

Nothing to test in game. Read the plan and check that the code references (update_hover, hovered_part, pick_in, nearest_blocker, populate_seen, populate_kind, wake_dormant, road_scale) match main.

What does this change, and why?

Adds the plan that came out of the #43 measurements (OMSI_PROFILE sessions of 24/10 and 25/10/2026):

  • Cursor ray: 93 % of the time in the frames over 50 ms. Each query tests the ray against every triangle of the cab and trailers, repeats the central ray, and runs once per mouse event plus once per frame. Plan: one query per frame with reused transforms (fix/cursor-uma-consulta), then a per-mesh BVH in omsi-geometry (fix/cursor-arvore-malha).
  • Traffic spawning: the car target grows with the lanes nearby and the whole deficit is spawned in one call (46 ms at the first population; 250–500 ms frames when the count went from 122 to 303 in a dense area). Plan: measure the populate sub-stages (feat/profile-povoacao), then a per-call spawn budget plus the first population during loading (fix/transito-orcamento-povoacao).

One PR at a time, each with a before/after measurement. The traffic cause of 25/10 is not yet measured with the profiler; the plan says so.

Checklist

  • cargo test --workspace and cargo build --release pass (docs only, no code change)
  • The pull request contains a single change
  • The changes are based on the latest available commit

Requested by Zane

🤖 Generated with Claude Code

Plan from the #43 measurements: the cabin cursor ray (one query per frame,
then a per-mesh BVH) and traffic spawning (measure, then a per-call budget).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copy link
Copy Markdown
Contributor

Thanks, Zane. I read the plan against main (f6a59fe) and the diagnosis matches the code: the eye is inside the cab meshes' spheres so ray_may_hit rejects nothing, pick_in casts up to 25 rays, and nearest_blocker / hovered_body_part repeat the central ray over every mesh. Nothing here blocks the docs PR. Notes to carry into the follow-up PRs:

Click parity (1:1)

  1. The BVH should only cull nodes (conservative slab test with an epsilon) and still run the same ray_triangle in mesh space, so every t stays bit-identical. Switch choice depends on the 3 cm depth band in best_mouseevent_hit, the 5 mm MOUSEEVENT_BLOCK_MARGIN and the t > 0.02 cut in nearest_blocker; keep the tie-break (first lowest t).
  2. cone_triangles is a cone filter, not a ray test. A BVH version must return a superset (conservative cone-vs-AABB); that is safe because the rays are re-tested afterwards.
  3. Before changing code, record a golden set from a real vehicle (Aachen ibox, a VDV panel, an articulated bus): a grid of cursor rays with the picked mesh index, hover name and hover_hand. Assert identical output old vs new, plus a randomized BVH vs full-scan comparison per mesh.
  4. One query per frame: click() takes a fresh ray, so clicks are unaffected, but check everything that reads self.hover at press time (touch, OMSI_INPUT, VR pointer). The cursor-kind (hand) may lag one frame; worth stating.
  5. Building the BVH on the first query would itself be a hitch. Build at vehicle load on the background pool, or fall back to the full test until it is ready.

Cheap wins for PR 1 (no BVH)

  • Compute transform.inverse() once per mesh per query instead of once per mesh per ray.
  • Skip hovered_body_part (full scan) when nothing needs hover_part; worth confirming who reads it (HUD name only?).
  • Reuse the central-ray result between nearest_blocker and hovered_body_part (already in the plan), and reuse the rings / candidates Vecs.

Measuring
Besides the sub-stages, a synthetic cab (~300 meshes, ~200k triangles, ~40 [mouseevent] meshes, eye inside the bounding sphere) for a micro-benchmark in omsi-geometry, plus an end-to-end OMSI_PROFILE=1 run in the driver camera with the cursor sweeping a fixed path via OMSI_INPUT, reporting p50/p99 of player.hover.

Traffic
The plan is sound. It would help to also record how many cars one populate call creates and the time per car, split between loading the vehicle type (model/textures) and instantiating it. If type loading dominates, a per-call budget only spreads the cost and pre-warming types at load would be needed. Tests that count cars right after populate will need to loop until the target is reached.

Nit
docs/PERFORMANCE_PLAN.md is written in Portuguese, and the repo convention is English for everything written in it, so it would be good to translate it before merging.


Generated by Claude Code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ZaneThurston ZaneThurston changed the title docs: plano de desempenho do raio do cursor e dos picos de trânsito (#43) docs: performance plan for the cursor ray and traffic spawn spikes (#43) Oct 28, 2026
…raffic timing

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copy link
Copy Markdown
Contributor Author

Thanks for the review. Addressed in e064669 and d1eae53:

  • Nit (English): the plan is now in English (e064669).
  • Click parity: the BVH only culls (conservative slab test with an epsilon) and runs the same ray_triangle in mesh space, so t stays bit-identical and the tie-break is kept; cone_triangles returns a conservative superset. The 3 cm band, the 5 mm block margin and the t > 0.02 cut are named as fixed. A golden set (Aachen ibox, a VDV panel, an articulated bus) is recorded before any code change and asserted by both cursor PRs, plus a randomized BVH vs full-scan check in PR 2.
  • BVH build: at vehicle load on the background pool, with the full test as fallback until it is ready.
  • PR 1 cheap wins: inverse once per mesh per query, reused rings/candidates buffers, and hovered_body_part skipped when hover_part is not read. Its only reader today is the log command of OMSI_INPUT scripts (input_script.rs), not the HUD. The one-frame lag of the hand cursor and the press-time readers of hover are stated.
  • Measuring: synthetic-cab micro-benchmark in omsi-geometry and an OMSI_INPUT cursor sweep reporting p50/p99 of player.hover.
  • Traffic: PR 3 records cars per call and time per car split between type loading and instantiation; if type loading dominates, types are pre-warmed at load.

Generated by Claude Code

@ZaneThurston
ZaneThurston merged commit c080491 into main Oct 28, 2026
7 checks passed
@ZaneThurston
ZaneThurston deleted the docs/plano-desempenho branch October 28, 2026 15:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants