Skip to content

Lite's perfmon chart and get_perfmon_trend set aside a one-sample Wait Statistics spike (#4476) - #4492

Merged
erikdarlingdata merged 11 commits into
devfrom
fix/4476-lite-perfmon
Sep 27, 2026
Merged

erikdarlingdata merged 11 commits into
devfrom
fix/4476-lite-perfmon

Conversation

@erikdarlingdata

@erikdarlingdata erikdarlingdata commented Sep 27, 2026 •

Copy link
Copy Markdown
Owner

Refs #4476.

Why

#4476 taught the Darling side's perfmon trend reads (the desktop chart and the get_perfmon_trend MCP tool) to recognize and set aside an isolated single-sample artifact in the SQLServer:Wait Statistics gauge family: SQL Server intermittently hands back a counter's lifetime cumulative count for one sample instead of the level it's supposed to report, and that one row can dwarf every real value around it once several instances are summed into a chart point. Lite has its own perfmon chart and its own get_perfmon_trend tool, reading the same shape of data through DuckDB instead of Postgres — without this change, the same spike distorts Lite's chart and its MCP answer exactly the way it used to distort Darling's.

What changes

  • Lite/Services/LocalDataService.Perfmon.cs, PerfmonTrendsSql (the batched chart read behind GetPerfmonTrendsByCountersAsync): a raw-row layer under the per-collection SUM, carrying lag/lead of cntr_value per instance so WaitStatisticsArtifact.ArtifactPredicateSql can flag the isolated spike before the instances are summed. Every artifact row is excluded from the cntr_value/delta_cntr_value sums via FILTER (WHERE NOT is_artifact); the bucket layer sums the set-aside count into a new trailing artifacts_set_aside column. GetPerfmonTrendsByCountersAsync drops a bucket whose every row was set aside rather than reading it as a fabricated 0, and PerfmonTrendPoint carries the new ArtifactsSetAside count (0 by default).
  • Lite/Services/LocalDataService.TrendBuckets.cs, GetPerfmonBucketsAsync (the get_perfmon_trend MCP tool's read): the same UNION ALL raw layer and FILTERed sums, now returning a PerfmonBucketsResult(Points, ArtifactsSetAside) — the published points (with a fully-set-aside bucket dropped) plus the total set-aside count across the whole window, since a dropped bucket's own count would otherwise be lost.
  • Lite/Mcp/McpPerfmonTools.cs: passes the new total through to TrendPayloads.PerfmonTrend, so get_perfmon_trend's envelope reports a real artifacts_set_aside count and notes line instead of always 0.
  • Lite/Controls/ServerTab.Pickers.cs: the perfmon chart title now shows WaitStatisticsArtifact.ChartCaption(...) when any plotted counter's trend set anything aside, mirroring the Darling viewer's chart chrome.
  • Checked that right(), GREATEST, COALESCE, FILTER, and window lag/lead all exist unchanged in DuckDB (confirmed with the DuckDB CLI), so no dialect parameter was needed on WaitStatisticsArtifact's SQL helpers.

Test plan

  • Local DuckDB check (not a CI pin): planted 4 instances x 5 collections in an in-memory DuckDB table shaped like v_perfmon_stats, one instance spiking 318 -> 214,396,451 -> 1,021 at the second collection. Ran the exclusion SQL directly: the spike collection's SUM comes back 62 (the other three instances' shared value at that timestamp) instead of 214,396,513. See REPORT above.
  • CI pin: Darling.Tests.LitePerfmonWaitStatisticsArtifactSourceTests (2 facts, macOS + Windows CI) scans Lite's two SQL-builder source files for the shared WaitStatisticsArtifact.ArtifactPredicateSql/ObjectNameSuffixMatchSql calls, the lag/lead window, the FILTER (WHERE NOT is_artifact) exclusion and the artifacts_set_aside column — proving the SQL text is wired without needing a live DuckDB in this project.
  • RED: same 2 facts run against dev (which has A Wait Statistics "per second" counter occasionally stores ~98 million as a gauge and flattens the throughput chart #4476's Darling side but not Lite's wiring) — both failed with "Not found: WaitStatisticsArtifact.ArtifactPredicateSql(".
  • Mutation: forced the predicate fragment to the literal false in GetPerfmonBucketsAsync's SQL, reran the local DuckDB check — the spike leaked back through unfiltered (214,396,513). Reverted, rebuilt clean.
  • Builds: Lite/PerformanceMonitorLite.csproj, Lite.Tests/Lite.Tests.csproj, Darling/Darling.Tests/Darling.Tests.csproj, -p:EnableWindowsTargeting=true, all 0 warnings / 0 errors. DocCommentHygieneTests + the new pin: 79/79 passed in-process on macOS.
  • CI pin (Lite.Tests, Windows-only): LitePerfmonWaitStatisticsArtifactLiveTests — GetPerfmonTrendsByCountersAsync_SetsAsideTheIsolatedSpike_AndDropsAnAllArtifactCollection (collection-3 Value == 62, ArtifactsSetAside == 1, an all-artifact collection drops entirely) and GetPerfmonBucketsAsync_KeepsTheSpikeOutOfThePublishedPeak_AndReportsOneArtifact (published peak < 10,000, ArtifactsSetAside == 1). Both run the real Lite reads against an embedded DuckDB seeded with the same field-shaped plant as Darling's live artifact tests. Lite.Tests.dll itself cannot run in-process on macOS (discovery dies on WindowsBase) — built clean here (0 warnings / 0 errors); Windows CI runs them.

CHANGELOG

SECTION: Fixed
ENTRY:

)

PerformanceMonitor.Common.WaitStatisticsArtifact.IsIsolatedSingleSampleArtifact
is the shared test for a Wait Statistics gauge row whose value is a
one-sample cumulative-count artifact: both neighbours present, value
>= 1,000,000, and > 1,000x the larger neighbour, scoped to gauge rows
whose object name ends in ":Wait Statistics". The read-path wiring
(Viewer perfmon chart, MCP get_perfmon_stats) and pins are not yet in
this commit; see the PR body for what remains.
…4476)

Runs the real GetPerfmonTrendsByCountersAsync and GetPerfmonBucketsAsync against an embedded DuckDB plant with the same field-shaped isolated single-sample Wait Statistics spike used by Darling's live artifact tests, proving the chart and MCP reads set the spike aside through the actual product call path instead of only a source-text scan.
# Conflicts:
#	Darling/PerformanceMonitor.Darling.Viewer/ViewerDataService.Perfmon.cs
@erikdarlingdata
erikdarlingdata marked this pull request as ready for review September 27, 2026 19:27
@erikdarlingdata
erikdarlingdata merged commit ae6fb1d into dev Sep 27, 2026
15 of 16 checks passed
@erikdarlingdata
erikdarlingdata deleted the fix/4476-lite-perfmon branch September 27, 2026 19:27
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