-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture Performance
This page shows the latest dispatch-throughput and cross-library comparison numbers for DxMessaging. The tables are auto-generated by CI: every pull request and push re-runs the benchmark suite with the .NET Standard 2.1 API profile and a Release code-optimization build, then renders the results into the AUTOGENERATED region below. Numbers are measured in two scopes -- in-editor PlayMode under Mono (the headline, the backend the library ships with for most targets) and a built Standalone player under IL2CPP (ahead-of-time coverage for platforms that require it).
These numbers are for orientation, not a leaderboard. Real-world performance depends on what your handlers actually do; the benchmarks measure raw dispatch cost with minimal handler work. For the full methodology, CI mechanics, baseline capture, the regression smoke gate, and how to add or bump a comparison library, see the ..-Runbooks-Perf-Benchmark-Methodology.
See also: .-Design-And-Architecture#performance-optimizations for design details.
- Scopes. Each dispatch table is labeled by execution scope and backend. PlayMode (Mono) is in-editor play mode on the backend the library ships with for most targets, and is the headline scope. Standalone (IL2CPP) is a built player on the ahead-of-time backend some platforms require, published alongside for AOT coverage. The two run different backends, so their numbers differ by design; read each against its own backend.
- Throughput. Reported as emits per second. Higher is better. Registration scenarios report wall-clock time instead, where lower is better.
-
Allocations. Reported as bytes per operation.
0is best for hot-path dispatch; any non-zero allocation on a dispatch scenario is something to explain (see the runbook). -
Comparison matrix
N/A. The cross-library matrix has a column per scenario and a row per library. A cell showsN/Awhen that library does not idiomatically support that capability -- it is a capability gap, not a failure, and the value is never faked.
The block below is regenerated by the Performance Numbers workflow
(.github/workflows/perf-numbers.yml) via scripts/unity/render-perf-doc.js. It
contains one dispatch-throughput table per execution scope (PlayMode and
Standalone) plus two cross-library comparison matrices -- one for throughput and
one for bytes per operation. The block also carries a privacy-safe provenance
line describing the runner hardware (CPU, cores, clock, RAM, GPU, OS), never a
hostname or runner name. On a pull request the refreshed numbers are posted as a
non-blocking sticky comment; after the pull request merges, the same workflow
commits the refreshed tables -- and the sibling baseline
perf-baseline.csv that the regression gate compares against -- directly to the
default branch when the auto-commit App is provisioned and the branch has not
advanced past the measured commit. Do not edit it by hand. See the
..-Runbooks-Perf-Numbers-Auto-Commit for
the repo-settings prerequisite that lets CI push to the default branch.
The dispatch throughput table populates after the first default-branch CI benchmark run.
| Scenario | Throughput / Wall clock | Allocated bytes |
|---|---|---|
| Pending first CI benchmark run | - | - |
The cross-library comparison matrices above measure DxMessaging against other common Unity messaging and eventing approaches on the same apples-to-apples scenarios:
- External libraries: MessagePipe, UniRx MessageBroker, Zenject SignalBus, and Unity Atoms.
-
Zero-dependency baselines: plain C# event, UnityEvent, a ScriptableObject
event channel, and Unity
SendMessage.
Each library implements only the scenarios it idiomatically supports;
unsupported cells render N/A. The comparison suite source lives in
Tests/Runtime/Comparisons/.
For a feature-by-feature discussion of when each approach wins, see the
.-Comparisons.
Dispatch state is stored per message type and, for targeted and broadcast
paths, per InstanceId. Long-running sessions accumulate slots for every
type or entity ever touched unless something reclaims them. The memory
reclamation system caps that growth without changing dispatch semantics or
allocating during emit.
Reclamation runs on two paths:
- An idle sweep that runs from emit-time clock samples and the Unity
PlayerLoop, gated by
DxMessagingRuntimeSettings.EvictionEnabledandEvictionTickIntervalSeconds. Empty slots become eligible only after remaining empty for at leastIdleEvictionSecondsof wall time. - An explicit
IMessageBus.Trim(force)andMessageHandler.TrimAll(force)pair that runs synchronously at scene boundaries, in tests, or in maintenance windows. The master switchEnableTrimApicontrols whether the explicit calls perform work; idle sweeps remain controlled byEvictionEnabledindependently.
Active registrations are never reclaimed. Only empty slots and shared pool entries are touched. Sweep work runs outside the hot handler loop, so emit throughput is unaffected; the per-emit overhead is one branch that samples the wall clock.
For tuning recommendations, the public Trim and diagnostic-counter API
surface, and worked examples (scene transitions, leak diagnosis, mobile
caps, shipped-title configurations), see the
..-Guides-Memory-Reclamation. For the
parameter reference, see the
..-Reference-Runtime-Settings.
- Getting-Started-Overview
- Getting-Started-Getting-Started
- Getting-Started-Install
- Getting-Started-Quick-Start
- Getting-Started-Visual-Guide
- Concepts-Message-Types
- Concepts-Listening-Patterns
- Concepts-Targeting-And-Context
- Concepts-Interceptors-And-Ordering
- Guides-Patterns
- Guides-Unity-Integration
- Guides-Testing
- Guides-Diagnostics
- Guides-Advanced
- Guides-Migration-Guide
- Advanced-Emit-Shorthands
- Advanced-Message-Bus-Providers
- Advanced-Runtime-Configuration
- Advanced-String-Messages
- Reference-Reference
- Reference-Quick-Reference
- Reference-Helpers
- Reference-Faq
- Reference-Glossary
- Reference-Troubleshooting
- Reference-Compatibility
Links