Repository navigation
Deprecated Dashboard analysis perfmon reads divide by the measured interval (#3561) - #3569
Conversation
Mirror of #3560 (Lite/Darling) into the deprecated Dashboard's frozen analysis twins: cntr_value_delta spans one collection interval, not one second, so the raw reads overstated by the cadence (60x at 60s, 300x at 5min) against thresholds defined in requests/sec. All three reads move together, or the z-score compares across units: - SqlServerFactCollector PERFMON_*_SEC facts divide the delta by the row's measured sample_interval_seconds; interval <= 0 rows (unknowable delta) are filtered so rn = 1 lands on the newest usable row - a counter with only interval-0 rows emits no fact, never 0. The raw delta and the divisor ride the metadata. - SqlServerAnomalyDetector's batch-request window AVG/MAX divide by NULLIF(sample_interval_seconds, 0) with interval <= 0 rows filtered, keeping the window statistic in the same requests/sec unit as the BatchRequestFloor/Fallback bars. - SqlServerBaselineProvider's batch_requests arm computes the baseline population as the per-second rate; the restart signature stays on the RAW delta (its > 1000 bar predates the division). The window and perfmon SQL move to public consts (the Darling twin's tested shape) and GetBaselineQuery goes internal so Dashboard.Tests can pin the text - the Dashboard has no test database. Semantics verified live against SQL Server via a temp-table clone of collect.perfmon_stats. Fixes #3561 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QMYFB4qv5tqGwMmdPsa4Zx
PR #3569 landed after the splice opened; its entry joins the same PR to keep the one-splice-per-wave discipline (18 entries now). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QMYFB4qv5tqGwMmdPsa4Zx
* CHANGELOG: the brains-review wave, one splice (17 entries) Wave-1 of the 2026-09 brains-review campaign landed sixteen PRs on dev with a buffered changelog protocol - agents reported their entries to the coordinator instead of touching this file, so sixteen PRs merged without a single CHANGELOG conflict. This is the one post-wave splice: seventeen Fixed entries covering #3523-#3537, #3547, #3548, #3551, #3556, plus their reference links. #3549 was documentation-only and carries no entry. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QMYFB4qv5tqGwMmdPsa4Zx * CHANGELOG: fold the #3561 Dashboard divisor entry into the wave splice PR #3569 landed after the splice opened; its entry joins the same PR to keep the one-splice-per-wave discipline (18 entries now). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QMYFB4qv5tqGwMmdPsa4Zx * CHANGELOG: fold the #3563 viewer-pass entry into the wave splice (19 entries) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QMYFB4qv5tqGwMmdPsa4Zx --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
| // sample_interval_seconds; interval <= 0 marks an unknowable delta (first sighting, counter | ||
| // reset, gap), so those rows are filtered rather than emitted as 0 — rn = 1 lands on the | ||
| // newest row a rate can honestly be derived from. | ||
| public const string PerfmonSql = @" |
There was a problem hiding this comment.
Non-blocking observation, out of scope for this PR: collect.perfmon_stats.cntr_value_per_second (the computed column defined in install/02_create_tables.sql, cntr_value_delta / NULLIF(sample_interval_seconds, 0)) does integer division — both operands are integral types, so it truncates fractional per-second rates (e.g. 150/60 → 2, not 2.5). This PR correctly avoids it by using * 1.0 / for float division in all three reads it touches, but DatabaseService.ResourceMetrics.Perfmon.cs (lines 48 and 126) still selects that computed column directly for the perfmon chart UI, so that read path still carries a truncated-rate defect distinct from the #3527/#3561 cadence bug this PR fixes. Worth a follow-up issue if not already tracked — not asking for it here since it's an unrelated file/read path.
|
Reviewed against Correctness — verified line-by-line against
Parity — this is the deprecated Full Dashboard, not Lite or Darling, so the strict Lite/Darling parity requirement doesn't directly apply. That said, the PR explicitly positions itself as a mirror of #3560, and I confirmed the SQL and C# shapes do faithfully mirror the Darling implementation (down to the Style — new comments explain why at length per convention, block-comment style is followed. Tests — Left one non-blocking inline comment about an unrelated, pre-existing integer-division truncation bug in the |
There was a problem hiding this comment.
LGTM — verified the three reads' SQL and C# division/interval-filtering logic against the Lite/Darling (#3560) twins line-by-line, confirmed the new SQL-text pin tests are correct, and checked for parity/style issues. No substantive findings; left one non-blocking inline note about a pre-existing, unrelated truncation bug in a different read path.
Fixes #3561
Mirror of #3560 (Lite + Darling) into the deprecated Dashboard's frozen analysis twins.
cntr_value_deltaspans one collection interval, not one second, so the raw reads overstated by the cadence (60x at 60s, 300x at 5min) against thresholds defined in requests/sec. All three reads move together — the consistency constraint is the whole fix:PERFMON_*_SECfacts divide the delta by the row's measuredsample_interval_seconds; interval <= 0 rows (unknowable delta: first sighting, reset, gap) are filtered inside the CTE sorn = 1lands on the newest usable row. A counter with only interval-0 rows emits no fact, never 0. The raw delta and the divisor ride the metadata, and a C# guard keeps a raw or zero value from escaping if the SQL filter ever regresses.AVG/MAXdivide byNULLIF(sample_interval_seconds, 0)withsample_interval_seconds > 0filtered, keeping the window statistic in the same requests/sec unit as theBatchRequestFloor/BatchRequestFallbackbars (both defined in requests/sec).batch_requestsbaseline arm computes its population as the per-second rate (AVG(v)/STDEV(v)); the restart signature stays on the raw delta (its > 1000 bar predates the division and marks a reset regardless of cadence), exactly as in Lite's Perfmon analysis reads divide the per-interval delta by its measured interval #3560 treatment.Test seam: the window and perfmon SQL move to
public constfields (the Darling twin's #3560-tested shape, and Dashboard.Tests' existingFailedJobsQuery.Sqlpin idiom) andGetBaselineQuerygoesinternal(InternalsVisibleTo) — the Dashboard has no test database, so the newPerfmonPerSecondSqlTestspins the SQL text of all three reads, including the absence of the rawAVG(cntr_value_delta)/MAX(cntr_value_delta)/STDEV(cntr_value_delta)defect shapes.Testing
dotnet build deprecated/Dashboard/Dashboard.csproj— Build succeeded, 0 Warning(s)dotnet build deprecated/Dashboard.Tests/Dashboard.Tests.csproj— Build succeeded, 0 Warning(s)collect.perfmon_statsseeded with the Perfmon analysis reads divide the per-interval delta by its measured interval #3560 fixture: fact read returns the newest usable row (interval-0 skipped, only-interval-0 counter absent), window read yields per-second avg/peak (100.00 from delta 6000 over 60s), baseline arm yields mean 100.00 with the restart zero excluded and interval-0 rows skipped.🤖 Generated with Claude Code
https://claude.ai/code/session_01QMYFB4qv5tqGwMmdPsa4Zx