From 993dadd4dd9d6ec11b5b29a933287b3242498802 Mon Sep 17 00:00:00 2001 From: Nick Babcock Date: Fri, 14 May 2021 02:24:50 -0500 Subject: [PATCH] Impose WMI timeouts (#444) WMI queries do not have a timeout by default and can subsequently hang. This commit adds timeouts to avoid these hangs. On timeout, `Get` will throw a `ManagementException` that has an error code of `ManagementStatus.Timedout`. In the case of abstract storage, this exception will be silently swallowed and the statistics from WMI not updated until the next update interval, which seems appropriate. The storage group, on the other hand, a timeout there would cause an initialization exception which would be propagated up to the caller (which seems ok as something must be terribly wrong for that WMI query to fail). The code was also updated to call dispose for all the WMI objects. I don't see this causing a behavior difference, but I found it better to be safe than sorry. The timeouts were chosen to be a compromise between returning in a reasonable timeframe and allowing WMI, which can be terribly slow, to return the query. --- .../Hardware/Storage/AbstractStorage.cs | 88 +++++++++---------- .../Hardware/Storage/StorageGroup.cs | 31 ++++--- 2 files changed, 59 insertions(+), 60 deletions(-) diff --git a/LibreHardwareMonitorLib/Hardware/Storage/AbstractStorage.cs b/LibreHardwareMonitorLib/Hardware/Storage/AbstractStorage.cs index 28d4d40..34660bf 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/AbstractStorage.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/AbstractStorage.cs @@ -123,52 +123,52 @@ namespace LibreHardwareMonitor.Hardware.Storage { string query = $"SELECT * FROM Win32_PerfRawData_PerfDisk_PhysicalDisk Where Name LIKE \"{driveIndex}%\""; - var perfData = new ManagementObjectSearcher(query); - ManagementObject data = perfData.Get().OfType().FirstOrDefault(); - if (data == null) + using (var perfData = new ManagementObjectSearcher(query) {Options = {Timeout = TimeSpan.FromSeconds(2.5)}}) + using (ManagementObjectCollection collection = perfData.Get()) + using (ManagementObject data = collection.OfType().FirstOrDefault()) { - perfData.Dispose(); - return; + if (data == null) + { + return; + } + + ulong value = (ulong)data.Properties["PercentDiskWriteTime"].Value; + ulong valueBase = (ulong)data.Properties["PercentDiskWriteTime_Base"].Value; + _perfWrite.Update(value, valueBase); + _sensorDiskWriteActivity.Value = (float)_perfWrite.Result; + + value = (ulong)data.Properties["PercentIdleTime"].Value; + valueBase = (ulong)data.Properties["PercentIdleTime_Base"].Value; + _perfTotal.Update(value, valueBase); + _sensorDiskTotalActivity.Value = (float)(100.0 - _perfTotal.Result); + + ulong readRateCounter = (ulong)data.Properties["DiskReadBytesPerSec"].Value; + ulong readRate = readRateCounter - _lastReadRateCounter; + _lastReadRateCounter = readRateCounter; + + ulong writeRateCounter = (ulong)data.Properties["DiskWriteBytesPerSec"].Value; + ulong writeRate = writeRateCounter - _lastWriteRateCounter; + _lastWriteRateCounter = writeRateCounter; + + ulong timestampPerfTime = (ulong)data.Properties["Timestamp_PerfTime"].Value; + ulong frequencyPerfTime = (ulong)data.Properties["Frequency_Perftime"].Value; + double currentTime = (double)timestampPerfTime / frequencyPerfTime; + + double timeDeltaSeconds = currentTime - _lastTime; + if (_lastTime == 0 || timeDeltaSeconds > 0.2) + { + double writeSpeed = writeRate * (1 / timeDeltaSeconds); + _sensorDiskWriteRate.Value = (float)writeSpeed; + + double readSpeed = readRate * (1 / timeDeltaSeconds); + _sensorDiskReadRate.Value = (float)readSpeed; + } + + if (_lastTime == 0 || timeDeltaSeconds > 0.2) + { + _lastTime = currentTime; + } } - - ulong value = (ulong)data.Properties["PercentDiskWriteTime"].Value; - ulong valueBase = (ulong)data.Properties["PercentDiskWriteTime_Base"].Value; - _perfWrite.Update(value, valueBase); - _sensorDiskWriteActivity.Value = (float)_perfWrite.Result; - - value = (ulong)data.Properties["PercentIdleTime"].Value; - valueBase = (ulong)data.Properties["PercentIdleTime_Base"].Value; - _perfTotal.Update(value, valueBase); - _sensorDiskTotalActivity.Value = (float)(100.0 - _perfTotal.Result); - - ulong readRateCounter = (ulong)data.Properties["DiskReadBytesPerSec"].Value; - ulong readRate = readRateCounter - _lastReadRateCounter; - _lastReadRateCounter = readRateCounter; - - ulong writeRateCounter = (ulong)data.Properties["DiskWriteBytesPerSec"].Value; - ulong writeRate = writeRateCounter - _lastWriteRateCounter; - _lastWriteRateCounter = writeRateCounter; - - ulong timestampPerfTime = (ulong)data.Properties["Timestamp_PerfTime"].Value; - ulong frequencyPerfTime = (ulong)data.Properties["Frequency_Perftime"].Value; - double currentTime = (double)timestampPerfTime / frequencyPerfTime; - - double timeDeltaSeconds = currentTime - _lastTime; - if (_lastTime == 0 || timeDeltaSeconds > 0.2) - { - double writeSpeed = writeRate * (1 / timeDeltaSeconds); - _sensorDiskWriteRate.Value = (float)writeSpeed; - - double readSpeed = readRate * (1 / timeDeltaSeconds); - _sensorDiskReadRate.Value = (float)readSpeed; - } - - if (_lastTime == 0 || timeDeltaSeconds > 0.2) - { - _lastTime = currentTime; - } - - perfData.Dispose(); } public override void Update() diff --git a/LibreHardwareMonitorLib/Hardware/Storage/StorageGroup.cs b/LibreHardwareMonitorLib/Hardware/Storage/StorageGroup.cs index c16109a..4098d66 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/StorageGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/StorageGroup.cs @@ -20,28 +20,27 @@ namespace LibreHardwareMonitor.Hardware.Storage return; //https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-diskdrive - var mosDisks = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive"); - ManagementObjectCollection queryCollection = mosDisks.Get(); // get the results - - foreach (ManagementBaseObject disk in queryCollection) + string query = "SELECT * FROM Win32_DiskDrive"; + using (var mosDisks = new ManagementObjectSearcher(query) {Options = {Timeout = TimeSpan.FromSeconds(10)}}) + using (ManagementObjectCollection queryCollection = mosDisks.Get()) { - string deviceId = (string)disk.Properties["DeviceId"].Value; // is \\.\PhysicalDrive0..n - uint idx = Convert.ToUInt32(disk.Properties["Index"].Value); - ulong diskSize = Convert.ToUInt64(disk.Properties["Size"].Value); - int scsi = Convert.ToInt32(disk.Properties["SCSIPort"].Value); - - if (deviceId != null) + foreach (ManagementBaseObject disk in queryCollection) { - var instance = AbstractStorage.CreateInstance(deviceId, idx, diskSize, scsi, settings); - if (instance != null) + string deviceId = (string)disk.Properties["DeviceId"].Value; // is \\.\PhysicalDrive0..n + uint idx = Convert.ToUInt32(disk.Properties["Index"].Value); + ulong diskSize = Convert.ToUInt64(disk.Properties["Size"].Value); + int scsi = Convert.ToInt32(disk.Properties["SCSIPort"].Value); + + if (deviceId != null) { - _hardware.Add(instance); + var instance = AbstractStorage.CreateInstance(deviceId, idx, diskSize, scsi, settings); + if (instance != null) + { + _hardware.Add(instance); + } } } } - - queryCollection.Dispose(); - mosDisks.Dispose(); } public IReadOnlyList Hardware => _hardware;