Skip to content

Lite: Blocking Stats severity sub-tab (Tier-1 parity)#1514

Merged
erikdarlingdata merged 1 commit into
devfrom
feature/lite-blocking-stats-tab
Jul 13, 2026
Merged

Lite: Blocking Stats severity sub-tab (Tier-1 parity)#1514
erikdarlingdata merged 1 commit into
devfrom
feature/lite-blocking-stats-tab

Conversation

@erikdarlingdata

Copy link
Copy Markdown
Owner

What

Ports Darling's Blocking Stats sub-tab to Lite: a 2×2 chart grid + a window summary strip showing blocking and deadlock SEVERITY over the window — the "are blocks/deadlocks getting worse, not just more frequent" signal. It is the severity companion to Lite's existing Blocking Trends sub-tab (which plots COUNTS).

Everything is computed on-the-fly from rows the store already keeps — no collector, no migration — the Lite equivalent of the Dashboard's pre-aggregated collect.blocking_deadlock_stats.

Sub-tab wiring (append-at-end, zero reindex)

  • New <TabItem Header="Blocking Stats"> appended as the LAST Blocking sub-tab → sub-index 4 (after 0 Trends, 1 Current Waits, 2 Blocked Process Reports, 3 Deadlocks). Current Waits / BPR / Deadlocks are untouched; the DrillDown/DailySummary navigations that target sub-indexes 2 and 3 are unaffected.
  • RefreshBlockingAsync gains case 4 in the subTabOnly switch (loads on sub-tab switch + timer tick when visible) and the two reads in the full-refresh path (first-load / manual refresh), matching how Trends/Current Waits are in both.
  • Top-level Blocking stays index 8RefreshVisibleTabAsync untouched.
  • Chart init/dispose wired in ServerTab.xaml.cs alongside the other chart-tab partials.

Note: Darling places Blocking Stats at sub-index 1; Lite already orders its Blocking sub-tabs differently, so append-at-end is the tab-alignment-safe choice. The parent may reorder later.

Collapse check — NOT twinned (viewer-only aggregate; parse already shared)

Darling's deadlock-severity computation is not a viewer↔service twin:

  • Service/MCP side (DarlingBlockingTrendReader / DarlingMcpBlockingTools) hosts only the count trends and explicitly documents that get_blocking_deadlock_stats / the victim-wait severity is not hosted (no raw source).
  • The Darling viewer aggregate (AggregateDeadlockSeverity) is viewer-only and already parses via the shared PerformanceMonitor.Common.DeadlockGraphParser.

So there is no twin to collapse. Per the brief's not-twinned branch, Lite reuses its own existing DeadlockProcessDetail.ParseFromRows (the same parse the Deadlocks grid uses, keeping Lite's severity internally consistent with its grid) rather than introducing a third copy of the parse. Nothing on the Darling side was touched.

Reads (Lite/Services/LocalDataService.BlockingStats.cs)

  • GetBlockingDurationStatsAsync — per-minute COUNT(*) + SUM/MAX/AVG(wait_time_ms) over the same XE-preferred (v_blocked_process_reports) + DMV-fallback (v_dmv_blocking_snapshots, WHERE NOT EXISTS) union the blocking-incident count trend uses, so the severity chart and count chart never disagree on which rows exist. Honors the [FEATURE] Add filter for databases(s) #1319 database filter on both arms.
  • GetDeadlockSeverityStatsAsync — reads raw deadlock_graph_xml over the same v_deadlocks / collection_time window as the deadlock count (uncapped, so it can't drop rows the count keeps), parses each graph off the UI thread with ParseFromRows, and buckets the per-process victim/wait rows by minute (victim_count = SUM of victims; total/max/avg over every process's wait).

Charts + summary (Lite/Controls/ServerTab.BlockingStats.cs)

Four charts (block Max/Avg + block Total; deadlock Max/Avg + deadlock Total — Total split onto its own axis per pair so the aggregate magnitude doesn't swamp the per-incident one) + a summary strip (events / total / max / avg block duration, deadlock count, deadlock victims, deadlock wait). Mirrors Darling's rendering with Lite's chart idioms: ChartStyle/ChartHoverHelper, SeriesColors/ChartPalette identities, UtcOffsetMinutes display conversion, Y-floor-at-0, window-pinned SetLimitsX, connected-scatter padded to the window ends.

Tests

Lite.Tests/BlockingStatsReaderTests.cs — real-DuckDB round-trips that plant blocked_process_reports / dmv_blocking_snapshots / deadlocks rows and assert:

  • the per-minute duration aggregate (count + total/max/avg),
  • the XE→DMV fallback union (DMV contributes only when no XE in window; BPR wins otherwise),
  • the [FEATURE] Add filter for databases(s) #1319 database filter,
  • window bounding (event_time for blocking, collection_time for deadlocks),
  • the deadlock-severity aggregate (victim_count + total/max/avg wait) reconciling with GetDeadlockTrendAsync over the same window.

Validation

  • dotnet build Lite/PerformanceMonitorLite.csproj -c Debugclean (0 errors).
  • Full Lite.Tests1238 passed, 0 failed (includes the new 7 + the collector-coverage pin, which is unchanged: no new collector table).
  • No collapse → Darling untouched, Darling.Tests not required.
  • Installer.Tests / SQL-Server integration tests not run.

🤖 Generated with Claude Code

Port Darling's Blocking Stats sub-tab to Lite: a 2x2 chart grid + summary
strip showing blocking AND deadlock SEVERITY over the window (the "getting
WORSE, not just more frequent" signal), the severity companion to Lite's
existing count-only Blocking Trends sub-tab. Appended as the LAST Blocking
sub-tab (sub-index 4, after Deadlocks) so nothing reindexes; RefreshBlocking
Async's subTabOnly switch gains case 4 and the full-refresh path renders it.
Blocking stays top-level index 8.

Reader (LocalDataService.BlockingStats.cs) adapts Darling's aggregates to
DuckDB: block-duration SUM/MAX/AVG(wait_time_ms) per minute over the same
XE-preferred + DMV-fallback (WHERE NOT EXISTS) union the count trend uses
(honoring the #1319 DB filter on both arms), and a deadlock-severity aggregate
over deadlock_graph_xml on the same v_deadlocks/collection_time window as the
count (uncapped), parsed off-thread with Lite's own DeadlockProcessDetail
.ParseFromRows and bucketed by minute (victim_count + total/max/avg wait).

Collapse check: Darling's deadlock-severity computation is NOT a viewer<->
service twin -- the service/MCP side hosts only count trends and deliberately
omits a blocking_deadlock_stats aggregate, and the Darling viewer already
parses via shared Common.DeadlockGraphParser -- so per the brief Lite reuses
its own existing ParseFromRows (internally consistent with its Deadlocks grid)
rather than adding a third copy. Nothing on the Darling side touched.

Four charts (ServerTab.BlockingStats.cs) mirror Darling with Lite's chart
idioms (ChartStyle/ChartHoverHelper, SeriesColors/ChartPalette, UtcOffset
Minutes axis, Y-floor-at-0, window-padded scatter), wired into the Blocking
TabControl + ServerTab.xaml.cs init/dispose. Real-DuckDB round-trip tests
(BlockingStatsReaderTests) assert the duration aggregate, the XE->DMV fallback,
the #1319 filter, window bounding, and the deadlock-severity aggregate
reconciling with the deadlock count.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@erikdarlingdata erikdarlingdata merged commit 01bbb8e into dev Jul 13, 2026
2 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