Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion Dashboard/Controls/MemoryContent.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,26 @@ public partial class MemoryContent : UserControl
// Legend panel references for edge-based legends (ScottPlot issue #4717 workaround)
private Dictionary<ScottPlot.WPF.WpfPlot, ScottPlot.IPanel?> _legendPanels = new();

// Chart hover tooltips
private Helpers.ChartHoverHelper? _memoryStatsOverviewHover;
private Helpers.ChartHoverHelper? _memoryGrantsHover;
private Helpers.ChartHoverHelper? _memoryClerksHover;
private Helpers.ChartHoverHelper? _planCacheHover;
private Helpers.ChartHoverHelper? _memoryPressureEventsHover;

// No DataGrids with filters - all tabs are chart-only

public MemoryContent()
{
InitializeComponent();
SetupChartContextMenus();
Loaded += OnLoaded;

_memoryStatsOverviewHover = new Helpers.ChartHoverHelper(MemoryStatsOverviewChart, "MB");
_memoryGrantsHover = new Helpers.ChartHoverHelper(MemoryGrantsChart, "MB");
_memoryClerksHover = new Helpers.ChartHoverHelper(MemoryClerksChart, "MB");
_planCacheHover = new Helpers.ChartHoverHelper(PlanCacheChart, "MB");
_memoryPressureEventsHover = new Helpers.ChartHoverHelper(MemoryPressureEventsChart, "events");
}

private void OnLoaded(object sender, RoutedEventArgs e)
Expand Down Expand Up @@ -183,6 +196,7 @@ private void LoadMemoryStatsOverviewChart(List<MemoryStatsItem> memoryData, int
_legendPanels[MemoryStatsOverviewChart] = null;
}
MemoryStatsOverviewChart.Plot.Clear();
_memoryStatsOverviewHover?.Clear();
TabHelpers.ApplyDarkModeToChart(MemoryStatsOverviewChart);

