@@ -86,6 +86,8 @@ public partial class ResourceMetricsContent : UserControl
8686 private Helpers . ChartHoverHelper ? _spinlockStatsHover ;
8787 private Helpers . ChartHoverHelper ? _fileIoReadHover ;
8888 private Helpers . ChartHoverHelper ? _fileIoWriteHover ;
89+ private Helpers . ChartHoverHelper ? _fileIoReadThroughputHover ;
90+ private Helpers . ChartHoverHelper ? _fileIoWriteThroughputHover ;
8991 private Helpers . ChartHoverHelper ? _perfmonHover ;
9092 private Helpers . ChartHoverHelper ? _waitStatsHover ;
9193 private Helpers . ChartHoverHelper ? _tempdbStatsHover ;
@@ -111,6 +113,8 @@ public ResourceMetricsContent()
111113 _spinlockStatsHover = new Helpers . ChartHoverHelper ( SpinlockStatsChart , "collisions/sec" ) ;
112114 _fileIoReadHover = new Helpers . ChartHoverHelper ( UserDbReadLatencyChart , "ms" ) ;
113115 _fileIoWriteHover = new Helpers . ChartHoverHelper ( UserDbWriteLatencyChart , "ms" ) ;
116+ _fileIoReadThroughputHover = new Helpers . ChartHoverHelper ( FileIoReadThroughputChart , "MB/s" ) ;
117+ _fileIoWriteThroughputHover = new Helpers . ChartHoverHelper ( FileIoWriteThroughputChart , "MB/s" ) ;
114118 _perfmonHover = new Helpers . ChartHoverHelper ( PerfmonCountersChart , "" ) ;
115119 _waitStatsHover = new Helpers . ChartHoverHelper ( WaitStatsDetailChart , "ms/sec" ) ;
116120 _tempdbStatsHover = new Helpers . ChartHoverHelper ( TempdbStatsChart , "MB" ) ;
@@ -146,6 +150,10 @@ private void SetupChartContextMenus()
146150 // File I/O Latency charts
147151 TabHelpers . SetupChartContextMenu ( UserDbReadLatencyChart , "UserDB_Read_Latency" , "collect.file_io_stats" ) ;
148152 TabHelpers . SetupChartContextMenu ( UserDbWriteLatencyChart , "UserDB_Write_Latency" , "collect.file_io_stats" ) ;
153+
154+ // File I/O Throughput charts
155+ TabHelpers . SetupChartContextMenu ( FileIoReadThroughputChart , "UserDB_Read_Throughput" , "collect.file_io_stats" ) ;
156+ TabHelpers . SetupChartContextMenu ( FileIoWriteThroughputChart , "UserDB_Write_Throughput" , "collect.file_io_stats" ) ;
149157 TabHelpers . SetupChartContextMenu ( TempDbLatencyChart , "TempDB_Latency" , "collect.file_io_stats" ) ;
150158
151159 // Server Utilization Trends charts
@@ -225,6 +233,7 @@ await Task.WhenAll(
225233 RefreshTempdbStatsAsync ( ) ,
226234 RefreshSessionStatsAsync ( ) ,
227235 LoadFileIoLatencyChartsAsync ( ) ,
236+ LoadFileIoThroughputChartsAsync ( ) ,
228237 RefreshServerTrendsAsync ( ) ,
229238 RefreshPerfmonCountersTabAsync ( ) ,
230239 RefreshWaitStatsDetailTabAsync ( )
@@ -837,11 +846,11 @@ private async Task LoadFileIoLatencyChartsAsync()
837846
838847 // Load User DB data only - TempDB latency moved to TempDB Stats tab
839848 var userDbData = await _databaseService . GetFileIoLatencyTimeSeriesAsync ( isTempDb : false , _fileIoHoursBack , _fileIoFromDate , _fileIoToDate ) ;
840- LoadFileIoChart ( UserDbReadLatencyChart , userDbData , d => d . ReadLatencyMs , "Read Latency (ms)" , colors , xMin , xMax , _fileIoReadHover ) ;
841- LoadFileIoChart ( UserDbWriteLatencyChart , userDbData , d => d . WriteLatencyMs , "Write Latency (ms)" , colors , xMin , xMax , _fileIoWriteHover ) ;
849+ LoadFileIoChart ( UserDbReadLatencyChart , userDbData , d => d . ReadLatencyMs , "Read Latency (ms)" , colors , xMin , xMax , _fileIoReadHover , d => d . ReadQueuedLatencyMs ) ;
850+ LoadFileIoChart ( UserDbWriteLatencyChart , userDbData , d => d . WriteLatencyMs , "Write Latency (ms)" , colors , xMin , xMax , _fileIoWriteHover , d => d . WriteQueuedLatencyMs ) ;
842851 }
843852
844- private void LoadFileIoChart ( ScottPlot . WPF . WpfPlot chart , List < FileIoLatencyTimeSeriesItem > data , Func < FileIoLatencyTimeSeriesItem , decimal > latencySelector , string yLabel , ScottPlot . Color [ ] colors , double xMin , double xMax , Helpers . ChartHoverHelper ? hover = null )
853+ private void LoadFileIoChart ( ScottPlot . WPF . WpfPlot chart , List < FileIoLatencyTimeSeriesItem > data , Func < FileIoLatencyTimeSeriesItem , decimal > latencySelector , string yLabel , ScottPlot . Color [ ] colors , double xMin , double xMax , Helpers . ChartHoverHelper ? hover = null , Func < FileIoLatencyTimeSeriesItem , decimal > ? queuedSelector = null )
845854 {
846855 DateTime rangeStart = DateTime . FromOADate ( xMin ) ;
847856 DateTime rangeEnd = DateTime . FromOADate ( xMax ) ;
@@ -856,6 +865,9 @@ private void LoadFileIoChart(ScottPlot.WPF.WpfPlot chart, List<FileIoLatencyTime
856865 TabHelpers . ApplyDarkModeToChart ( chart ) ;
857866 hover ? . Clear ( ) ;
858867
868+ // Check if any queued data exists (only render overlay if there's real data)
869+ bool hasQueuedData = queuedSelector != null && data != null && data . Any ( d => queuedSelector ( d ) > 0 ) ;
870+
859871 if ( data != null && data . Count > 0 )
860872 {
861873 // Get all unique time points for gap filling
@@ -879,13 +891,31 @@ private void LoadFileIoChart(ScottPlot.WPF.WpfPlot chart, List<FileIoLatencyTime
879891 var scatter = chart . Plot . Add . Scatter ( xs , ys ) ;
880892 scatter . LineWidth = 2 ;
881893 scatter . MarkerSize = 5 ;
882- scatter . Color = colors [ colorIndex % colors . Length ] ;
894+ var color = colors [ colorIndex % colors . Length ] ;
895+ scatter . Color = color ;
883896
884897 // Use just the filename for legend (not database.filename which is redundant)
885898 var fileName = fileData . First ( ) . FileName ;
886899 scatter . LegendText = fileName ;
887900 hover ? . Add ( scatter , fileName ) ;
888901
902+ // Add queued I/O overlay as dashed line with same color
903+ if ( hasQueuedData )
904+ {
905+ var queuedValues = fileData . Select ( d => ( double ) queuedSelector ! ( d ) ) ;
906+ if ( queuedValues . Any ( v => v > 0 ) )
907+ {
908+ var ( qxs , qys ) = TabHelpers . FillTimeSeriesGaps ( timePoints , queuedValues ) ;
909+ var queuedScatter = chart . Plot . Add . Scatter ( qxs , qys ) ;
910+ queuedScatter . LineWidth = 2 ;
911+ queuedScatter . MarkerSize = 0 ;
912+ queuedScatter . Color = color ;
913+ queuedScatter . LinePattern = ScottPlot . LinePattern . Dashed ;
914+ queuedScatter . LegendText = $ "{ fileName } (queued)";
915+ hover ? . Add ( queuedScatter , $ "{ fileName } (queued)") ;
916+ }
917+ }
918+
889919 colorIndex ++ ;
890920 }
891921 }
@@ -913,6 +943,22 @@ private void LoadFileIoChart(ScottPlot.WPF.WpfPlot chart, List<FileIoLatencyTime
913943 chart . Refresh ( ) ;
914944 }
915945
946+ private async Task LoadFileIoThroughputChartsAsync ( )
947+ {
948+ if ( _databaseService == null ) return ;
949+
950+ DateTime rangeEnd = _fileIoToDate ?? Helpers . ServerTimeHelper . ServerNow ;
951+ DateTime rangeStart = _fileIoFromDate ?? rangeEnd . AddHours ( - _fileIoHoursBack ) ;
952+ double xMin = rangeStart . ToOADate ( ) ;
953+ double xMax = rangeEnd . ToOADate ( ) ;
954+
955+ var colors = TabHelpers . ChartColors ;
956+
957+ var throughputData = await _databaseService . GetFileIoThroughputTimeSeriesAsync ( isTempDb : false , _fileIoHoursBack , _fileIoFromDate , _fileIoToDate ) ;
958+ LoadFileIoChart ( FileIoReadThroughputChart , throughputData , d => d . ReadThroughputMbPerSec , "Read Throughput (MB/s)" , colors , xMin , xMax , _fileIoReadThroughputHover ) ;
959+ LoadFileIoChart ( FileIoWriteThroughputChart , throughputData , d => d . WriteThroughputMbPerSec , "Write Throughput (MB/s)" , colors , xMin , xMax , _fileIoWriteThroughputHover ) ;
960+ }
961+
916962 #endregion
917963
918964 #region Server Trends Tab
0 commit comments