Skip to content

perf: reduce subscription churn and retained registration storage #502

Description

Part of #497 and the SubUnsub outcome in #414.

Inputs and dependencies

Exploration may begin earlier. Production confirmation waits for the #500 gates.

Purpose

Reduce registration and deregistration time, allocation calls, copied state, and retained storage without moving steady dispatch or weakening stale-handle safety.

Current representation

MessageRegistrationToken already has a slot array, doubly linked live list, and free list. This issue must not recreate that mechanism under a new name.

Concrete attributed candidates include:

  • one process-wide atomic ID increment per staged registration;
  • large copied MessageBusRegistration and typed deregistration state;
  • Dictionary plus List ordered spill storage with a dictionary lookup during ordered iteration and O(n) arbitrary list removal.

Owned experiments

  • Attribute every registration/deregistration allocation and copied byte by owner.
  • Measure direct bus, direct handler, token stage/active, remove, and disable at 1/16/256/1,000 live registrations.
  • Test owner-local generational handles: one token-owner identity plus slot and generation, with a burned slot on wrap.
  • Keep the internal handle at or below the current 16 bytes and preserve the public factory path where process-wide uniqueness is required.
  • Test a bus-owned generational registration-record arena with a small opaque built-in handle while preserving custom IMessageBus ExternalId/ExternalState behavior.
  • Test a compact ordered spill store: sparse hash index to append-ordered dense records, scrubbed tombstones, and transactional density-based compaction.
  • Apply the ordered-store experiment to HandlerActionCache spill first. Extend it to bus handler/priority stores only after that mechanism wins.
  • Test indexed or intrusive removal separately from storage layout.
  • Test bounded slabs or pools only for an attributed allocation owner.
  • Prototype batch register, enable, disable, and deregister transactions that validate, invalidate, and roll back once.
  • Measure delegate equality/hash cost for static, instance, capturing, equal, and duplicate delegates.
  • Revisit exact-MessageBus deregistration only when perf lab: resolve IL2CPP cost with WPR, PMU, and native maps #511 still shows the relevant indirect call and perf lab: calibrate variance, controls, power, and confirmatory inference #510 makes the lifecycle bracket interpretable.
  • Measure cold prewarm, high-water capacity, occupied slots, idle sweep, force trim, and retained Unity references.

Do not repeat object-only token recycling or rejected inline-plus-ordinary-spill layouts without a materially different mechanism.

RED and correctness

  • Extend test: build a differential bus state-machine oracle #509 with copied, double, foreign-token, out-of-order, stale, reset, reuse, and forced-wrap handles.
  • Cover owner destruction, partial failure, remove/register during dispatch, duplicate refcounts, and remove/re-add ordering.
  • Use LeakWatcher around 10,000 complete cycles.
  • Return occupied slots and retained buffers to configured caps after sweep or trim.
  • Clear every delegate, captured object, and Unity object reference before reuse.
  • Keep every emit allocation row at zero.
  • Preserve custom IMessageBus round trips and retryable failure behavior.

Acceptance

  • The declared lifecycle endpoint passes perf lab: calibrate variance, controls, power, and confirmatory inference #510; the normal target boundary remains greater than 3%.
  • Registration-cycle GC.Alloc calls do not increase. An allocation candidate must reduce its declared count or establish a structural zero.
  • Handle size, copied bytes, probes, tombstones, compactions, and retained capacity are reported.
  • Dispatch affected rows and equivalent sentinels pass their registered gates.
  • Differential, lifecycle, leak, reclamation, allocation, and public-surface gates pass.
  • A sealed holdout supports the result.
  • Every representation receives a retained decision.

Route maps and middleware are out of scope.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions