Skip to content

perf(discovery): pipeline MMS model discovery with smart enrichment - #134

Open
masarray wants to merge 25 commits into
mainfrom
perf/smart-ied-discovery
Open

masarray wants to merge 25 commits into
mainfrom
perf/smart-ied-discovery

Conversation

@masarray

@masarray masarray commented Sep 16, 2026

Copy link
Copy Markdown
Owner

Why

The ARSAS-vs-IEDScout capture audit showed that the current consumer path can amplify initial discovery into ~30.7k confirmed MMS requests (~23.7k GetVariableAccessAttributes and ~6.6k Read) while using only ~1-2 requests in flight, even though the tested association negotiated about 10 outstanding calls. The objective of this PR is to make the engine capable of an IEDScout-like pipelined discovery pattern while preserving ARIEC61850's correctness and receive-pump invariants.

What changed

Smart structural discovery

  • Adds MmsClientSession.DiscoverSmartAsync and MmsSmartDiscoveryOptions.
  • Enumerates the VMD/domain list once per smart discovery generation.
  • Pipelines independent (domain, object-class) GetNameList chains with bounded concurrency.
  • Caps the effective window by negotiated maxOutstandingCalling; unknown peers use a conservative fallback cap.
  • Keeps every moreFollows/continueAfter chain strictly sequential.
  • Rebuilds results in deterministic domain order after concurrent completion.
  • Preserves successful domain branches when another chain returns an MMS-level failure.
  • Does not perform eager per-leaf Read/GVA during structural discovery.

Association-scoped single-flight

  • Adds DiscoverSmartSingleFlightAsync as the consumer-facing orchestration wrapper for repeated smart discovery on one accepted MMS association.
  • Identical smart discovery profiles share one in-flight/completed wire operation while the accepted association marker, host, and port remain unchanged.
  • A caller cancellation only cancels that waiter through Task.WaitAsync; it does not cancel the shared wire operation.
  • Partial/faulted smart results are not retained as reusable cache, so later callers may retry rather than inheriting poisoned discovery state.
  • A reconnect naturally invalidates the single-flight entry because the accepted association marker changes.

Structure-first exact type enrichment

  • Adds GetVariableAccessAttributesSmartAsync.
  • Probes LN$FC$DO roots first.
  • Uses the returned structured TypeSpecification hierarchy when available.
  • Falls back to exact leaf GVA only for roots that fail or do not describe descendants.
  • Uses the same bounded association-aware request window.

Safe request pipelining

  • Adds a single-writer gate to TpktClient.SendTpktAsync so concurrent confirmed requests cannot interleave TPKT frame bytes.
  • This gate protects only frame writes; it does not serialize request/response lifecycles.
  • The existing single MMS receive pump and invoke-ID routing remain unchanged.

Documentation

  • Adds docs/SMART_MMS_DISCOVERY.md with invariants, migration example, capture baseline, and acceptance KPIs.

Compatibility

The existing DiscoverAsync and GetVariableAccessAttributesBatchAsync APIs remain unchanged. DiscoverSmartAsync remains available for callers that deliberately want an uncached generation; DiscoverSmartSingleFlightAsync is additive for consumers that need association-scoped deduplication.

Correctness / safety invariants

  • one receive pump per association;
  • no parallel raw/socket reads;
  • invoke-ID correlation remains authoritative;
  • continuation pages within one GetNameList chain are never parallelized;
  • negotiated outstanding-call limit is respected when decoded;
  • final published model ordering is deterministic;
  • waiter cancellation does not tear down a shared discovery generation;
  • partial/faulted discovery does not poison the reusable single-flight cache.

Acceptance target

This PR is designed to close the observed scheduling/orchestration gap; it does not claim to be faster than IEDScout until the same IED is re-captured after consumer integration. Acceptance should compare TTFI/TTFT, final LD/LN/FC-point/dataset counts, request count by MMS service, peak outstanding calls, partial-domain status, exact type coverage, and whether any second GetNameList sweep occurs on the same association.

Base: 3afc924c97627fe86adbe784c905e2f35dff0b1a (latest main at branch creation).

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

Preserve named semantic leaves proven by logical-node GetVariableAccessAttributes trees in the canonical live directory without adding per-leaf MMS requests. Existing observed GetNameList points remain authoritative; unknown FCs, arrays, and anonymous placeholders are skipped.

Copy link
Copy Markdown
Owner Author

R3 hardening committed at 1b7cbbe8af3dfbc2a15086cb2c3e5eff02e006bb.

Adds association-scoped DiscoverSmartSingleFlightAsync:

  • identical smart profiles share one wire discovery on the accepted association;
  • waiter cancellation uses Task.WaitAsync and does not cancel the shared operation;
  • partial/faulted discovery is not retained as reusable cache;
  • association marker + host/port changes invalidate reuse on reconnect.

.NET CI run #628 (35123807877) completed successfully: source verification, restore, build, test, packaging and artifact upload all passed.

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