Skip to content

perf: add MessagePipe attribution benchmarks - #419

Merged
Eli Pinkerton (wallstop) merged 1 commit into
masterfrom
session-215-messagepipe-attribution
Aug 15, 2026
Merged

perf: add MessagePipe attribution benchmarks#419
Eli Pinkerton (wallstop) merged 1 commit into
masterfrom
session-215-messagepipe-attribution

Conversation

@wallstop

@wallstop Eli Pinkerton (wallstop) commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add four fixed-cycle registration attribution rows for direct bus, direct handler,
    disabled-token, and active-token register/remove paths
  • add a direct-handler one-listener dispatch row beside the existing token-augmented row
  • pin exact layer state, registration ownership, leak-free teardown, benchmark ordering,
    result extraction, rendering, and stable scenario keys
  • document how to interpret the new timing and allocation deltas

Why

Issue #414 shows that DxMessaging trails MessagePipe most strongly on fixed-overhead
one-listener dispatch and subscribe/unsubscribe churn, while higher-fan-out and keyed
rows are much closer or faster. The previous dispatch candidate did not clear the
repository's A/B/A claim threshold. These diagnostics isolate the bus, handler, token,
and augmented-callback layers before another production optimization is attempted.

No production runtime path changes in this pull request.

Measurement contract

  • Registration latency uses 131072 complete register/remove cycles, one cached by-ref
    handler, seven fresh timing states, and the minimum wall-clock sample.
  • Allocation instrumentation is separate from latency. Each of seven Mono attempts
    warms 10000 cycles on one state, then measures a second 10000-cycle batch so the
    allocation state matches the warmed SubUnsub comparison shape.
  • Release IL2CPP keeps reporting allocation as n/a because its profiler recorder is
    stripped.
  • UntargetedFlood_OneDirectHandler and UntargetedFlood_OneHandler share the payload,
    active handler, priority, by-ref fast slot, and fan-out; token ownership and the
    augmented callback are the intended variable.

Validation

  • npm test (421 passed)
  • npm run format:check
  • npm run lint:markdown
  • npm run check:spelling
  • npm run validate:all
  • dotnet tool run csharpier check .
  • node --test scripts/__tests__/unity-perf.test.js (29 passed)
  • git diff --check
  • two adversarial review tracks, both ending with zero actionable findings
  • Unity MCP runtime benchmark contracts (23 passed, 0 failed)
  • Unity MCP editor benchmark harness (119 passed, 0 failed)
  • Unity MCP preflight/postflight: clean scene, main stage, idle editor

Related: #414


Note

Low Risk
Changes are limited to benchmarks, tests, documentation, and scenario rendering; production messaging paths are untouched.

Overview
Adds diagnostic perf harness only (no production runtime changes) to isolate MessagePipe-related overhead before further optimizations.

Registration attribution introduces four wall-clock rows (RegistrationAttribution_*_131072) that time complete register/remove cycles through direct bus, direct handler, disabled token, and active token paths, with separate allocation batches aligned to the comparison SubUnsub shape. A new RegistrationAttributionBenchmark entry runs on DispatchThroughputBenchmarks at NUnit order 1, between published dispatch (0) and deregistration attribution (2).

Dispatch attribution adds UntargetedFlood_OneDirectHandler beside the existing token-augmented one-handler row so token ownership and the augmented callback are the only variables. Contract observations now track token vs direct registration ownership, and BenchmarkRegistrationScope can register untargeted handlers directly with proper teardown.

Tooling & docs: perf-scenarios.js, unity perf tests, and the perf methodology runbook are updated for 35 dispatch scenarios (including the eight attribution rows), stable keys, and interpretation notes. Contract tests pin exact per-layer state, scenario keys, and benchmark ordering.

Reviewed by Cursor Bugbot for commit bf2469c. Bugbot is set up for automated code reviews on this repo. Configure here.

@wallstop
Eli Pinkerton (wallstop) marked this pull request as ready for review August 15, 2026 01:44
Copilot AI lite review requested due to automatic review settings August 15, 2026 01:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

