Skip to content

[Docs] Actors and locks: benchmark, lock census of the frame and rules - #66

Merged
miogds merged 2 commits into
developfrom
docs/actors_and_locks
Oct 3, 2026
Merged

miogds merged 2 commits into
developfrom
docs/actors_and_locks

Conversation

@miogds

@miogds miogds commented Oct 3, 2026

Copy link
Copy Markdown
Member

What

Research on two questions, with the tools to re-run it. No engine code changes.

  1. May engine code use Swift actors, or are they too slow next to locks?
  2. Does the per-frame path use the best lock mechanism?

Contents

  • docs/proposals/ActorsAndLocks.md: results, proposed rules for engine and editor, review of the critical path, how to reproduce, limits.
  • Examples/ConcurrencyBench: standalone package (macOS 15) that measures an actor against NSLock, NSRecursiveLock, OSAllocatedUnfairLock, Mutex and a serial queue.
  • Tests/UntoldEngineRenderTests/LockCensusTests.swift: opt-in test (UNTOLD_LOCK_CENSUS=1, skipped otherwise) that counts every NSLock / NSRecursiveLock acquisition in renderer.draw and names the function that made it.

Findings (Mac16,5, release builds)

  • Actors: not for state the frame touches. A synchronous thread reaches an actor only through a Task; the wait is 7 µs with the thread pool idle and 2.4 to 24 ms (median) with the pool full of asset jobs. A lock stays under 1 µs. Actors are fine at the async edges (the three the engine has) and in the editor.
  • Locks: the frame takes about 130 to 140 locks per entity (564,000 per frame at 4,000 cubes), almost all uncontended. 98 % come from the scene global getter, the component-id map and the scene-channel render-mode check.
  • Cost: swapping those locks for unfair locks cuts renderer.draw by 6 to 7 %; removing per-access locking (ceiling, not a shippable change) cuts it by 25 to 28 %.

Verified

  • swift build -c release of Examples/ConcurrencyBench, all five sections run.
  • LockCensusTests run in debug and release at 1,000 and 4,000 cubes; skipped without the environment variable.
  • swiftformat --lint on the new Swift files, commit prefix check.

Javier Segura added 2 commits October 3, 2026 16:26
Research note docs/proposals/ActorsAndLocks.md with its two tools:

- Examples/ConcurrencyBench: standalone package that measures a Swift
  actor against NSLock, NSRecursiveLock, OSAllocatedUnfairLock, Mutex
  and a serial queue (uncontended, contended, latency seen by a
  synchronous thread with the thread pool idle and saturated, a pass
  over 10,000 entities).
- LockCensusTests: opt-in render test (UNTOLD_LOCK_CENSUS=1) that counts
  every NSLock / NSRecursiveLock acquisition in renderer.draw and
  attributes it to the engine function that made it.

No engine code changes.
…velop

Same text as the upstream PR (untoldengine#1294), so the note merges cleanly at the next sync. The counts are identical; the frame times are a second set of runs.
@miogds
miogds merged commit 16d2598 into develop Oct 3, 2026
7 of 8 checks passed
@miogds
miogds deleted the docs/actors_and_locks branch October 3, 2026 16:24
miogds pushed a commit that referenced this pull request Oct 3, 2026
miogds pushed a commit that referenced this pull request Oct 3, 2026
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.

1 participant