Repository navigation
Fix Lite Overview ghost-line comparison offset under a preset range (#4296) - #4309
Merged
Merged
Conversation
RefreshOverviewAsync built the correlated-lanes comparison window from DateTime.UtcNow under a preset range, but the lanes' own reads (GetCpuUtilizationAsync, GetTotalWaitTrendAsync, etc.) treat a supplied fromDate/toDate as server-local. On a server not on UTC that shifted the ghost-line reference window, and CorrelatedTimelineLanesControl.RefreshAsync's timeShift/ComparisonLabel had the same fallback. GetOverviewComparisonRange and GetCurrentWindowServerLocal build the current window from the server's own local now instead, and thread CurrentFrom through so the shift is exact arithmetic rather than a second DateTime.UtcNow sample. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3
…4296) Covers GetCurrentWindowServerLocal/GetOverviewComparisonRange under a preset and a custom range, for a server east (UTC+5) and west (UTC-7) of UTC, plus a source-scan pin for the RefreshOverviewAsync/RefreshAsync/ComparisonLabel call sites. Verified against this branch's parent commit (git show HEAD~1) that every assertion in the source-scan test fails on the pre-fix source. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3
…ne-offset # Conflicts: # Lite/Controls/ServerTab.Refresh.cs
Merged
6 tasks done
erikdarlingdata
marked this pull request as ready for review
September 25, 2026 16:22
erikdarlingdata
added a commit
that referenced
this pull request
Sep 25, 2026
…eset range (#4305) (#4317) CorrelatedTimelineLanesControl.xaml.cs is a copy of Lite's control (SYNC WARNING), which had the identical bug PR #4309 (#4296) fixed: under a preset range, the comparison ghost line built its reference window from DateTime.UtcNow while the correlated lanes' own reads treat a supplied fromDate/toDate as server-local (collection_time defaults to SYSDATETIME() throughout install/*.sql). Mirrors that fix here: GetCurrentWindowServerLocal/GetOverviewComparisonRange, CurrentFrom threaded through RefreshAsync's timeShift and ComparisonLabel, and the caller (ResourceMetricsContent/ServerTab) switched to deriving the range fresh, per refresh, from the Compare dropdown's index rather than a value resolved once and reused across later auto-refreshes. Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3 Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
erikdarlingdata
added a commit
that referenced
this pull request
Sep 25, 2026
…4321) * Dashboard Overview ghost line uses the server's local time under a preset range (#4305) CorrelatedTimelineLanesControl.xaml.cs is a copy of Lite's control (SYNC WARNING), which had the identical bug PR #4309 (#4296) fixed: under a preset range, the comparison ghost line built its reference window from DateTime.UtcNow while the correlated lanes' own reads treat a supplied fromDate/toDate as server-local (collection_time defaults to SYSDATETIME() throughout install/*.sql). Mirrors that fix here: GetCurrentWindowServerLocal/GetOverviewComparisonRange, CurrentFrom threaded through RefreshAsync's timeShift and ComparisonLabel, and the caller (ResourceMetricsContent/ServerTab) switched to deriving the range fresh, per refresh, from the Compare dropdown's index rather than a value resolved once and reused across later auto-refreshes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3 * Dashboard query comparison grids use the server's local time (#4313) Query Stats / Proc Stats / Query Store comparison grids built their preset-range current window from DateTime.UtcNow (ServerTab.xaml.cs's GetComparisonRange, QueryPerformanceContent.Comparison.cs's RefreshComparisonAsync) while the reads they feed (GetQueryStatsComparisonAsync, GetProcedureStatsComparisonAsync, GetQueryStoreComparisonAsync) filter collection_time, which is server-local (collect.query_stats/proc_stats/query_store_stats default it to SYSDATETIME()). Same bug family as #4305/#4317's Overview ghost line, on the two spots #4305 explicitly left for this issue. Also fixes a third spot #4305 didn't touch: CorrelatedTimelineLanesControl.xaml.cs's RefreshAsync baseline referenceTime fed SqlServerBaselineProvider.GetBaselineAsync's hour-of-day/day-of-week bucket match, also against collection_time, from the same raw-UTC fallback. All three now reuse #4305's tested GetCurrentWindowServerLocal/ GetOverviewComparisonRange statics instead of independently resampling UTC now. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3 --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #4296.
Why
Lite's Overview tab has a "Compare to" ghost-line overlay on the correlated timeline lanes (CPU, waits,
blocking, memory, file I/O).
ServerTab.RefreshOverviewAsyncbuilds the reference (ghost-line) timewindow and hands it to
CorrelatedTimelineLanesControl.RefreshAsync, which reads it straight intoLocalDataService.GetCpuUtilizationAsync,GetTotalWaitTrendAsync, and friends. Those reads treat asupplied
fromDate/toDateas the monitored server's own local time, not UTC.Under a PRESET range (no custom dates picked), the window was built from
DateTime.UtcNowinstead of theserver's local now. On a server not on UTC, the reads got a window shifted by the server's offset. The
ghost line came from the wrong hours entirely, not just a display skew. The same raw
DateTime.UtcNowfallback was duplicated in two more places:
RefreshAsync'stimeShift(the ghost line's X-axisalignment) and
ComparisonLabel(the "yesterday" / "last week" text). So even after fixing the referencewindow alone, the overlay stayed misplaced on the chart and mislabeled. A CUSTOM range was already correct:
the date pickers convert to server time before
RefreshOverviewAsyncever seesfromDate/toDate.The three call sites are
RefreshOverviewAsync,RefreshAsync'stimeShiftandComparisonLabel. With thetwo changed files reverted to this branch's parent commit, the new source pin test failed.
The Darling viewer has no ghost-line overlay to fix in parallel. Its
CorrelatedTimelineLanesControl.xaml.csheader says so directly: "Deliberately dropped for v1 (noted inthe PR): Lite's comparison-range ghost-line overlay (the whole comparisonRange block, AddGhostLine,
ComparisonLabel)."
What changes
Lite/Controls/CorrelatedTimelineLanesControl.xaml.cs: two newinternal statichelpers,GetCurrentWindowServerLocalandGetOverviewComparisonRange. Under a preset range, they build thecurrent window from the server's own local now:
utcNow.AddMinutes(utcOffsetMinutes). That is the resultServerTimeHelper.ToServerTimegives, without its static state. Under a customrange they pass the already-server-local
fromDate/toDatethrough unchanged.GetOverviewComparisonRangereturns
CurrentFromwithFromandTo. SoRefreshAsync'stimeShiftandComparisonLabeluse thesame current-window start that the reference range came from. Before, each one read
DateTime.UtcNowagain. That makes the shift exact arithmetic(
currentStart - (currentStart - N days) = N days) instead of two independent clock reads a networkround-trip apart.
Lite/Controls/ServerTab.Refresh.cs:RefreshOverviewAsyncnow callsCorrelatedTimelineLanesControl.GetOverviewComparisonRangeinstead of the sharedServerTab.Comparison.csGetComparisonRange(). Under a preset range, that shared helper fallsback to UTC. That is right for the Queries-tab comparisons it also serves, because they read the UTC
collection_timedirectly. It is wrong for the correlated lanes. So the Overview tab gets its ownderivation, and the Queries tab keeps the shared one.
Lite.Tests/OverviewComparisonWindowOffsetTests.cs(new) pins both helpers for a server at UTC+5 and oneat UTC-7, under a preset and a custom range. A source pin also checks the three call sites.
copy of this control (
deprecated/Dashboard/Controls/CorrelatedTimelineLanesControl.xaml.cs, flagged byits own "SYNC WARNING" header) has the same bug. Not fixed here: Dashboard is a separate, SQL-Server-only
product with its own data service. Confirming the same UTC-vs-server-local read semantics apply there
needs its own look, not a copy-paste of this fix.
This branch also merges in #4302 (#4284's Queries-tab fix), which landed on
devwhile this PR was inprogress and touched the same
RefreshOverviewAsyncmethod. Its own comment there named #4296 as themismatch it did not fix. The merge conflict was resolved by keeping this PR's derivation, which supersedes
that comment.
Test plan
dotnet build Lite.Tests/Lite.Tests.csproj -c Debug: 0 Warning(s), 0 Error(s), both before andafter merging
origin/dev.Lite.Tests.exe -class "PerformanceMonitorLite.Tests.OverviewComparisonWindowOffsetTests": 9/9passed.
DateTime.UtcNowlines and lack the new ones.origin/dev,Lite.Tests.exewith no filter: Total 5398, Errors 0,Failed 0, Skipped 0, Not Run 0.
66b3a337: build, Darling PostgreSQL tests and Lite tests all pass.CHANGELOG entry
SECTION: Fixed
ENTRY:
the "Compare to" ghost line read a window off by the server's UTC offset. So on a server not set to UTC,
it covered the wrong hours of the day it compared against. The window, the line's position
and its label now all come from the server's local time.
REF:
[Fix Lite Overview ghost-line comparison offset under a preset range (#4296) #4309]: Fix Lite Overview ghost-line comparison offset under a preset range (#4296) #4309
🤖 Generated with Claude Code
https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