var dataList = memoryData?.OrderBy(d => d.CollectionTime).ToList() ?? new List<MemoryStatsItem>();
Expand Down Expand Up @@ -216,24 +230,28 @@ private void LoadMemoryStatsOverviewChart(List<MemoryStatsItem> memoryData, int
totalScatter.MarkerSize = 5;
totalScatter.Color = TabHelpers.ChartColors[9];
totalScatter.LegendText = "Total Memory";
_memoryStatsOverviewHover?.Add(totalScatter, "Total Memory");

var bufferScatter = MemoryStatsOverviewChart.Plot.Add.Scatter(bufferXs, bufferYs);
bufferScatter.LineWidth = 2;
bufferScatter.MarkerSize = 5;
bufferScatter.Color = TabHelpers.ChartColors[0];
bufferScatter.LegendText = "Buffer Pool";
_memoryStatsOverviewHover?.Add(bufferScatter, "Buffer Pool");

var cacheScatter = MemoryStatsOverviewChart.Plot.Add.Scatter(cacheXs, cacheYs);
cacheScatter.LineWidth = 2;
cacheScatter.MarkerSize = 5;
cacheScatter.Color = TabHelpers.ChartColors[1];
cacheScatter.LegendText = "Plan Cache";
_memoryStatsOverviewHover?.Add(cacheScatter, "Plan Cache");

var availScatter = MemoryStatsOverviewChart.Plot.Add.Scatter(availXs, availYs);
availScatter.LineWidth = 2;
availScatter.MarkerSize = 5;
availScatter.Color = TabHelpers.ChartColors[2];
availScatter.LegendText = "Available Physical";
_memoryStatsOverviewHover?.Add(availScatter, "Available Physical");

_legendPanels[MemoryStatsOverviewChart] = MemoryStatsOverviewChart.Plot.ShowLegend(ScottPlot.Edge.Bottom);
MemoryStatsOverviewChart.Plot.Legend.FontSize = 12;
Expand Down Expand Up @@ -389,6 +407,7 @@ private void LoadMemoryGrantsChart(IEnumerable<MemoryGrantStatsItem> data, int h
_legendPanels[MemoryGrantsChart] = null;
}
MemoryGrantsChart.Plot.Clear();
_memoryGrantsHover?.Clear();
TabHelpers.ApplyDarkModeToChart(MemoryGrantsChart);

var dataList = data?.OrderBy(d => d.CollectionTime).ToList() ?? new List<MemoryGrantStatsItem>();
Expand Down Expand Up @@ -422,12 +441,14 @@ private void LoadMemoryGrantsChart(IEnumerable<MemoryGrantStatsItem> data, int h
grantedScatter.MarkerSize = 5;
grantedScatter.Color = TabHelpers.ChartColors[0];
grantedScatter.LegendText = "Granted MB";
_memoryGrantsHover?.Add(grantedScatter, "Granted MB");

var targetScatter = MemoryGrantsChart.Plot.Add.Scatter(targetXs, targetYs);
targetScatter.LineWidth = 2;
targetScatter.MarkerSize = 5;
targetScatter.Color = TabHelpers.ChartColors[2];
targetScatter.LegendText = "Target MB";
_memoryGrantsHover?.Add(targetScatter, "Target MB");

_legendPanels[MemoryGrantsChart] = MemoryGrantsChart.Plot.ShowLegend(ScottPlot.Edge.Bottom);
MemoryGrantsChart.Plot.Legend.FontSize = 12;
Expand Down Expand Up @@ -488,6 +509,7 @@ private void LoadMemoryClerksChart(List<MemoryClerksItem> data, int hoursBack, D
_legendPanels[MemoryClerksChart] = null;
}
MemoryClerksChart.Plot.Clear();
_memoryClerksHover?.Clear();
TabHelpers.ApplyDarkModeToChart(MemoryClerksChart);

var dataList = data ?? new List<MemoryClerksItem>();
Expand Down Expand Up @@ -521,7 +543,9 @@ private void LoadMemoryClerksChart(List<MemoryClerksItem> data, int hoursBack, D
scatter.LineWidth = 2;
scatter.MarkerSize = 5;
scatter.Color = colors[colorIndex % colors.Length];
scatter.LegendText = clerkType.Length > 20 ? clerkType.Substring(0, 20) + "..." : clerkType;
var label = clerkType.Length > 20 ? clerkType.Substring(0, 20) + "..." : clerkType;
scatter.LegendText = label;
_memoryClerksHover?.Add(scatter, label);
colorIndex++;
}
}
Expand Down Expand Up @@ -623,6 +647,7 @@ private void LoadPlanCacheChart(IEnumerable<PlanCacheStatsItem> data, int hoursB
_legendPanels[PlanCacheChart] = null;
}
PlanCacheChart.Plot.Clear();
_planCacheHover?.Clear();
TabHelpers.ApplyDarkModeToChart(PlanCacheChart);

var dataList = data?.ToList() ?? new List<PlanCacheStatsItem>();
Expand Down Expand Up @@ -650,6 +675,7 @@ private void LoadPlanCacheChart(IEnumerable<PlanCacheStatsItem> data, int hoursB
singleScatter.MarkerSize = 5;
singleScatter.Color = TabHelpers.ChartColors[3];
singleScatter.LegendText = "Single-Use";
_planCacheHover?.Add(singleScatter, "Single-Use");

// Multi-Use series with gap filling
var (multiXs, multiYs) = TabHelpers.FillTimeSeriesGaps(
Expand All @@ -661,6 +687,7 @@ private void LoadPlanCacheChart(IEnumerable<PlanCacheStatsItem> data, int hoursB
multiScatter.MarkerSize = 5;
multiScatter.Color = TabHelpers.ChartColors[1];
multiScatter.LegendText = "Multi-Use";
_planCacheHover?.Add(multiScatter, "Multi-Use");

_legendPanels[PlanCacheChart] = PlanCacheChart.Plot.ShowLegend(ScottPlot.Edge.Bottom);
PlanCacheChart.Plot.Legend.FontSize = 12;
Expand Down Expand Up @@ -762,6 +789,7 @@ private void LoadMemoryPressureEventsChart(IEnumerable<MemoryPressureEventItem>
_legendPanels[MemoryPressureEventsChart] = null;
}
MemoryPressureEventsChart.Plot.Clear();
_memoryPressureEventsHover?.Clear();
TabHelpers.ApplyDarkModeToChart(MemoryPressureEventsChart);

// Only chart HIGH severity events
Expand All @@ -788,6 +816,7 @@ private void LoadMemoryPressureEventsChart(IEnumerable<MemoryPressureEventItem>
highScatter.MarkerSize = 5;
highScatter.Color = TabHelpers.ChartColors[3];
highScatter.LegendText = "High Pressure Events";
_memoryPressureEventsHover?.Add(highScatter, "High Pressure Events");

_legendPanels[MemoryPressureEventsChart] = MemoryPressureEventsChart.Plot.ShowLegend(ScottPlot.Edge.Bottom);
MemoryPressureEventsChart.Plot.Legend.FontSize = 12;
Expand Down
23 changes: 19 additions & 4 deletions Dashboard/Controls/QueryPerformanceContent.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,23 @@ public partial class QueryPerformanceContent : UserControl
// Legend panel references for edge-based legends (ScottPlot issue #4717 workaround)
private Dictionary<ScottPlot.WPF.WpfPlot, ScottPlot.IPanel?> _legendPanels = new();

// Chart hover tooltips
private Helpers.ChartHoverHelper? _queryDurationHover;
private Helpers.ChartHoverHelper? _procDurationHover;
private Helpers.ChartHoverHelper? _qsDurationHover;
private Helpers.ChartHoverHelper? _execTrendsHover;

public QueryPerformanceContent()
{
InitializeComponent();
SetupChartSaveMenus();
Loaded += OnLoaded;
Unloaded += OnUnloaded;

_queryDurationHover = new Helpers.ChartHoverHelper(QueryPerfTrendsQueryChart, "ms/sec");
_procDurationHover = new Helpers.ChartHoverHelper(QueryPerfTrendsProcChart, "ms/sec");
_qsDurationHover = new Helpers.ChartHoverHelper(QueryPerfTrendsQsChart, "ms/sec");
_execTrendsHover = new Helpers.ChartHoverHelper(QueryPerfTrendsExecChart, "/sec");
}

private void OnUnloaded(object sender, RoutedEventArgs e)
Expand Down Expand Up @@ -243,9 +254,9 @@ await Task.WhenAll(
QueryStoreNoDataMessage.Visibility = queryStore.Count == 0 ? Visibility.Visible : Visibility.Collapsed;

// Populate charts from time-series data
LoadDurationChart(QueryPerfTrendsQueryChart, await queryDurationTrendsTask, _perfTrendsHoursBack, _perfTrendsFromDate, _perfTrendsToDate, "Duration (ms/sec)", TabHelpers.ChartColors[0]);
LoadDurationChart(QueryPerfTrendsProcChart, await procDurationTrendsTask, _perfTrendsHoursBack, _perfTrendsFromDate, _perfTrendsToDate, "Duration (ms/sec)", TabHelpers.ChartColors[1]);
LoadDurationChart(QueryPerfTrendsQsChart, await qsDurationTrendsTask, _perfTrendsHoursBack, _perfTrendsFromDate, _perfTrendsToDate, "Duration (ms/sec)", TabHelpers.ChartColors[4]);
LoadDurationChart(QueryPerfTrendsQueryChart, await queryDurationTrendsTask, _perfTrendsHoursBack, _perfTrendsFromDate, _perfTrendsToDate, "Duration (ms/sec)", TabHelpers.ChartColors[0], _queryDurationHover);
LoadDurationChart(QueryPerfTrendsProcChart, await procDurationTrendsTask, _perfTrendsHoursBack, _perfTrendsFromDate, _perfTrendsToDate, "Duration (ms/sec)", TabHelpers.ChartColors[1], _procDurationHover);
LoadDurationChart(QueryPerfTrendsQsChart, await qsDurationTrendsTask, _perfTrendsHoursBack, _perfTrendsFromDate, _perfTrendsToDate, "Duration (ms/sec)", TabHelpers.ChartColors[4], _qsDurationHover);
LoadExecChart(await execTrendsTask, _perfTrendsHoursBack, _perfTrendsFromDate, _perfTrendsToDate);
}
catch (Exception ex)
Expand Down Expand Up @@ -890,7 +901,7 @@ private void LongRunningQueryPatternsNumericFilterTextBox_TextChanged(object sen
/// Renders a duration trend chart from time-series data (per-collection_time aggregation).
/// Replaces the old per-query-summary approach that produced too few data points.
/// </summary>
private void LoadDurationChart(WpfPlot chart, IEnumerable<DurationTrendItem> trendData, int hoursBack, DateTime? fromDate, DateTime? toDate, string legendText, ScottPlot.Color color)
private void LoadDurationChart(WpfPlot chart, IEnumerable<DurationTrendItem> trendData, int hoursBack, DateTime? fromDate, DateTime? toDate, string legendText, ScottPlot.Color color, Helpers.ChartHoverHelper? hover = null)
{
try
{
Expand All @@ -905,6 +916,7 @@ private void LoadDurationChart(WpfPlot chart, IEnumerable<DurationTrendItem> tre
_legendPanels[chart] = null;
}
chart.Plot.Clear();
hover?.Clear();
TabHelpers.ApplyDarkModeToChart(chart);

var dataList = (trendData ?? Enumerable.Empty<DurationTrendItem>())
Expand All @@ -920,6 +932,7 @@ private void LoadDurationChart(WpfPlot chart, IEnumerable<DurationTrendItem> tre
scatter.MarkerSize = 5;
scatter.Color = color;
scatter.LegendText = legendText;
hover?.Add(scatter, legendText);

if (xs.Length == 0)
{
Expand Down Expand Up @@ -959,6 +972,7 @@ private void LoadExecChart(IEnumerable<ExecutionTrendItem> execTrends, int hours
_legendPanels[QueryPerfTrendsExecChart] = null;
}
QueryPerfTrendsExecChart.Plot.Clear();
_execTrendsHover?.Clear();
TabHelpers.ApplyDarkModeToChart(QueryPerfTrendsExecChart);

var dataList = (execTrends ?? Enumerable.Empty<ExecutionTrendItem>())
Expand All @@ -974,6 +988,7 @@ private void LoadExecChart(IEnumerable<ExecutionTrendItem> execTrends, int hours
scatter.MarkerSize = 5;
scatter.Color = TabHelpers.ChartColors[0];
scatter.LegendText = "Executions/sec";
_execTrendsHover?.Add(scatter, "Executions/sec");

if (xs.Length == 0)
{
Expand Down
Loading