Skip to content

fix: suppress Npcap SV catch-up bursts after scheduler lateness - #49

Merged
masarray merged 2 commits into
mainfrom
fix/sv-transmit-burst-pacing
Aug 3, 2026
Merged

fix: suppress Npcap SV catch-up bursts after scheduler lateness#49
masarray merged 2 commits into
mainfrom
fix/sv-transmit-burst-pacing

Conversation

@masarray

@masarray masarray commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Summary

Hardens live Sampled Values transmission when a Windows publisher thread is delayed by foreground UI load, window focus changes, GC or scheduler contention.

Problem

A deadline-driven publisher can become late and then call SendAsync repeatedly while catching up. The existing Npcap transport injected every queued SV frame immediately, producing a micro-burst. On a local loopback adapter this could still overflow receiver/capture scheduling, exposing smpCnt gaps and unstable downstream waveform/phasor presentation.

Change

  • serializes injection on the opened Npcap device;
  • identifies outgoing SV streams using an allocation-free Ethernet/VLAN/APPID key;
  • learns each stream's normal send interval from actual steady transmission;
  • anchors each following interval to the actual previous send time, so a late frame is sent once and subsequent frames resume paced transmission rather than bursting;
  • rejects ultra-short burst intervals and long scheduler stalls from interval learning;
  • keeps GOOSE/PTP/non-SV traffic unpaced;
  • keeps independent pacing clocks for each source/destination/APPID/VLAN identity;
  • avoids reparsing the SV APDU or allocating strings/objects in the transmit hot path.

Scope

Frame encoding, smpCnt, reference timestamps, quality, APPID, VLAN and capture behavior are unchanged. This is a transport-level burst-suppression guard for best-effort Windows/Npcap laboratory publishing.

@masarray
masarray marked this pull request as ready for review August 3, 2026 06:58

masarray commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

Final validation:

  • Public-source/provenance/license verification passed.
  • Windows Release solution build succeeded with 0 warnings and 0 errors.
  • AR.Iec61850.Tests: 438/438 passed.
  • Test diagnostic artifact uploaded.
  • Npcap transmission now uses an allocation-free Ethernet/VLAN/APPID stream key.
  • Each SV stream learns its normal steady send interval.
  • After scheduler lateness, the first late frame may send immediately, but following frames are paced from the actual previous send time instead of being injected as a catch-up burst.
  • GOOSE, PTP and other non-SV traffic remain unpaced.
  • Frame encoding, sample counters, reference time and quality are unchanged.

@masarray
masarray merged commit b90700a into main Aug 3, 2026
1 check passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 674d351017

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +196 to +198
var learnable = observedInterval >= MinimumLearnableIntervalTicks &&
observedInterval <= MaximumLearnableIntervalTicks &&
(nominalInterval <= 0 || observedInterval <= nominalInterval * 3);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Avoid learning the pacing rate from a late interval

When the thread is delayed between the first two frames, any gap from 20 µs through 5 ms is accepted as the nominal interval, even though it may be scheduler lateness rather than the requested rate. For example, a 4,000 fps publisher preempted for 1 ms after its first send learns 1 ms; subsequent pacing then enforces that interval, and because later observations are taken after pacing, the clock cannot converge back to 250 µs. This permanently reduces the wire rate while smpCnt and reference timestamps continue to represent the configured rate. Seed or update the estimate only from demonstrated steady intervals rather than accepting the first in-range observation.

AGENTS.md reference: AGENTS.md:L173-L178

Useful? React with 👍 / 👎.

Comment on lines +51 to +53
var isSampledValues = TryReadSampledValuesKey(frame.Span, out var streamKey);
if (isSampledValues)
await PaceSampledValuesAsync(streamKey, cancellationToken).ConfigureAwait(false);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep SV pacing from blocking unrelated traffic

When SV and PTP or GOOSE share this duplex transport, an SV call acquires the global send gate before awaiting its pacing deadline, so every unrelated frame is blocked for the remaining learned interval, potentially up to 5 ms. The inspected SV Publisher workflow does share this transport with the concurrent lab PTP publisher and peer-delay responder, meaning time-sensitive PTP responses can be delayed even though they are supposed to remain unpaced; pacing state needs separate synchronization from the short device-injection critical section.

AGENTS.md reference: AGENTS.md:L173-L178

Useful? React with 👍 / 👎.

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