From ef82a5f08a8f9e7a0a482afe0536a9a12ab04a58 Mon Sep 17 00:00:00 2001 From: Jake Scott <69864859+JRScott812@users.noreply.github.com> Date: Wed, 24 Jun 2026 17:54:19 -0400 Subject: [PATCH 1/2] Added `Disk Stats` functionality to the Performance Monitor in Command Palette. As requested in issue #46724 --- .../DevHome/Helpers/ChartHelper.cs | 10 + .../DevHome/Helpers/DataManager.cs | 24 ++ .../DevHome/Helpers/DataType.cs | 5 + .../DevHome/Helpers/DiskStats.cs | 192 +++++++++ .../DevHome/Helpers/SystemData.cs | 3 + .../Templates/SystemDiskUsageTemplate.json | 88 +++++ .../DiskSpeedUnit.cs | 20 + .../Icons.cs | 4 + ...osoft.CmdPal.Ext.PerformanceMonitor.csproj | 3 + .../PerformanceMonitorCommandsProvider.cs | 6 + .../PerformanceWidgetsPage.cs | 368 +++++++++++++++++- .../SettingsManager.cs | 16 + .../Strings/en-US/Resources.resw | 116 +++++- 13 files changed, 850 insertions(+), 5 deletions(-) create mode 100644 src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Helpers/DiskStats.cs create mode 100644 src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Templates/SystemDiskUsageTemplate.json create mode 100644 src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DiskSpeedUnit.cs diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Helpers/ChartHelper.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Helpers/ChartHelper.cs index bec3398c8b76..4cc56866ef96 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Helpers/ChartHelper.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Helpers/ChartHelper.cs @@ -17,6 +17,7 @@ public enum ChartType GPU, Mem, Net, + Dis, } public const int ChartHeight = 86; @@ -28,6 +29,7 @@ public enum ChartType private const string GPULineStyle = "fill:none;stroke:rgb(222,104,242);stroke-width:1"; private const string MemLineStyle = "fill:none;stroke:rgb(92,158,250);stroke-width:1"; private const string NetLineStyle = "fill:none;stroke:rgb(245,98,142);stroke-width:1"; + private const string DisLineStyle = "fill:none;stroke:rgb(103,153,24);stroke-width:1"; private const string FillStyle = "fill:url(#gradientId);stroke:transparent"; @@ -43,6 +45,9 @@ public enum ChartType private const string NetBrushStop1Style = "stop-color:rgb(245,98,142);stop-opacity:0.4"; private const string NetBrushStop2Style = "stop-color:rgb(130,0,47);stop-opacity:0.25"; + private const string DisBrushStop1Style = "stop-color:rgb(103,153,24);stop-opacity:0.4"; + private const string DisBrushStop2Style = "stop-color:rgb(45,62,15);stop-opacity:0.25"; + private const string SvgElement = "svg"; private const string RectElement = "rect"; private const string PolylineElement = "polyline"; @@ -174,6 +179,10 @@ private static XElement CreateGradientDefinition(ChartType type) stop1Style = NetBrushStop1Style; stop2Style = NetBrushStop2Style; break; + case ChartType.Dis: + stop1Style = DisBrushStop1Style; + stop2Style = DisBrushStop2Style; + break; case ChartType.CPU: default: stop1Style = CPUBrushStop1Style; @@ -213,6 +222,7 @@ private static string GetLineStyle(ChartType type) ChartType.GPU => GPULineStyle, ChartType.Mem => MemLineStyle, ChartType.Net => NetLineStyle, + ChartType.Dis => DisLineStyle, _ => CPULineStyle, }; diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Helpers/DataManager.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Helpers/DataManager.cs index 8dc80db69826..aefc001de975 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Helpers/DataManager.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Helpers/DataManager.cs @@ -45,6 +45,14 @@ private void GetNetworkData() } } + private void GetDiskData() + { + lock (_systemData.DiskStats) + { + _systemData.DiskStats.GetData(); + } + } + private void GetGPUData() { lock (_systemData.GPUStats) @@ -107,6 +115,13 @@ private void UpdateTimer_Elapsed(object? sender, System.Timers.ElapsedEventArgs break; } + case DataType.Disk: + { + // disk + GetDiskData(); + break; + } + case DataType.Battery: { GetBatteryData(); @@ -146,6 +161,7 @@ private void UpdateTimer_Elapsed(object? sender, System.Timers.ElapsedEventArgs DataType.GPU => "GPU.FirstUpdate", DataType.Memory => "Memory.FirstUpdate", DataType.Network => "Network.FirstUpdate", + DataType.Disk => "Disk.FirstUpdate", DataType.Battery => "Battery.FirstUpdate", _ => null, }; @@ -167,6 +183,14 @@ internal NetworkStats GetNetworkStats() } } + internal DiskStats GetDiskStats() + { + lock (_systemData.DiskStats) + { + return _systemData.DiskStats; + } + } + internal GPUStats GetGPUStats() { lock (_systemData.GPUStats) diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Helpers/DataType.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Helpers/DataType.cs index e9af0f6986ad..700e9ccf4c72 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Helpers/DataType.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Helpers/DataType.cs @@ -37,4 +37,9 @@ public enum DataType /// Battery related data. /// Battery, + + /// + /// Disk related data. + /// + Disk, } diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Helpers/DiskStats.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Helpers/DiskStats.cs new file mode 100644 index 000000000000..fafd40977e51 --- /dev/null +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Helpers/DiskStats.cs @@ -0,0 +1,192 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Microsoft.CmdPal.Common; + +namespace CoreWidgetProvider.Helpers; + +internal sealed partial class DiskStats : PerformanceCounterSourceBase, IDisposable +{ + private readonly Dictionary> _diskCounters = new(); + private bool _diskCounterReadFailureLogged; + + private Dictionary DiskUsages { get; set; } = new(); + + private Dictionary> DiskChartValues { get; set; } = new(); + + public sealed class Data + { + public float Usage + { + get; set; + } + + public float Read + { + get; set; + } + + public float Written + { + get; set; + } + } + + public DiskStats() + { + InitDiskPerfCounters(); + } + + private void InitDiskPerfCounters() + { + try + { + var perfCounterCategory = CreatePerformanceCounterCategory("PhysicalDisk"); + if (perfCounterCategory is null) + { + return; + } + + var instanceNames = perfCounterCategory.GetInstanceNames(); + foreach (var instanceName in instanceNames) + { + if (string.Equals(instanceName, "_Total", StringComparison.OrdinalIgnoreCase)) + { + continue; + } + + try + { + var bytesRead = CreatePerformanceCounter("PhysicalDisk", "Disk Read Bytes/sec", instanceName, logFailure: false); + var bytesWritten = CreatePerformanceCounter("PhysicalDisk", "Disk Write Bytes/sec", instanceName, logFailure: false); + var diskTime = CreatePerformanceCounter("PhysicalDisk", "% Disk Time", instanceName, logFailure: false); + if (bytesRead is null || bytesWritten is null || diskTime is null) + { + bytesRead?.Dispose(); + bytesWritten?.Dispose(); + diskTime?.Dispose(); + continue; + } + + var instanceCounters = new List { bytesRead, bytesWritten, diskTime }; + _diskCounters.Add(instanceName, instanceCounters); + DiskChartValues.Add(instanceName, new List()); + DiskUsages.Add(instanceName, new Data()); + } + catch (Exception) + { + // Skip interfaces whose counters cannot be initialized. + } + } + } + catch (Exception ex) + { + CoreLogger.LogError("Failed to initialize disk performance counters.", ex); + } + } + + public void GetData() + { + foreach (var diskCounterWithName in _diskCounters) + { + try + { + var read = diskCounterWithName.Value[0].NextValue(); + var written = diskCounterWithName.Value[1].NextValue(); + var diskTimePercent = diskCounterWithName.Value[2].NextValue(); + var name = diskCounterWithName.Key; + + DiskUsages[name].Read = read; + DiskUsages[name].Written = written; + DiskUsages[name].Usage = diskTimePercent / 100f; + + var chartValues = DiskChartValues[name]; + lock (chartValues) + { + ChartHelper.AddNextChartValue(diskTimePercent, chartValues); + } + } + catch (Exception ex) + { + LogFailureOnce(ref _diskCounterReadFailureLogged, "Failed while reading disk performance counters.", ex); + } + } + } + + public string CreateDiskImageUrl(int diskChartIndex) + { + return ChartHelper.CreateImageUrl(DiskChartValues.ElementAt(diskChartIndex).Value, ChartHelper.ChartType.Dis); + } + + public string GetDiskName(int diskIndex) + { + if (DiskChartValues.Count <= diskIndex) + { + return string.Empty; + } + + return DiskChartValues.ElementAt(diskIndex).Key; + } + + public Data GetDiskUsage(int diskIndex) + { + if (DiskChartValues.Count <= diskIndex) + { + return new Data(); + } + + var currDiskName = DiskChartValues.ElementAt(diskIndex).Key; + if (!DiskUsages.TryGetValue(currDiskName, out var value)) + { + return new Data(); + } + + return value; + } + + public int GetPrevDiskIndex(int diskIndex) + { + if (DiskChartValues.Count == 0) + { + return 0; + } + + if (diskIndex == 0) + { + return DiskChartValues.Count - 1; + } + + return diskIndex - 1; + } + + public int GetNextDiskIndex(int diskIndex) + { + if (DiskChartValues.Count == 0) + { + return 0; + } + + if (diskIndex == DiskChartValues.Count - 1) + { + return 0; + } + + return diskIndex + 1; + } + + public void Dispose() + { + foreach (var counterPair in _diskCounters) + { + foreach (var counter in counterPair.Value) + { + counter.Dispose(); + } + } + } +} diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Helpers/SystemData.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Helpers/SystemData.cs index 55fdbc53dbc5..1abab760d247 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Helpers/SystemData.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Helpers/SystemData.cs @@ -13,6 +13,7 @@ internal sealed partial class SystemData private readonly Lazy _memoryStats = new(() => CreateGuarded("Memory.Initialize", static () => new MemoryStats())); private readonly Lazy _networkStats = new(() => CreateGuarded("Network.Initialize", static () => new NetworkStats())); + private readonly Lazy _diskStats = new(() => CreateGuarded("Disk.Initialize", static () => new DiskStats())); private readonly Lazy _gpuStats = new(() => CreateGuarded("GPU.Initialize", static () => new GPUStats())); private readonly Lazy _cpuStats = new(() => CreateGuarded("CPU.Initialize", static () => new CPUStats())); private readonly Lazy _batteryStats = new(() => CreateGuarded("Battery.Initialize", static () => new BatteryStats())); @@ -21,6 +22,8 @@ internal sealed partial class SystemData public NetworkStats NetworkStats => _networkStats.Value; + public DiskStats DiskStats => _diskStats.Value; + public GPUStats GPUStats => _gpuStats.Value; public CPUStats CpuStats => _cpuStats.Value; diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Templates/SystemDiskUsageTemplate.json b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Templates/SystemDiskUsageTemplate.json new file mode 100644 index 000000000000..80194b3af0af --- /dev/null +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DevHome/Templates/SystemDiskUsageTemplate.json @@ -0,0 +1,88 @@ +{ + "type": "AdaptiveCard", + "body": [ + { + "type": "Container", + "$when": "${errorMessage != null}", + "items": [ + { + "type": "TextBlock", + "text": "${errorMessage}", + "wrap": true, + "size": "small" + } + ], + "style": "warning" + }, + { + "type": "Container", + "$when": "${errorMessage == null}", + "items": [ + { + "type": "Image", + "url": "${diskGraphUrl}", + "height": "${chartHeight}", + "width": "${chartWidth}", + "$when": "${$host.widgetSize != \"small\"}", + "horizontalAlignment": "center" + }, + { + "type": "ColumnSet", + "columns": [ + { + "type": "Column", + "items": [ + { + "text": "%DiskUsage_Widget_Template/Sent%", + "type": "TextBlock", + "spacing": "none", + "size": "small", + "isSubtle": true + }, + { + "text": "${diskRead}", + "type": "TextBlock", + "size": "large", + "weight": "bolder" + } + ] + }, + { + "type": "Column", + "items": [ + { + "text": "%DiskUsage_Widget_Template/Received%", + "type": "TextBlock", + "spacing": "none", + "size": "small", + "isSubtle": true, + "horizontalAlignment": "right" + }, + { + "text": "${diskWrite}", + "type": "TextBlock", + "size": "large", + "weight": "bolder", + "horizontalAlignment": "right" + } + ] + } + ] + }, + { + "text": "%DiskUsage_Widget_Template/Disk_Name%", + "type": "TextBlock", + "size": "small", + "isSubtle": true + }, + { + "text": "${diskName}", + "type": "TextBlock", + "size": "medium" + } + ] + } + ], + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "version": "1.5" +} diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DiskSpeedUnit.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DiskSpeedUnit.cs new file mode 100644 index 000000000000..7fea63be5b6d --- /dev/null +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/DiskSpeedUnit.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.CmdPal.Ext.PerformanceMonitor; + +/// +/// Controls the unit used to display disk read/write speed. +/// +internal enum DiskSpeedUnit +{ + /// Bits per second (Kbps, Mbps, Gbps) — SI decimal prefixes. + BitsPerSecond, + + /// Bytes per second (KB/s, MB/s, GB/s) — SI decimal prefixes. + BytesPerSecond, + + /// Bytes per second (KiB/s, MiB/s, GiB/s) — IEC binary prefixes. + BinaryBytesPerSecond, +} diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Icons.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Icons.cs index 02b704d3d434..56fb01896c0f 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Icons.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Icons.cs @@ -19,6 +19,10 @@ internal static class Icons internal static IconInfo HardDriveIcon => new("\uEDA2"); // HardDrive icon + internal static IconInfo FileReadIcon => new("\uE890"); // FileRead icon + + internal static IconInfo FileWriteIcon => new("\uE70F"); // FileWrite icon + internal static IconInfo NetworkIcon => new("\uEC05"); // Network icon internal static IconInfo NetworkUpIcon => new("\uE74A"); // Up arrow icon diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Microsoft.CmdPal.Ext.PerformanceMonitor.csproj b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Microsoft.CmdPal.Ext.PerformanceMonitor.csproj index 9ec357605eaf..319296f5406e 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Microsoft.CmdPal.Ext.PerformanceMonitor.csproj +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Microsoft.CmdPal.Ext.PerformanceMonitor.csproj @@ -50,6 +50,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/PerformanceMonitorCommandsProvider.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/PerformanceMonitorCommandsProvider.cs index 18864c1f8798..a3973043b0e0 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/PerformanceMonitorCommandsProvider.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/PerformanceMonitorCommandsProvider.cs @@ -29,6 +29,7 @@ public partial class PerformanceMonitorCommandsProvider : CommandProvider private PerformanceWidgetsPage? _bandPage; private PerformanceWidgetsPage? _cpuBandPage; private PerformanceWidgetsPage? _memoryBandPage; + private PerformanceWidgetsPage? _diskBandPage; private PerformanceWidgetsPage? _networkBandPage; private PerformanceWidgetsPage? _gpuBandPage; private PerformanceWidgetsPage? _batteryBandPage; @@ -138,6 +139,7 @@ private void SetEnabledState() _cpuBandPage = new PerformanceWidgetsPage(_settingsManager, true, PerformanceMetricKind.Cpu); _memoryBandPage = new PerformanceWidgetsPage(_settingsManager, true, PerformanceMetricKind.Memory); _networkBandPage = new PerformanceWidgetsPage(_settingsManager, true, PerformanceMetricKind.Network); + _diskBandPage = new PerformanceWidgetsPage(_settingsManager, true, PerformanceMetricKind.Disk); _gpuBandPage = new PerformanceWidgetsPage(_settingsManager, true, PerformanceMetricKind.Gpu); _batteryBandPage = new PerformanceWidgetsPage(_settingsManager, true, PerformanceMetricKind.Battery); @@ -146,6 +148,7 @@ private void SetEnabledState() new CommandItem(_cpuBandPage) { Title = Resources.GetResource("CPU_Usage_Title") }, new CommandItem(_memoryBandPage) { Title = Resources.GetResource("Memory_Usage_Title") }, new CommandItem(_networkBandPage) { Title = Resources.GetResource("Network_Usage_Title") }, + new CommandItem(_diskBandPage) { Title = Resources.GetResource("Disk_Usage_Title") }, new CommandItem(_gpuBandPage) { Title = Resources.GetResource("GPU_Usage_Title") } ]; var batteryStats = new BatteryStats(); @@ -182,6 +185,9 @@ private void DisposeActivePages() _memoryBandPage?.Dispose(); _memoryBandPage = null; + _diskBandPage?.Dispose(); + _diskBandPage = null; + _networkBandPage?.Dispose(); _networkBandPage = null; diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/PerformanceWidgetsPage.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/PerformanceWidgetsPage.cs index 9207e4b48619..0ce3e0ad93b5 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/PerformanceWidgetsPage.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/PerformanceWidgetsPage.cs @@ -31,6 +31,7 @@ internal enum PerformanceMetricKind Cpu, Memory, Network, + Disk, Gpu, Battery, } @@ -59,6 +60,7 @@ internal sealed partial class PerformanceWidgetsPage : OnLoadStaticListPage, IDi PerformanceMetricKind.Cpu => Icons.CpuIcon, PerformanceMetricKind.Memory => Icons.MemoryIcon, PerformanceMetricKind.Network => Icons.NetworkIcon, + PerformanceMetricKind.Disk => Icons.HardDriveIcon, PerformanceMetricKind.Gpu => Icons.GpuIcon, PerformanceMetricKind.Battery => _batteryPage?.CurrentIcon ?? Icons.BatteryIcon, _ => Icons.PerformanceMonitorIcon, @@ -74,6 +76,9 @@ internal sealed partial class PerformanceWidgetsPage : OnLoadStaticListPage, IDi private readonly SystemMemoryUsageWidgetPage? _memoryPage; private readonly ListItem? _memoryItem; + private readonly SystemDiskUsageWidgetPage? _diskPage; + private readonly ListItem? _diskItem; + private readonly SystemNetworkUsageWidgetPage? _networkPage; private readonly ListItem? _networkItem; @@ -89,6 +94,12 @@ internal sealed partial class PerformanceWidgetsPage : OnLoadStaticListPage, IDi private string _networkUpSpeed = string.Empty; private string _networkDownSpeed = string.Empty; + // For bands, we want two bands, one for read and one for write + private ListItem? _diskReadItem; + private ListItem? _diskWriteItem; + private string _diskReadSpeed = string.Empty; + private string _diskWriteSpeed = string.Empty; + public PerformanceWidgetsPage(SettingsManager settingsManager, bool isBandPage = false, PerformanceMetricKind? singleMetric = null) { _isBandPage = isBandPage; @@ -147,6 +158,26 @@ public PerformanceWidgetsPage(SettingsManager settingsManager, bool isBandPage = }; } + if (IncludesMetric(PerformanceMetricKind.Disk)) + { + _diskPage = new SystemDiskUsageWidgetPage(settingsManager); + _diskItem = new ListItem(_diskPage) + { + Title = _diskPage.GetItemTitle(isBandPage), + MoreCommands = _diskPage.Commands, + }; + + _diskPage.Updated += (s, e) => + { + _diskItem.Title = _diskPage.GetItemTitle(isBandPage); + _diskReadSpeed = _diskPage.GetReadSpeed(); + _diskWriteSpeed = _diskPage.GetWriteSpeed(); + _diskReadItem?.Title = $"{_diskReadSpeed}"; + _diskWriteItem?.Title = $"{_diskWriteSpeed}"; + RaiseItemsChanged(); + }; + } + if (IncludesMetric(PerformanceMetricKind.Gpu)) { _gpuPage = new SystemGPUUsageWidgetPage(); @@ -203,6 +234,11 @@ public PerformanceWidgetsPage(SettingsManager settingsManager, bool isBandPage = _networkItem.Subtitle = Resources.GetResource("Network_Usage_Subtitle"); } + if (_diskItem is not null) + { + _diskItem.Subtitle = Resources.GetResource("Disk_Usage_Subtitle"); + } + if (_gpuItem is not null) { _gpuItem.Subtitle = Resources.GetResource("GPU_Usage_Subtitle"); @@ -220,6 +256,7 @@ protected override void Loaded() _cpuPage?.PushActivate(); _memoryPage?.PushActivate(); _networkPage?.PushActivate(); + _diskPage?.PushActivate(); _gpuPage?.PushActivate(); _batteryPage?.PushActivate(); } @@ -229,6 +266,7 @@ protected override void Unloaded() _cpuPage?.PopActivate(); _memoryPage?.PopActivate(); _networkPage?.PopActivate(); + _diskPage?.PopActivate(); _gpuPage?.PopActivate(); _batteryPage?.PopActivate(); } @@ -243,6 +281,7 @@ public override IListItem[] GetItems() PerformanceMetricKind.Cpu => new IListItem[] { _cpuItem! }, PerformanceMetricKind.Memory => new IListItem[] { _memoryItem! }, PerformanceMetricKind.Network => new IListItem[] { _networkItem! }, + PerformanceMetricKind.Disk => new IListItem[] { _diskItem! }, PerformanceMetricKind.Gpu => new IListItem[] { _gpuItem! }, PerformanceMetricKind.Battery => new IListItem[] { _batteryItem! }, _ => Array.Empty(), @@ -253,8 +292,8 @@ public override IListItem[] GetItems() { // TODO add details return _batteryItem is not null - ? new[] { _cpuItem!, _memoryItem!, _networkItem!, _gpuItem!, _batteryItem! } - : new[] { _cpuItem!, _memoryItem!, _networkItem!, _gpuItem! }; + ? new[] { _cpuItem!, _memoryItem!, _networkItem!, _diskItem!, _gpuItem!, _batteryItem! } + : new[] { _cpuItem!, _memoryItem!, _networkItem!, _diskItem!, _gpuItem! }; } else { @@ -274,9 +313,25 @@ public override IListItem[] GetItems() MoreCommands = _networkPage!.Commands, }; + _diskReadItem = new ListItem(_diskPage!) + { + Title = $"{_diskReadSpeed}", + Subtitle = Resources.GetResource("Disk_Read_Subtitle"), + Icon = Icons.FileReadIcon, + MoreCommands = _diskPage!.Commands, + }; + + _diskWriteItem = new ListItem(_diskPage!) + { + Title = $"{_diskWriteSpeed}", + Subtitle = Resources.GetResource("Disk_Write_Subtitle"), + Icon = Icons.FileWriteIcon, + MoreCommands = _diskPage!.Commands, + }; + return _batteryItem is not null - ? new[] { _cpuItem!, _memoryItem!, _networkUpItem!, _networkDownItem!, _gpuItem!, _batteryItem! } - : new[] { _cpuItem!, _memoryItem!, _networkUpItem!, _networkDownItem!, _gpuItem! }; + ? new[] { _cpuItem!, _memoryItem!, _networkUpItem!, _networkDownItem!, _diskReadItem!, _diskWriteItem!, _gpuItem!, _batteryItem! } + : new[] { _cpuItem!, _memoryItem!, _networkUpItem!, _networkDownItem!, _diskReadItem!, _diskWriteItem!, _gpuItem! }; } } @@ -285,6 +340,7 @@ public void Dispose() _cpuPage?.Dispose(); _memoryPage?.Dispose(); _networkPage?.Dispose(); + _diskPage?.Dispose(); _gpuPage?.Dispose(); _batteryPage?.Dispose(); } @@ -301,6 +357,7 @@ private static string GetMetricSuffix(PerformanceMetricKind metric) PerformanceMetricKind.Cpu => "cpu", PerformanceMetricKind.Memory => "memory", PerformanceMetricKind.Network => "network", + PerformanceMetricKind.Disk => "disk", PerformanceMetricKind.Gpu => "gpu", PerformanceMetricKind.Battery => "battery", _ => "unknown", @@ -663,6 +720,309 @@ public void Dispose() } } +internal sealed partial class SystemDiskUsageWidgetPage : WidgetPage, IDisposable +{ + public override string Id => "com.microsoft.cmdpal.disk_widget"; + + public override string Title => Resources.GetResource("Disk_Usage_Title"); + + public override IconInfo Icon => Icons.HardDriveIcon; + + private readonly DataManager _dataManager; + private readonly SettingsManager _settingsManager; + private int _diskIndex; + + public SystemDiskUsageWidgetPage(SettingsManager settingsManager) + { + _settingsManager = settingsManager; + _dataManager = new(DataType.Disk, () => UpdateWidget()); + Commands = [ + new CommandContextItem(new PrevDiskCommand(this) { Name = Resources.GetResource("Previous_Disk_Title") }), + new CommandContextItem(new NextDiskCommand(this) { Name = Resources.GetResource("Next_Disk_Title") }), + new CommandContextItem(OpenTaskManagerCommand.Instance), + ]; + } + + protected override void LoadContentData() + { + // CoreLogger.LogDebug("Getting Disk stats"); + try + { + ContentData.Clear(); + + var timer = Stopwatch.StartNew(); + + var currentData = _dataManager.GetDiskStats(); + + var dataDuration = timer.ElapsedMilliseconds; + + var diskName = currentData.GetDiskName(_diskIndex); + var diskStats = currentData.GetDiskUsage(_diskIndex); + + ContentData["diskUsage"] = FloatToPercentString(diskStats.Usage); + ContentData["diskRead"] = SpeedToString(diskStats.Read); + ContentData["diskWrite"] = SpeedToString(diskStats.Written); + ContentData["diskName"] = diskName; + ContentData["diskGraphUrl"] = currentData.CreateDiskImageUrl(_diskIndex); + ContentData["chartHeight"] = ChartHelper.ChartHeight + "px"; + ContentData["chartWidth"] = ChartHelper.ChartWidth + "px"; + + var contentDuration = timer.ElapsedMilliseconds - dataDuration; + + // CoreLogger.LogDebug($"Disk stats retrieved in {dataDuration} ms, content prepared in {contentDuration} ms. (Total {timer.ElapsedMilliseconds} ms)"); + } + catch (Exception e) + { + ContentData.Clear(); + ContentData["errorMessage"] = e.Message; + return; + } + } + + protected override string GetTemplatePath(WidgetPageState page) + { + return page switch + { + WidgetPageState.Content => @"DevHome\Templates\SystemDiskUsageTemplate.json", + WidgetPageState.Loading => @"DevHome\Templates\SystemDiskUsageTemplate.json", + _ => throw new NotImplementedException(), + }; + } + + public string GetItemTitle(bool isBandPage) + { + if (ContentData.TryGetValue("diskName", out var name) && ContentData.TryGetValue("diskUsage", out var usage)) + { + return isBandPage ? usage : string.Format(CultureInfo.CurrentCulture, Resources.GetResource("Disk_Usage_Label"), name, usage); + } + else + { + return isBandPage ? Resources.GetResource("Disk_Usage_Unknown") : Resources.GetResource("Disk_Usage_Unknown_Label"); + } + } + + // read/write speed is always used for bands + public string GetReadSpeed() + { + if (ContentData.TryGetValue("diskRead", out var readSpeed)) + { + return readSpeed; + } + else + { + return "???"; + } + } + + public string GetWriteSpeed() + { + if (ContentData.TryGetValue("diskWrite", out var writeSpeed)) + { + return writeSpeed; + } + else + { + return "???"; + } + } + + private string SpeedToString(float bytesPerSec) + { + return _settingsManager.DiskSpeedUnit switch + { + DiskSpeedUnit.BytesPerSecond => FormatAsBytesPerSecString(bytesPerSec), + DiskSpeedUnit.BinaryBytesPerSecond => FormatAsBinaryBytesPerSecString(bytesPerSec), + _ => FormatAsBitsPerSecString(bytesPerSec), + }; + } + + private static string FormatAsBitsPerSecString(float value) + { + // Bytes to bits + value *= 8; + + // bits to Kbits + value /= 1024; + if (value < 1024) + { + if (value < 100) + { + return string.Format(CultureInfo.InvariantCulture, "{0:0.0} Kbps", value); + } + + return string.Format(CultureInfo.InvariantCulture, "{0:0} Kbps", value); + } + + // Kbits to Mbits + value /= 1024; + if (value < 1024) + { + if (value < 100) + { + return string.Format(CultureInfo.InvariantCulture, "{0:0.0} Mbps", value); + } + + return string.Format(CultureInfo.InvariantCulture, "{0:0} Mbps", value); + } + + // Mbits to Gbits + value /= 1024; + if (value < 100) + { + return string.Format(CultureInfo.InvariantCulture, "{0:0.0} Gbps", value); + } + + return string.Format(CultureInfo.InvariantCulture, "{0:0} Gbps", value); + } + + private static string FormatAsBytesPerSecString(float value) + { + // Bytes to KB + value /= 1024; + if (value < 1024) + { + if (value < 100) + { + return string.Format(CultureInfo.InvariantCulture, "{0:0.0} KB/s", value); + } + + return string.Format(CultureInfo.InvariantCulture, "{0:0} KB/s", value); + } + + // KB to MB + value /= 1024; + if (value < 1024) + { + if (value < 100) + { + return string.Format(CultureInfo.InvariantCulture, "{0:0.0} MB/s", value); + } + + return string.Format(CultureInfo.InvariantCulture, "{0:0} MB/s", value); + } + + // MB to GB + value /= 1024; + if (value < 100) + { + return string.Format(CultureInfo.InvariantCulture, "{0:0.0} GB/s", value); + } + + return string.Format(CultureInfo.InvariantCulture, "{0:0} GB/s", value); + } + + private static string FormatAsBinaryBytesPerSecString(float value) + { + // Bytes to KiB + value /= 1024; + if (value < 1024) + { + if (value < 100) + { + return string.Format(CultureInfo.InvariantCulture, "{0:0.0} KiB/s", value); + } + + return string.Format(CultureInfo.InvariantCulture, "{0:0} KiB/s", value); + } + + // KiB to MiB + value /= 1024; + if (value < 1024) + { + if (value < 100) + { + return string.Format(CultureInfo.InvariantCulture, "{0:0.0} MiB/s", value); + } + + return string.Format(CultureInfo.InvariantCulture, "{0:0} MiB/s", value); + } + + // MiB to GiB + value /= 1024; + if (value < 100) + { + return string.Format(CultureInfo.InvariantCulture, "{0:0.0} GiB/s", value); + } + + return string.Format(CultureInfo.InvariantCulture, "{0:0} GiB/s", value); + } + + internal override void PushActivate() + { + base.PushActivate(); + if (IsActive) + { + _dataManager.Start(); + } + } + + internal override void PopActivate() + { + base.PopActivate(); + if (!IsActive) + { + _dataManager.Stop(); + } + } + + private void HandlePrevDisk() + { + _diskIndex = _dataManager.GetDiskStats().GetPrevDiskIndex(_diskIndex); + UpdateWidget(); + } + + private void HandleNextDisk() + { + _diskIndex = _dataManager.GetDiskStats().GetNextDiskIndex(_diskIndex); + UpdateWidget(); + } + + public void Dispose() + { + _dataManager.Dispose(); + } + + private sealed partial class PrevDiskCommand : InvokableCommand + { + private readonly SystemDiskUsageWidgetPage _page; + + public PrevDiskCommand(SystemDiskUsageWidgetPage page) + { + _page = page; + } + + public override string Id => "com.microsoft.cmdpal.disk_widget.prev"; + + public override IconInfo Icon => Icons.NavigateBackwardIcon; + + public override ICommandResult Invoke() + { + _page.HandlePrevDisk(); + return CommandResult.KeepOpen(); + } + } + + private sealed partial class NextDiskCommand : InvokableCommand + { + private readonly SystemDiskUsageWidgetPage _page; + + public NextDiskCommand(SystemDiskUsageWidgetPage page) + { + _page = page; + } + + public override string Id => "com.microsoft.cmdpal.disk_widget.next"; + + public override IconInfo Icon => Icons.NavigateForwardIcon; + + public override ICommandResult Invoke() + { + _page.HandleNextDisk(); + return CommandResult.KeepOpen(); + } + } +} + internal sealed partial class SystemNetworkUsageWidgetPage : WidgetPage, IDisposable { public override string Id => "com.microsoft.cmdpal.network_widget"; diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/SettingsManager.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/SettingsManager.cs index fd975a65e7d0..8d1dd40ce32f 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/SettingsManager.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/SettingsManager.cs @@ -30,6 +30,21 @@ internal sealed class SettingsManager : JsonSettingsManager ? unit : NetworkSpeedUnit.BitsPerSecond; + private readonly ChoiceSetSetting _diskSpeedUnit = new( + Namespaced(nameof(DiskSpeedUnit)), + Resources.GetResource("Disk_Speed_Unit_Setting_Title"), + Resources.GetResource("Disk_Speed_Unit_Setting_Description"), + [ + new ChoiceSetSetting.Choice(Resources.GetResource("Disk_Speed_Unit_BitsPerSec"), DiskSpeedUnit.BitsPerSecond.ToString("G")), + new ChoiceSetSetting.Choice(Resources.GetResource("Disk_Speed_Unit_BytesPerSec"), DiskSpeedUnit.BytesPerSecond.ToString("G")), + new ChoiceSetSetting.Choice(Resources.GetResource("Disk_Speed_Unit_BinaryBytesPerSec"), DiskSpeedUnit.BinaryBytesPerSecond.ToString("G")), + ]); + + public DiskSpeedUnit DiskSpeedUnit => + Enum.TryParse(_diskSpeedUnit.Value, out var unit) + ? unit + : DiskSpeedUnit.BitsPerSecond; + private static string SettingsJsonPath() { var directory = Utilities.BaseSettingsPath("Microsoft.CmdPal"); @@ -42,6 +57,7 @@ public SettingsManager() FilePath = SettingsJsonPath(); Settings.Add(_networkSpeedUnit); + Settings.Add(_diskSpeedUnit); LoadSettings(); diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Strings/en-US/Resources.resw b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Strings/en-US/Resources.resw index e6fa2862a5df..b0afb677b44c 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Strings/en-US/Resources.resw +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Strings/en-US/Resources.resw @@ -1,5 +1,64 @@  + @@ -135,6 +194,24 @@ Ethernet + + Utilization + + + Read + + + Write + + + Name + + + Previous disk + + + Next disk + Utilization @@ -183,6 +260,9 @@ Network + + Disk + GPU @@ -257,6 +337,19 @@ Network Usage: ??? + + Disk Usage + + + Disk ({0}): {1} + {0} is the disk interface name, {1} is the usage percentage + + + ??? + + + Disk Usage: ??? + GPU Usage @@ -331,6 +424,12 @@ Receive + + Read + + + Write + Network speed unit @@ -346,4 +445,19 @@ Binary bytes per second (KiB/s, MiB/s, GiB/s) - + + Disk speed unit + + + Choose the unit used to display disk transfer speed + + + Bits per second (Kbps, Mbps, Gbps) + + + Bytes per second (KB/s, MB/s, GB/s) + + + Binary bytes per second (KiB/s, MiB/s, GiB/s) + + \ No newline at end of file From c5c6972d2633f971d8e26dd0b69b75650672353f Mon Sep 17 00:00:00 2001 From: Jake Scott <69864859+JRScott812@users.noreply.github.com> Date: Wed, 24 Jun 2026 23:11:54 -0400 Subject: [PATCH 2/2] Fixes suggestion --- .../PerformanceWidgetsPage.cs | 348 ++++++------------ .../SettingsManager.cs | 2 +- .../Strings/en-US/Resources.resw | 4 +- 3 files changed, 123 insertions(+), 231 deletions(-) diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/PerformanceWidgetsPage.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/PerformanceWidgetsPage.cs index 64010470eb13..9f28b0ef6159 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/PerformanceWidgetsPage.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/PerformanceWidgetsPage.cs @@ -825,123 +825,12 @@ private string SpeedToString(float bytesPerSec) { return _settingsManager.DiskSpeedUnit switch { - DiskSpeedUnit.BytesPerSecond => FormatAsBytesPerSecString(bytesPerSec), - DiskSpeedUnit.BinaryBytesPerSecond => FormatAsBinaryBytesPerSecString(bytesPerSec), - _ => FormatAsBitsPerSecString(bytesPerSec), + DiskSpeedUnit.BytesPerSecond => FormatIncomingData.AsBytesPerSecString(bytesPerSec), + DiskSpeedUnit.BinaryBytesPerSecond => FormatIncomingData.AsBinaryBytesPerSecString(bytesPerSec), + _ => FormatIncomingData.AsBitsPerSecString(bytesPerSec), }; } - private static string FormatAsBitsPerSecString(float value) - { - // Bytes to bits - value *= 8; - - // bits to Kbits - value /= 1024; - if (value < 1024) - { - if (value < 100) - { - return string.Format(CultureInfo.InvariantCulture, "{0:0.0} Kbps", value); - } - - return string.Format(CultureInfo.InvariantCulture, "{0:0} Kbps", value); - } - - // Kbits to Mbits - value /= 1024; - if (value < 1024) - { - if (value < 100) - { - return string.Format(CultureInfo.InvariantCulture, "{0:0.0} Mbps", value); - } - - return string.Format(CultureInfo.InvariantCulture, "{0:0} Mbps", value); - } - - // Mbits to Gbits - value /= 1024; - if (value < 100) - { - return string.Format(CultureInfo.InvariantCulture, "{0:0.0} Gbps", value); - } - - return string.Format(CultureInfo.InvariantCulture, "{0:0} Gbps", value); - } - - private static string FormatAsBytesPerSecString(float value) - { - // Bytes to KB - value /= 1024; - if (value < 1024) - { - if (value < 100) - { - return string.Format(CultureInfo.InvariantCulture, "{0:0.0} KB/s", value); - } - - return string.Format(CultureInfo.InvariantCulture, "{0:0} KB/s", value); - } - - // KB to MB - value /= 1024; - if (value < 1024) - { - if (value < 100) - { - return string.Format(CultureInfo.InvariantCulture, "{0:0.0} MB/s", value); - } - - return string.Format(CultureInfo.InvariantCulture, "{0:0} MB/s", value); - } - - // MB to GB - value /= 1024; - if (value < 100) - { - return string.Format(CultureInfo.InvariantCulture, "{0:0.0} GB/s", value); - } - - return string.Format(CultureInfo.InvariantCulture, "{0:0} GB/s", value); - } - - private static string FormatAsBinaryBytesPerSecString(float value) - { - // Bytes to KiB - value /= 1024; - if (value < 1024) - { - if (value < 100) - { - return string.Format(CultureInfo.InvariantCulture, "{0:0.0} KiB/s", value); - } - - return string.Format(CultureInfo.InvariantCulture, "{0:0} KiB/s", value); - } - - // KiB to MiB - value /= 1024; - if (value < 1024) - { - if (value < 100) - { - return string.Format(CultureInfo.InvariantCulture, "{0:0.0} MiB/s", value); - } - - return string.Format(CultureInfo.InvariantCulture, "{0:0} MiB/s", value); - } - - // MiB to GiB - value /= 1024; - if (value < 100) - { - return string.Format(CultureInfo.InvariantCulture, "{0:0.0} GiB/s", value); - } - - return string.Format(CultureInfo.InvariantCulture, "{0:0} GiB/s", value); - } - internal override void PushActivate() { base.PushActivate(); @@ -1128,123 +1017,12 @@ private string SpeedToString(float bytesPerSec) { return _settingsManager.NetworkSpeedUnit switch { - NetworkSpeedUnit.BytesPerSecond => FormatAsBytesPerSecString(bytesPerSec), - NetworkSpeedUnit.BinaryBytesPerSecond => FormatAsBinaryBytesPerSecString(bytesPerSec), - _ => FormatAsBitsPerSecString(bytesPerSec), + NetworkSpeedUnit.BytesPerSecond => FormatIncomingData.AsBytesPerSecString(bytesPerSec), + NetworkSpeedUnit.BinaryBytesPerSecond => FormatIncomingData.AsBinaryBytesPerSecString(bytesPerSec), + _ => FormatIncomingData.AsBitsPerSecString(bytesPerSec), }; } - private static string FormatAsBitsPerSecString(float value) - { - // Bytes to bits - value *= 8; - - // bits to Kbits - value /= 1024; - if (value < 1024) - { - if (value < 100) - { - return string.Format(CultureInfo.InvariantCulture, "{0:0.0} Kbps", value); - } - - return string.Format(CultureInfo.InvariantCulture, "{0:0} Kbps", value); - } - - // Kbits to Mbits - value /= 1024; - if (value < 1024) - { - if (value < 100) - { - return string.Format(CultureInfo.InvariantCulture, "{0:0.0} Mbps", value); - } - - return string.Format(CultureInfo.InvariantCulture, "{0:0} Mbps", value); - } - - // Mbits to Gbits - value /= 1024; - if (value < 100) - { - return string.Format(CultureInfo.InvariantCulture, "{0:0.0} Gbps", value); - } - - return string.Format(CultureInfo.InvariantCulture, "{0:0} Gbps", value); - } - - private static string FormatAsBytesPerSecString(float value) - { - // Bytes to KB - value /= 1024; - if (value < 1024) - { - if (value < 100) - { - return string.Format(CultureInfo.InvariantCulture, "{0:0.0} KB/s", value); - } - - return string.Format(CultureInfo.InvariantCulture, "{0:0} KB/s", value); - } - - // KB to MB - value /= 1024; - if (value < 1024) - { - if (value < 100) - { - return string.Format(CultureInfo.InvariantCulture, "{0:0.0} MB/s", value); - } - - return string.Format(CultureInfo.InvariantCulture, "{0:0} MB/s", value); - } - - // MB to GB - value /= 1024; - if (value < 100) - { - return string.Format(CultureInfo.InvariantCulture, "{0:0.0} GB/s", value); - } - - return string.Format(CultureInfo.InvariantCulture, "{0:0} GB/s", value); - } - - private static string FormatAsBinaryBytesPerSecString(float value) - { - // Bytes to KiB - value /= 1024; - if (value < 1024) - { - if (value < 100) - { - return string.Format(CultureInfo.InvariantCulture, "{0:0.0} KiB/s", value); - } - - return string.Format(CultureInfo.InvariantCulture, "{0:0} KiB/s", value); - } - - // KiB to MiB - value /= 1024; - if (value < 1024) - { - if (value < 100) - { - return string.Format(CultureInfo.InvariantCulture, "{0:0.0} MiB/s", value); - } - - return string.Format(CultureInfo.InvariantCulture, "{0:0} MiB/s", value); - } - - // MiB to GiB - value /= 1024; - if (value < 100) - { - return string.Format(CultureInfo.InvariantCulture, "{0:0.0} GiB/s", value); - } - - return string.Format(CultureInfo.InvariantCulture, "{0:0} GiB/s", value); - } - internal override void PushActivate() { base.PushActivate(); @@ -1661,3 +1439,117 @@ public override ICommandResult Invoke() return CommandResult.Hide(); } } + +internal static class FormatIncomingData +{ + public static string AsBitsPerSecString(float value) + { + // Bytes to bits + value *= 8; + + // bits to Kbits + value /= 1024; + if (value < 1024) + { + if (value < 100) + { + return string.Format(CultureInfo.InvariantCulture, "{0:0.0} Kbps", value); + } + + return string.Format(CultureInfo.InvariantCulture, "{0:0} Kbps", value); + } + + // Kbits to Mbits + value /= 1024; + if (value < 1024) + { + if (value < 100) + { + return string.Format(CultureInfo.InvariantCulture, "{0:0.0} Mbps", value); + } + + return string.Format(CultureInfo.InvariantCulture, "{0:0} Mbps", value); + } + + // Mbits to Gbits + value /= 1024; + if (value < 100) + { + return string.Format(CultureInfo.InvariantCulture, "{0:0.0} Gbps", value); + } + + return string.Format(CultureInfo.InvariantCulture, "{0:0} Gbps", value); + } + + public static string AsBytesPerSecString(float value) + { + // Bytes to KB + value /= 1024; + if (value < 1024) + { + if (value < 100) + { + return string.Format(CultureInfo.InvariantCulture, "{0:0.0} KB/s", value); + } + + return string.Format(CultureInfo.InvariantCulture, "{0:0} KB/s", value); + } + + // KB to MB + value /= 1024; + if (value < 1024) + { + if (value < 100) + { + return string.Format(CultureInfo.InvariantCulture, "{0:0.0} MB/s", value); + } + + return string.Format(CultureInfo.InvariantCulture, "{0:0} MB/s", value); + } + + // MB to GB + value /= 1024; + if (value < 100) + { + return string.Format(CultureInfo.InvariantCulture, "{0:0.0} GB/s", value); + } + + return string.Format(CultureInfo.InvariantCulture, "{0:0} GB/s", value); + } + + public static string AsBinaryBytesPerSecString(float value) + { + // Bytes to KiB + value /= 1024; + if (value < 1024) + { + if (value < 100) + { + return string.Format(CultureInfo.InvariantCulture, "{0:0.0} KiB/s", value); + } + + return string.Format(CultureInfo.InvariantCulture, "{0:0} KiB/s", value); + } + + // KiB to MiB + value /= 1024; + if (value < 1024) + { + if (value < 100) + { + return string.Format(CultureInfo.InvariantCulture, "{0:0.0} MiB/s", value); + } + + return string.Format(CultureInfo.InvariantCulture, "{0:0} MiB/s", value); + } + + // MiB to GiB + value /= 1024; + if (value < 100) + { + return string.Format(CultureInfo.InvariantCulture, "{0:0.0} GiB/s", value); + } + + return string.Format(CultureInfo.InvariantCulture, "{0:0} GiB/s", value); + } +} diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/SettingsManager.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/SettingsManager.cs index 8d1dd40ce32f..2d6eedf7fdf1 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/SettingsManager.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/SettingsManager.cs @@ -43,7 +43,7 @@ internal sealed class SettingsManager : JsonSettingsManager public DiskSpeedUnit DiskSpeedUnit => Enum.TryParse(_diskSpeedUnit.Value, out var unit) ? unit - : DiskSpeedUnit.BitsPerSecond; + : DiskSpeedUnit.BytesPerSecond; private static string SettingsJsonPath() { diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Strings/en-US/Resources.resw b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Strings/en-US/Resources.resw index b0afb677b44c..d8c3a7ab77c5 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Strings/en-US/Resources.resw +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Strings/en-US/Resources.resw @@ -197,10 +197,10 @@ Utilization - + Read - + Write