Copy link
Copy Markdown
Contributor

Performance Numbers

Measured commit: bf2469c
Trusted reporting code (PR base): 5e99d66
Workflow run: 31857267407 attempt 1

Benchmark or harness paths changed, so historical deltas are non-comparable:

  • Tests/Editor/Allocations/BenchmarkHarnessRobustnessTests.cs
  • Tests/Runtime/Benchmarks/BenchmarkProtocol.cs
  • Tests/Runtime/Benchmarks/DispatchThroughputBenchmarks.cs
  • Tests/Runtime/Benchmarks/RegistrationLifecycleBenchmarkContractTests.cs
  • Tests/Runtime/Benchmarks/RegistrationLifecycleBenchmarks.cs
  • scripts/unity/perf-scenarios.js

Historical Standalone delta

Delta direction: + is better; - is worse.

Historical delta omitted because benchmark or harness code changed in this pull request.

Current TargetMap evidence

These raw rows are current-run diagnostics. Use fresh bracketed controls before accepting a micro-optimization.

[Standalone] DXM_TARGET_MAP_BENCHMARK scenario=TargetMap_16_Churn keyCount=16 operation=Churn totalOperations=1890000 operationsPerSecond=377168.336 wallClockMs=5011.025 gcAllocations=-1 gcAllocatedBytes=-1 targetMapEntries=16 targetMapCapacity=32 observedInvocations=1910000
[Standalone] DXM_TARGET_MAP_BENCHMARK scenario=TargetMap_16_Hit keyCount=16 operation=Hit totalOperations=48470000 operationsPerSecond=9692057.130 wallClockMs=5001.002 gcAllocations=-1 gcAllocatedBytes=-1 targetMapEntries=16 targetMapCapacity=32 observedInvocations=48490000
[Standalone] DXM_TARGET_MAP_BENCHMARK scenario=TargetMap_16_Miss keyCount=16 operation=Miss totalOperations=56710000 operationsPerSecond=11340391.932 wallClockMs=5000.709 gcAllocations=-1 gcAllocatedBytes=-1 targetMapEntries=16 targetMapCapacity=32 observedInvocations=0
[Standalone] DXM_TARGET_MAP_BENCHMARK scenario=TargetMap_1_Churn keyCount=1 operation=Churn totalOperations=2090000 operationsPerSecond=416897.323 wallClockMs=5013.225 gcAllocations=-1 gcAllocatedBytes=-1 targetMapEntries=1 targetMapCapacity=4 observedInvocations=2110000
[Standalone] DXM_TARGET_MAP_BENCHMARK scenario=TargetMap_1_Hit keyCount=1 operation=Hit totalOperations=52110000 operationsPerSecond=10421323.865 wallClockMs=5000.324 gcAllocations=-1 gcAllocatedBytes=-1 targetMapEntries=1 targetMapCapacity=4 observedInvocations=52130000
[Standalone] DXM_TARGET_MAP_BENCHMARK scenario=TargetMap_1_Miss keyCount=1 operation=Miss totalOperations=62560000 operationsPerSecond=12511873.130 wallClockMs=5000.051 gcAllocations=-1 gcAllocatedBytes=-1 targetMapEntries=1 targetMapCapacity=4 observedInvocations=0
[Standalone] DXM_TARGET_MAP_BENCHMARK scenario=TargetMap_256_Churn keyCount=256 operation=Churn totalOperations=1750000 operationsPerSecond=349599.429 wallClockMs=5005.729 gcAllocations=-1 gcAllocatedBytes=-1 targetMapEntries=256 targetMapCapacity=512 observedInvocations=1770000
[Standalone] DXM_TARGET_MAP_BENCHMARK scenario=TargetMap_256_Hit keyCount=256 operation=Hit totalOperations=46000000 operationsPerSecond=9199210.340 wallClockMs=5000.429 gcAllocations=-1 gcAllocatedBytes=-1 targetMapEntries=256 targetMapCapacity=512 observedInvocations=46020000
[Standalone] DXM_TARGET_MAP_BENCHMARK scenario=TargetMap_256_Miss keyCount=256 operation=Miss totalOperations=55710000 operationsPerSecond=11141006.445 wallClockMs=5000.446 gcAllocations=-1 gcAllocatedBytes=-1 targetMapEntries=256 targetMapCapacity=512 observedInvocations=0
[Standalone] DXM_TARGET_MAP_BENCHMARK scenario=TargetMap_4096_Churn keyCount=4096 operation=Churn totalOperations=1370000 operationsPerSecond=271494.545 wallClockMs=5046.142 gcAllocations=-1 gcAllocatedBytes=-1 targetMapEntries=4096 targetMapCapacity=8192 observedInvocations=1390000
[Standalone] DXM_TARGET_MAP_BENCHMARK scenario=TargetMap_4096_Hit keyCount=4096 operation=Hit totalOperations=41830000 operationsPerSecond=8365165.491 wallClockMs=5000.499 gcAllocations=-1 gcAllocatedBytes=-1 targetMapEntries=4096 targetMapCapacity=8192 observedInvocations=41850000
[Standalone] DXM_TARGET_MAP_BENCHMARK scenario=TargetMap_4096_Miss keyCount=4096 operation=Miss totalOperations=54420000 operationsPerSecond=10881956.151 wallClockMs=5000.939 gcAllocations=-1 gcAllocatedBytes=-1 targetMapEntries=4096 targetMapCapacity=8192 observedInvocations=0
[Standalone] DXM_TARGET_MAP_BENCHMARK scenario=TargetMap_4_Churn keyCount=4 operation=Churn totalOperations=2040000 operationsPerSecond=406779.166 wallClockMs=5015.006 gcAllocations=-1 gcAllocatedBytes=-1 targetMapEntries=4 targetMapCapacity=8 observedInvocations=2060000
[Standalone] DXM_TARGET_MAP_BENCHMARK scenario=TargetMap_4_Hit keyCount=4 operation=Hit totalOperations=55430000 operationsPerSecond=11081145.129 wallClockMs=5002.191 gcAllocations=-1 gcAllocatedBytes=-1 targetMapEntries=4 targetMapCapacity=8 observedInvocations=55450000
[Standalone] DXM_TARGET_MAP_BENCHMARK scenario=TargetMap_4_Miss keyCount=4 operation=Miss totalOperations=58680000 operationsPerSecond=11734839.424 wallClockMs=5000.495 gcAllocations=-1 gcAllocatedBytes=-1 targetMapEntries=4 targetMapCapacity=8 observedInvocations=0
[Standalone] DXM_TARGET_MAP_CONSTRUCTION keyCount=1 wallClockMs=0.000104 operationsPerSecond=9578544.061 gcAllocations=-1 gcAllocatedBytes=-1 targetMapCapacity=4
[Standalone] DXM_TARGET_MAP_CONSTRUCTION keyCount=16 wallClockMs=0.000625 operationsPerSecond=1600000.000 gcAllocations=-1 gcAllocatedBytes=-1 targetMapCapacity=32
[Standalone] DXM_TARGET_MAP_CONSTRUCTION keyCount=256 wallClockMs=0.008350 operationsPerSecond=119760.479 gcAllocations=-1 gcAllocatedBytes=-1 targetMapCapacity=512
[Standalone] DXM_TARGET_MAP_CONSTRUCTION keyCount=4 wallClockMs=0.000209 operationsPerSecond=4789272.031 gcAllocations=-1 gcAllocatedBytes=-1 targetMapCapacity=8
[Standalone] DXM_TARGET_MAP_CONSTRUCTION keyCount=4096 wallClockMs=0.124400 operationsPerSecond=8038.585 gcAllocations=-1 gcAllocatedBytes=-1 targetMapCapacity=8192

@wallstop
Eli Pinkerton (wallstop) merged commit 22110d8 into master Aug 15, 2026
46 of 47 checks passed
@wallstop
Eli Pinkerton (wallstop) deleted the session-215-messagepipe-attribution branch August 15, 2026 02:07
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.

2 participants