Skip to content

PR-D4: pick support for dynamic feature sources#147

Merged
philliphoff merged 3 commits into
mainfrom
philliphoff/pr-d4-dynamic-source-pick
May 31, 2026
Merged

PR-D4: pick support for dynamic feature sources#147
philliphoff merged 3 commits into
mainfrom
philliphoff/pr-d4-dynamic-source-pick

Conversation

@philliphoff
Copy link
Copy Markdown
Owner

Closes the click-to-identify gap for dynamic-source overlays shipped in PR-D3 (#142). The map click handler now hit-tests live IDynamicFeatureSource.CurrentFeatures snapshots in addition to the dataset/portrayal pipeline, and the Pick Report panel renders a sectioned single list — Dynamic sources block above the existing dataset hits — so a single click reveals every target under the crosshair.

What's new

  • DynamicSourceHitTester — pure, 12-device-pixel tolerance, point-only in v1, sources walked in registration order, hits ordered by ascending distance.
  • IDynamicSourcePickService / DynamicSourcePickService — projects raw hits to DynamicPickHit DTOs with localised attribute rows (Position, COG, Heading, SOG, Dimensions, MMSI, Name, Call sign).
  • IDynamicFeatureSourceRegistry.GetVisibleSourceInstances() — exposes the live source list so the pick path can read CurrentFeatures / Metadata without an extra registration round-trip; hidden sources are excluded.
  • PickReportViewModel.DynamicHits + HasDynamicHits / HasDatasetPickPickReportView gates the dataset detail region by HasDatasetPick so dynamic-only picks render cleanly.
  • IPickService.HandlePick(MapInfo?, IReadOnlyList<DynamicPickHit>?) with a default parameter — existing call sites that pass only MapInfo keep compiling.
  • All new UI strings live in Resources/Strings.resx + Strings.cs; tooltip on the dynamic-section header.

Design doc

docs/design/dynamic-source-pick.md answers Q1–Q6 (sibling DTO type, 12px tolerance, separate pick service, sectioned single-list UI, all-resx strings, selection ring deferred). Linked from docs/toc.yml and the viewer README's new Picking dynamic features subsection.

Out of scope (noted in design doc)

  • Selection ring / highlight on map (deferred to a follow-up).
  • Multi-target ARPA-style track viewer.
  • AIS aids-to-navigation, base stations, SAR aircraft.
  • CPA / TCPA.
  • Server-side / MCP exposure of dynamic picks.

Verification

  • dotnet build -c Release clean (0 errors; 2 pre-existing warnings).
  • dotnet test -c Release green across every suite (2,388 passed, 2 skipped).
  • New tests:
    • DynamicSourceHitTesterTests — tolerance hit/miss, ordering by distance, multi-source walk, empty-coordinate skip, invalid-resolution guard.
    • DynamicSourcePickServiceTests — empty registry, full attribute projection (Position / COG / Heading / SOG / MMSI / Name / Call sign), display-label fallback to feature id.
    • PickReportViewModelTests — dynamic-only SetPicks flips HasPick, mixed dataset+dynamic preserves selection, Clear() clears dynamic, both-empty resets state.

philliphoff and others added 3 commits May 30, 2026 11:29
Adds click-to-identify for dynamic-source overlays (own-ship, AIS
targets). The map click handler now also hit-tests live
IDynamicFeatureSource.CurrentFeatures snapshots and merges those
hits into PickReportViewModel, which renders a sectioned 'Dynamic
sources' block alongside the existing dataset hits.

Highlights:
- DynamicSourceHitTester: pure, 12-device-pixel tolerance, point-only
  in v1, sources walked in registration order, hits ordered by
  ascending distance.
- IDynamicSourcePickService / DynamicSourcePickService: projects raw
  hits to DynamicPickHit DTOs with localised attribute rows (Position,
  COG, Heading, SOG, Dimensions, MMSI, Name, Call sign).
- IDynamicFeatureSourceRegistry.GetVisibleSourceInstances(): exposes
  the live source list so the pick path can read CurrentFeatures /
  Metadata without an extra registration round-trip; hidden sources
  are excluded.
- PickReportViewModel: DynamicHits collection plus HasDynamicHits /
  HasDatasetPick flags; PickReportView gates the dataset detail
  region by HasDatasetPick so dynamic-only picks render cleanly.
- IPickService.HandlePick(MapInfo?, IReadOnlyList<DynamicPickHit>?)
  with a default parameter — call sites that only pass MapInfo keep
  compiling.
- All new UI strings via Resources/Strings.resx + Strings.cs.
- Design doc: docs/design/dynamic-source-pick.md (Q1–Q6).
- Viewer README: 'Picking dynamic features' subsection.
- Tests: DynamicSourceHitTesterTests, DynamicSourcePickServiceTests,
  PickReportViewModelTests dynamic-hit coverage (4 new cases).

Out of scope (noted in design doc): selection ring on map, multi-
target ARPA viewer, AIS aids-to-navigation / base stations / SAR,
CPA / TCPA, server-side MCP exposure of dynamic picks.

Build clean (0 errors / 2 pre-existing warnings); dotnet test -c
Release green across all suites (2,388 passed, 2 skipped).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Previously the dynamic-source hit tester used a single 12-device-pixel
tolerance around the antenna position. When the renderer drew a
true-scale hull (zoomed in far enough), most of the visible pictogram
fell outside this tolerance — the user had to click within a few
pixels of the CCRP cross at the antenna, not just anywhere on the
drawn vessel.

The hit tester now does a point-in-polygon test against the same
5-vertex hull polygon the renderer composes from
DynamicVesselGeometry (length / beam / bow + port offsets) and the
feature's heading. The 12-px point tolerance still applies for
features without VesselGeometry and as a fallback for the disc-mode
pictogram so zoomed-out clicks still pick.

Inside-polygon hits report distance 0 so they sort ahead of
edge-tolerance hits, keeping the closest-first ordering intact.

Tests: two new DynamicSourceHitTester cases (inside-hull at tiny
resolution, far miss falls back to point tolerance). Full
EncDotNet.S100.Viewer.Tests suite: 441 passed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

Performance Gate

PASSED — no regressions.

Threshold: 10.0%, MAD multiplier (k): 3.0, retry-zone mult: 2.0×

Scenario summary

Scenario Status Δ median (%) z (Δ/MAD) Base median (ms) Samples (b/c)
exchange-set-open ✅ pass +1.7 +0.20 0.56 20/20
s101-portray-cold ✅ pass -3.1 -0.74 383.53 20/20
s101-portray-warm ✅ pass -0.3 -0.09 265.64 20/20
s101-render-warm ✅ pass +0.4 +0.12 251.73 20/20
s102-coverage ✅ pass -2.8 -0.70 1.21 20/20
s102-coverage-open ✅ pass -3.8 -1.43 3.04 20/20
s102-coverage-render-large ✅ pass -0.5 -0.30 130.66 20/20
s124-vector ✅ pass -0.4 -0.03 0.33 20/20
s201-vector ✅ pass +5.0 +0.66 0.34 20/20

exchange-set-open

Iteration statistics

Stat Baseline Candidate
Samples 20 20
Median (ms) 0.56 0.57
Baseline MAD (ms) 0.05
Δ median +1.7%
z (Δ/MAD) +0.20

Spans (sum of all iterations)

Span Baseline (ms) Candidate (ms) Delta Status
s100.asset.read 11.63 11.59 -0.4% ▫️
s100.exchangeset.parse 41.93 42.75 +2.0% ▫️

Metrics

Metric Baseline Candidate Delta Status
s100.asset.read.duration 19.47 19.30 -0.9% ▫️

s101-portray-cold

Iteration statistics

Stat Baseline Candidate
Samples 20 20
Median (ms) 383.53 371.46
Baseline MAD (ms) 16.37
Δ median -3.1%
z (Δ/MAD) -0.74

Spans (sum of all iterations)

Span Baseline (ms) Candidate (ms) Delta Status
s100.lua.execute 7586.43 7490.87 -1.3% ▫️
s100.lua.rule.invoke 6495.09 6403.68 -1.4% ▫️
s100.pipeline.vector.process 7785.96 7685.69 -1.3% ▫️
s100.pipeline.vector.stage.assemble 0.25 0.27 +5.7%
s100.pipeline.vector.stage.feature_xml 140.91 134.37 -4.6% ▫️
s100.pipeline.vector.stage.lua 7588.77 7493.41 -1.3% ▫️
s100.pipeline.vector.stage.rule_select 6.37 6.68 +4.8% ▫️
s100.pipeline.vector.stage.sort 13.83 14.15 +2.3% ▫️
s100.pipeline.vector.stage.viewing_groups 15.68 16.21 +3.4% ▫️
s100.pipeline.vector.stage.xslt 0.24 0.28 +13.2%
s100.render.frame 1892.32 1921.58 +1.5% ▫️

Metrics

Metric Baseline Candidate Delta Status
s100.catalogue.match.count 7.00 7.00 +0.0% ▫️
s100.featurecatalogue.cache.hit.count 6.00 6.00 +0.0% ▫️
s100.featurecatalogue.cache.miss.count 1.00 1.00 +0.0% ▫️
s100.lua.execute.duration 2524.43 2467.03 -2.3% ▫️
s100.lua.feature.instructions.count 28.00 28.00 +0.0% ▫️
s100.lua.feature.instructions.count 63.00 63.00 +0.0% ▫️
s100.lua.feature.instructions.count 63.00 63.00 +0.0% ▫️
s100.lua.feature.instructions.count 14.00 14.00 +0.0% ▫️
s100.lua.feature.instructions.count 42.00 42.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 217.00 217.00 +0.0% ▫️
s100.lua.feature.instructions.count 840.00 840.00 +0.0% ▫️
s100.lua.feature.instructions.count 49.00 49.00 +0.0% ▫️
s100.lua.feature.instructions.count 14.00 14.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 49.00 49.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 21.00 21.00 +0.0% ▫️
s100.lua.feature.instructions.count 14.00 14.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 49.00 49.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 14.00 14.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 840.00 840.00 +0.0% ▫️
s100.lua.feature.instructions.count 28.00 28.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 28.00 28.00 +0.0% ▫️
s100.lua.feature.instructions.count 14.00 14.00 +0.0% ▫️
s100.lua.features.count 2478.00 2478.00 +0.0% ▫️
s100.lua.instructions.emitted.count 4004.00 4004.00 +0.0% ▫️
s100.lua.rule.invoke.count 7.00 7.00 +0.0% ▫️
s100.lua.rule.invoke.count 77.00 77.00 +0.0% ▫️
s100.lua.rule.invoke.duration 2120.48 2065.73 -2.6% ▫️
s100.lua.rule.invoke.duration 4.66 4.17 -10.6%
s100.lua.source.cache.hit.count 552.00 552.00 +0.0% ▫️
s100.lua.source.cache.miss.count 43.00 43.00 +0.0% ▫️
s100.pattern.cache.hit.count 210.00 210.00 +0.0% ▫️
s100.pattern.cache.miss.count 14.00 14.00 +0.0% ▫️
s100.pipeline.drawinginstructions.out 4004.00 4004.00 +0.0% ▫️
s100.pipeline.duration 2582.12 2526.84 -2.1% ▫️
s100.pipeline.features.in 217.00 217.00 +0.0% ▫️
s100.pipeline.stage.duration 0.27 0.30 +8.2%
s100.pipeline.stage.duration 41.53 43.17 +3.9% ▫️
s100.pipeline.stage.duration 2526.15 2468.82 -2.3% ▫️
s100.pipeline.stage.duration 4.99 4.89 -2.0% ▫️
s100.pipeline.stage.duration 5.11 5.39 +5.5%
s100.pipeline.stage.duration 1.10 1.11 +1.4% ▫️
s100.pipeline.stage.duration 0.86 0.91 +6.3%
s100.pipeline.stage.instructions.count 0.00 0.00 N/A ▫️
s100.pipeline.stage.instructions.count 4004.00 4004.00 +0.0% ▫️
s100.pipeline.stage.instructions.count 4004.00 4004.00 +0.0% ▫️
s100.pipeline.stage.instructions.count 4004.00 4004.00 +0.0% ▫️
s100.portrayal.cache.hit.count 12.00 12.00 +0.0% ▫️
s100.portrayal.cache.hit.count 552.00 552.00 +0.0% ▫️
s100.portrayal.cache.hit.count 7.00 7.00 +0.0% ▫️
s100.portrayal.cache.hit.count 96.00 96.00 +0.0% ▫️
s100.portrayal.cache.miss.count 2.00 2.00 +0.0% ▫️
s100.portrayal.cache.miss.count 43.00 43.00 +0.0% ▫️
s100.portrayal.cache.miss.count 16.00 16.00 +0.0% ▫️
s100.render.frame.duration 740.10 720.72 -2.6% ▫️
s100.render.instructions.processed.count 4004.00 4004.00 +0.0% ▫️
s100.render.styles.applied.count 4256.00 4256.00 +0.0% ▫️
s100.symbol.cache.hit.count 364.00 364.00 +0.0% ▫️
s100.symbol.cache.miss.count 98.00 98.00 +0.0% ▫️
s100.symbol.resolve.duration 0.33 0.31 -6.4% ▫️
s100.symbol.resolve.duration 16.80 15.93 -5.2% ▫️

s101-portray-warm

Iteration statistics

Stat Baseline Candidate
Samples 20 20
Median (ms) 265.64 264.87
Baseline MAD (ms) 8.27
Δ median -0.3%
z (Δ/MAD) -0.09

Spans (sum of all iterations)

Span Baseline (ms) Candidate (ms) Delta Status
s100.lua.execute 6321.14 6312.63 -0.1% ▫️
s100.lua.rule.invoke 5598.78 5605.33 +0.1% ▫️
s100.pipeline.vector.process 6638.56 6628.86 -0.1% ▫️
s100.pipeline.vector.stage.assemble 0.22 0.23 +3.7% ▫️
s100.pipeline.vector.stage.feature_xml 287.92 286.61 -0.5% ▫️
s100.pipeline.vector.stage.lua 6322.45 6313.94 -0.1% ▫️
s100.pipeline.vector.stage.rule_select 4.86 4.74 -2.6% ▫️
s100.pipeline.vector.stage.sort 17.40 17.72 +1.8% ▫️
s100.pipeline.vector.stage.viewing_groups 19.09 19.50 +2.1% ▫️
s100.pipeline.vector.stage.xslt 0.27 0.26 -2.9% ▫️
s100.render.frame 240.69 240.76 +0.0% ▫️

Metrics

Metric Baseline Candidate Delta Status
s100.catalogue.match.count 1.00 1.00 +0.0% ▫️
s100.featurecatalogue.cache.hit.count 7.00 7.00 +0.0% ▫️
s100.lua.execute.duration 1839.53 1763.68 -4.1% ▫️
s100.lua.feature.instructions.count 28.00 28.00 +0.0% ▫️
s100.lua.feature.instructions.count 63.00 63.00 +0.0% ▫️
s100.lua.feature.instructions.count 63.00 63.00 +0.0% ▫️
s100.lua.feature.instructions.count 14.00 14.00 +0.0% ▫️
s100.lua.feature.instructions.count 42.00 42.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 217.00 217.00 +0.0% ▫️
s100.lua.feature.instructions.count 840.00 840.00 +0.0% ▫️
s100.lua.feature.instructions.count 49.00 49.00 +0.0% ▫️
s100.lua.feature.instructions.count 14.00 14.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 49.00 49.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 21.00 21.00 +0.0% ▫️
s100.lua.feature.instructions.count 14.00 14.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 49.00 49.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 14.00 14.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 840.00 840.00 +0.0% ▫️
s100.lua.feature.instructions.count 28.00 28.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 28.00 28.00 +0.0% ▫️
s100.lua.feature.instructions.count 14.00 14.00 +0.0% ▫️
s100.lua.features.count 2478.00 2478.00 +0.0% ▫️
s100.lua.instructions.emitted.count 4004.00 4004.00 +0.0% ▫️
s100.lua.rule.invoke.count 7.00 7.00 +0.0% ▫️
s100.lua.rule.invoke.count 77.00 77.00 +0.0% ▫️
s100.lua.rule.invoke.duration 1606.69 1548.44 -3.6% ▫️
s100.lua.rule.invoke.duration 2.33 2.37 +1.9% ▫️
s100.lua.source.cache.hit.count 595.00 595.00 +0.0% ▫️
s100.pattern.cache.hit.count 222.00 222.00 +0.0% ▫️
s100.pattern.cache.miss.count 2.00 2.00 +0.0% ▫️
s100.pipeline.drawinginstructions.out 4004.00 4004.00 +0.0% ▫️
s100.pipeline.duration 1925.30 1842.71 -4.3% ▫️
s100.pipeline.features.in 217.00 217.00 +0.0% ▫️
s100.pipeline.stage.duration 0.03 0.02 -12.1%
s100.pipeline.stage.duration 76.20 70.09 -8.0% ▫️
s100.pipeline.stage.duration 1839.94 1764.05 -4.1% ▫️
s100.pipeline.stage.duration 1.57 1.43 -9.1% ▫️
s100.pipeline.stage.duration 5.55 5.31 -4.3% ▫️
s100.pipeline.stage.duration 0.30 0.31 +2.7% ▫️
s100.pipeline.stage.duration 0.05 0.05 -9.9% ▫️
s100.pipeline.stage.instructions.count 0.00 0.00 N/A ▫️
s100.pipeline.stage.instructions.count 4004.00 4004.00 +0.0% ▫️
s100.pipeline.stage.instructions.count 4004.00 4004.00 +0.0% ▫️
s100.pipeline.stage.instructions.count 4004.00 4004.00 +0.0% ▫️
s100.portrayal.cache.hit.count 2.00 2.00 +0.0% ▫️
s100.portrayal.cache.hit.count 595.00 595.00 +0.0% ▫️
s100.portrayal.cache.hit.count 7.00 7.00 +0.0% ▫️
s100.portrayal.cache.hit.count 16.00 16.00 +0.0% ▫️
s100.render.frame.duration 130.93 128.18 -2.1% ▫️
s100.render.instructions.processed.count 4004.00 4004.00 +0.0% ▫️
s100.render.styles.applied.count 4256.00 4256.00 +0.0% ▫️
s100.symbol.cache.hit.count 448.00 448.00 +0.0% ▫️
s100.symbol.cache.miss.count 14.00 14.00 +0.0% ▫️
s100.symbol.resolve.duration 0.46 0.40 -14.0%
s100.symbol.resolve.duration 2.13 2.21 +3.7% ▫️

s101-render-warm

Iteration statistics

Stat Baseline Candidate
Samples 20 20
Median (ms) 251.73 252.73
Baseline MAD (ms) 8.37
Δ median +0.4%
z (Δ/MAD) +0.12

Spans (sum of all iterations)

Span Baseline (ms) Candidate (ms) Delta Status
s100.lua.execute 6141.38 6505.80 +5.9%
s100.lua.rule.invoke 5465.79 5808.76 +6.3%
s100.pipeline.vector.process 6286.00 6657.80 +5.9%
s100.pipeline.vector.stage.assemble 0.20 0.18 -12.3%
s100.pipeline.vector.stage.feature_xml 125.80 133.23 +5.9%
s100.pipeline.vector.stage.lua 6142.37 6506.84 +5.9%
s100.pipeline.vector.stage.rule_select 3.32 3.29 -0.9% ▫️
s100.pipeline.vector.stage.sort 10.11 10.11 +0.0% ▫️
s100.pipeline.vector.stage.viewing_groups 11.51 11.53 +0.1% ▫️
s100.pipeline.vector.stage.xslt 0.22 0.20 -6.6% ▫️
s100.render.frame 130.14 151.36 +16.3%

Metrics

Metric Baseline Candidate Delta Status
s100.catalogue.match.count 1.00 1.00 +0.0% ▫️
s100.featurecatalogue.cache.hit.count 7.00 7.00 +0.0% ▫️
s100.lua.execute.duration 1713.81 1678.53 -2.1% ▫️
s100.lua.feature.instructions.count 28.00 28.00 +0.0% ▫️
s100.lua.feature.instructions.count 63.00 63.00 +0.0% ▫️
s100.lua.feature.instructions.count 63.00 63.00 +0.0% ▫️
s100.lua.feature.instructions.count 14.00 14.00 +0.0% ▫️
s100.lua.feature.instructions.count 42.00 42.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 217.00 217.00 +0.0% ▫️
s100.lua.feature.instructions.count 840.00 840.00 +0.0% ▫️
s100.lua.feature.instructions.count 49.00 49.00 +0.0% ▫️
s100.lua.feature.instructions.count 14.00 14.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 49.00 49.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 21.00 21.00 +0.0% ▫️
s100.lua.feature.instructions.count 14.00 14.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 49.00 49.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 14.00 14.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 840.00 840.00 +0.0% ▫️
s100.lua.feature.instructions.count 28.00 28.00 +0.0% ▫️
s100.lua.feature.instructions.count 7.00 7.00 +0.0% ▫️
s100.lua.feature.instructions.count 28.00 28.00 +0.0% ▫️
s100.lua.feature.instructions.count 14.00 14.00 +0.0% ▫️
s100.lua.features.count 2478.00 2478.00 +0.0% ▫️
s100.lua.instructions.emitted.count 4004.00 4004.00 +0.0% ▫️
s100.lua.rule.invoke.count 7.00 7.00 +0.0% ▫️
s100.lua.rule.invoke.count 77.00 77.00 +0.0% ▫️
s100.lua.rule.invoke.duration 1523.87 1488.98 -2.3% ▫️
s100.lua.rule.invoke.duration 2.03 2.13 +5.3%
s100.lua.source.cache.hit.count 595.00 595.00 +0.0% ▫️
s100.pattern.cache.hit.count 222.00 222.00 +0.0% ▫️
s100.pattern.cache.miss.count 2.00 2.00 +0.0% ▫️
s100.pipeline.drawinginstructions.out 4004.00 4004.00 +0.0% ▫️
s100.pipeline.duration 1761.50 1727.37 -1.9% ▫️
s100.pipeline.features.in 217.00 217.00 +0.0% ▫️
s100.pipeline.stage.duration 0.04 0.02 -40.3%
s100.pipeline.stage.duration 41.83 42.77 +2.2% ▫️
s100.pipeline.stage.duration 1714.03 1678.76 -2.1% ▫️
s100.pipeline.stage.duration 1.17 1.12 -4.5% ▫️
s100.pipeline.stage.duration 3.00 3.45 +15.0%
s100.pipeline.stage.duration 0.22 0.22 -0.1% ▫️
s100.pipeline.stage.duration 0.06 0.04 -39.3%
s100.pipeline.stage.instructions.count 0.00 0.00 N/A ▫️
s100.pipeline.stage.instructions.count 4004.00 4004.00 +0.0% ▫️
s100.pipeline.stage.instructions.count 4004.00 4004.00 +0.0% ▫️
s100.pipeline.stage.instructions.count 4004.00 4004.00 +0.0% ▫️
s100.portrayal.cache.hit.count 2.00 2.00 +0.0% ▫️
s100.portrayal.cache.hit.count 595.00 595.00 +0.0% ▫️
s100.portrayal.cache.hit.count 7.00 7.00 +0.0% ▫️
s100.portrayal.cache.hit.count 16.00 16.00 +0.0% ▫️
s100.render.frame.duration 106.51 108.27 +1.7% ▫️
s100.render.instructions.processed.count 4004.00 4004.00 +0.0% ▫️
s100.render.styles.applied.count 4256.00 4256.00 +0.0% ▫️
s100.symbol.cache.hit.count 448.00 448.00 +0.0% ▫️
s100.symbol.cache.miss.count 14.00 14.00 +0.0% ▫️
s100.symbol.resolve.duration 0.27 0.22 -18.4%
s100.symbol.resolve.duration 1.94 2.03 +4.8% ▫️

s102-coverage

Iteration statistics

Stat Baseline Candidate
Samples 20 20
Median (ms) 1.21 1.18
Baseline MAD (ms) 0.05
Δ median -2.8%
z (Δ/MAD) -0.70

Spans (sum of all iterations)

Span Baseline (ms) Candidate (ms) Delta Status
s100.pipeline.coverage.process 48.43 47.88 -1.1% ▫️
s100.pipeline.coverage.stage.read 4.92 4.71 -4.4% ▫️
s100.pipeline.coverage.stage.resolve 40.09 40.12 +0.1% ▫️
s100.render.coverage.build 79.84 79.31 -0.7% ▫️

Metrics

Metric Baseline Candidate Delta Status
s100.catalogue.match.count 1.00 1.00 +0.0% ▫️
s100.coverage.cells 4557.00 4557.00 +0.0% ▫️
s100.hdf5.read.bytes 5208.00 5208.00 +0.0% ▫️
s100.hdf5.read.duration 22.11 22.09 -0.1% ▫️
s100.hdf5.read.duration 30.39 30.24 -0.5% ▫️
s100.hdf5.read.duration 7.46 7.45 -0.1% ▫️
s100.pipeline.duration 9.55 9.58 +0.4% ▫️
s100.pipeline.stage.duration 0.91 0.88 -3.1% ▫️
s100.pipeline.stage.duration 8.14 8.21 +0.8% ▫️
s100.portrayal.cache.hit.count 7.00 7.00 +0.0% ▫️

s102-coverage-open

Iteration statistics

Stat Baseline Candidate
Samples 20 20
Median (ms) 3.04 2.93
Baseline MAD (ms) 0.08
Δ median -3.8%
z (Δ/MAD) -1.43

Spans (sum of all iterations)

Span Baseline (ms) Candidate (ms) Delta Status
s100.dataset.open 85.47 82.06 -4.0% ▫️
s100.hdf5.dataset.read 13.47 12.60 -6.4% ▫️
s100.hdf5.file.open 20.13 20.44 +1.5% ▫️
s100.hdf5.open 21.14 21.09 -0.2% ▫️

Metrics

Metric Baseline Candidate Delta Status
s100.hdf5.read.bytes 36456.00 36456.00 +0.0% ▫️
s100.hdf5.read.duration 6.93 7.03 +1.4% ▫️
s100.hdf5.read.duration 2.55 2.59 +1.6% ▫️
s100.hdf5.read.duration 4.82 4.99 +3.4% ▫️

s102-coverage-render-large

Iteration statistics

Stat Baseline Candidate
Samples 20 20
Median (ms) 130.66 130.04
Baseline MAD (ms) 2.04
Δ median -0.5%
z (Δ/MAD) -0.30

Spans (sum of all iterations)

Span Baseline (ms) Candidate (ms) Delta Status
s100.pipeline.coverage.process 190.79 199.26 +4.4% ▫️
s100.pipeline.coverage.stage.read 137.56 142.72 +3.8% ▫️
s100.pipeline.coverage.stage.resolve 49.80 52.93 +6.3%
s100.render.coverage.build 4637.89 4613.93 -0.5% ▫️

Metrics

Metric Baseline Candidate Delta Status
s100.catalogue.match.count 1.00 1.00 +0.0% ▫️
s100.coverage.cells 7000000.00 7000000.00 +0.0% ▫️
s100.hdf5.read.bytes 8000000.00 8000000.00 +0.0% ▫️
s100.hdf5.read.duration 0.10 0.08 -19.5%
s100.hdf5.read.duration 2.54 2.63 +3.3% ▫️
s100.hdf5.read.duration 1.39 1.39 +0.3% ▫️
s100.pipeline.duration 34.02 39.49 +16.1%
s100.pipeline.stage.duration 24.18 28.12 +16.3%
s100.pipeline.stage.duration 9.09 10.53 +15.9%
s100.portrayal.cache.hit.count 7.00 7.00 +0.0% ▫️

s124-vector

Iteration statistics

Stat Baseline Candidate
Samples 20 20
Median (ms) 0.33 0.33
Baseline MAD (ms) 0.03
Δ median -0.4%
z (Δ/MAD) -0.03

Spans (sum of all iterations)

Span Baseline (ms) Candidate (ms) Delta Status
s100.pipeline.vector.process 7.79 7.26 -6.8% ▫️
s100.pipeline.vector.stage.assemble 0.27 0.25 -8.4% ▫️
s100.pipeline.vector.stage.feature_xml 1.14 1.04 -8.9% ▫️
s100.pipeline.vector.stage.rule_select 0.25 0.26 +4.3% ▫️
s100.pipeline.vector.stage.sort 0.22 0.18 -16.4%
s100.pipeline.vector.stage.viewing_groups 0.53 0.43 -19.5%
s100.pipeline.vector.stage.xslt 3.77 3.61 -4.2% ▫️
s100.render.frame 0.83 0.85 +2.5% ▫️
s100.xslt.transform 1.47 1.37 -6.8% ▫️

Metrics

Metric Baseline Candidate Delta Status
s100.catalogue.match.count 1.00 1.00 +0.0% ▫️
s100.featurecatalogue.cache.miss.count 1.00 1.00 +0.0% ▫️
s100.pipeline.drawinginstructions.out 14.00 14.00 +0.0% ▫️
s100.pipeline.duration 56.84 57.21 +0.6% ▫️
s100.pipeline.features.in 7.00 7.00 +0.0% ▫️
s100.pipeline.stage.duration 1.05 1.13 +7.6%
s100.pipeline.stage.duration 3.15 3.24 +2.8% ▫️
s100.pipeline.stage.duration 1.08 1.23 +13.1%
s100.pipeline.stage.duration 0.06 0.06 +2.0% ▫️
s100.pipeline.stage.duration 0.12 0.10 -17.8%
s100.pipeline.stage.duration 50.90 50.92 +0.0% ▫️
s100.pipeline.stage.instructions.count 14.00 14.00 +0.0% ▫️
s100.pipeline.stage.instructions.count 14.00 14.00 +0.0% ▫️
s100.pipeline.stage.instructions.count 14.00 14.00 +0.0% ▫️
s100.portrayal.cache.hit.count 13.00 13.00 +0.0% ▫️
s100.portrayal.cache.hit.count 7.00 7.00 +0.0% ▫️
s100.portrayal.cache.hit.count 6.00 6.00 +0.0% ▫️
s100.portrayal.cache.miss.count 1.00 1.00 +0.0% ▫️
s100.portrayal.cache.miss.count 1.00 1.00 +0.0% ▫️
s100.render.frame.duration 2.41 2.33 -3.6% ▫️
s100.render.instructions.processed.count 14.00 14.00 +0.0% ▫️
s100.render.styles.applied.count 14.00 14.00 +0.0% ▫️
s100.xslt.transform.duration 10.81 10.87 +0.5% ▫️

s201-vector

Iteration statistics

Stat Baseline Candidate
Samples 20 20
Median (ms) 0.34 0.36
Baseline MAD (ms) 0.03
Δ median +5.0%
z (Δ/MAD) +0.66

Spans (sum of all iterations)

Span Baseline (ms) Candidate (ms) Delta Status
s100.pipeline.vector.process 7.90 8.17 +3.5% ▫️
s100.pipeline.vector.stage.assemble 0.18 0.19 +7.0%
s100.pipeline.vector.stage.feature_xml 0.97 0.97 -0.2% ▫️
s100.pipeline.vector.stage.rule_select 0.29 0.26 -9.7% ▫️
s100.pipeline.vector.stage.sort 0.10 0.10 -3.1% ▫️
s100.pipeline.vector.stage.viewing_groups 0.40 0.40 -1.0% ▫️
s100.pipeline.vector.stage.xslt 3.25 3.47 +6.9%
s100.render.frame 0.68 0.72 +6.5%
s100.xslt.transform 2.19 2.34 +6.6%

Metrics

Metric Baseline Candidate Delta Status
s100.catalogue.match.count 1.00 1.00 +0.0% ▫️
s100.featurecatalogue.cache.miss.count 1.00 1.00 +0.0% ▫️
s100.pipeline.drawinginstructions.out 7.00 7.00 +0.0% ▫️
s100.pipeline.duration 174.43 168.57 -3.4% ▫️
s100.pipeline.features.in 21.00 21.00 +0.0% ▫️
s100.pipeline.stage.duration 0.60 0.62 +2.1% ▫️
s100.pipeline.stage.duration 7.06 6.62 -6.2% ▫️
s100.pipeline.stage.duration 0.16 0.15 -6.2% ▫️
s100.pipeline.stage.duration 0.02 0.02 -2.3% ▫️
s100.pipeline.stage.duration 0.06 0.06 +3.6% ▫️
s100.pipeline.stage.duration 166.06 160.58 -3.3% ▫️
s100.pipeline.stage.instructions.count 7.00 7.00 +0.0% ▫️
s100.pipeline.stage.instructions.count 7.00 7.00 +0.0% ▫️
s100.pipeline.stage.instructions.count 7.00 7.00 +0.0% ▫️
s100.portrayal.cache.hit.count 7.00 7.00 +0.0% ▫️
s100.portrayal.cache.hit.count 6.00 6.00 +0.0% ▫️
s100.portrayal.cache.miss.count 1.00 1.00 +0.0% ▫️
s100.portrayal.cache.miss.count 1.00 1.00 +0.0% ▫️
s100.render.frame.duration 1.15 1.10 -3.7% ▫️
s100.render.instructions.processed.count 7.00 7.00 +0.0% ▫️
s100.render.styles.applied.count 14.00 14.00 +0.0% ▫️
s100.symbol.cache.hit.count 6.00 6.00 +0.0% ▫️
s100.symbol.cache.miss.count 1.00 1.00 +0.0% ▫️
s100.symbol.resolve.duration 0.01 0.01 +70.4%
s100.symbol.resolve.duration 0.86 0.80 -7.2% ▫️
s100.xslt.transform.duration 29.66 29.62 -0.1% ▫️

Generated by EncDotNet.S100.PerfReport gate command

@philliphoff philliphoff merged commit b739511 into main May 31, 2026
10 checks 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