.NET 5.0环境下不使用WMI提取磁盘性能数据的可行方案
Great question! Since WMI is unavailable in your Jenkins environment (and installing .NET Framework isn't feasible), you have a couple of reliable options to fetch those disk performance metrics like ReadTimes, IdleTimes, WriteTimes, and AvgDiscSec per Read. Let's break them down:
1. Use .NET's Native PerformanceCounter Class
The System.Diagnostics.PerformanceCounter is a built-in .NET component that directly interfaces with Windows' Performance Counters—no WMI required. This is the most straightforward approach since it doesn't need external dependencies.
How It Works
Windows maintains a set of performance counters for physical disks, including exactly the metrics you need. You'll need to:
- Target the
PhysicalDiskcounter category. - Enumerate instances for each individual disk (skip
_Totalif you want per-disk data). - Fetch the relevant counters, and for cumulative metrics like
ReadTimes, calculate the difference between two sample points (since counters return raw cumulative values).
Code Example
using System; using System.Diagnostics; public class DiskMetricsCollector { public static void CollectDiskMetrics() { var diskCategory = new PerformanceCounterCategory("PhysicalDisk"); string[] diskInstances = diskCategory.GetInstanceNames(); foreach (var instance in diskInstances) { // Skip the total aggregate instance if you want per-disk data if (instance.Equals("_Total", StringComparison.OrdinalIgnoreCase)) continue; Console.WriteLine($"--- Disk Instance: {instance} ---"); // Get Avg. Disk sec/Read (direct value) using var avgReadSecCounter = new PerformanceCounter( "PhysicalDisk", "Avg. Disk sec/Read", instance, true); float avgReadSec = avgReadSecCounter.NextValue(); Console.WriteLine($"Avg. Disk sec per Read: {avgReadSec:F6}"); // Get cumulative Read Time (calculate difference over 1 second) using var readTimeRawCounter = new PerformanceCounter( "PhysicalDisk", "Disk Read Time", instance, true); long firstRawValue = readTimeRawCounter.RawValue; System.Threading.Thread.Sleep(1000); // Wait to capture a delta long secondRawValue = readTimeRawCounter.RawValue; long readTimeDelta = secondRawValue - firstRawValue; double readTimeSeconds = readTimeDelta / (double)Stopwatch.Frequency; Console.WriteLine($"Read Time (last 1s): {readTimeSeconds:F2}s"); // Repeat similar logic for other metrics: // - Disk Write Time (for WriteTimes) // - Disk Idle Time (for IdleTimes) } } }
Notes
- Make sure your Jenkins service account has Performance Monitor Users permissions to access these counters.
- Some counter names might vary slightly by Windows version—verify them using the Windows Performance Monitor tool (
perfmon.exe).
2. Use a Third-Party Library for PDH API Access
If you prefer a more streamlined or flexible approach, you can use a third-party NuGet library that wraps the Windows Performance Data Helper (PDH) API (the underlying system API that PerformanceCounter uses). One popular option is PdhSharp.
How to Use It
- Install the NuGet package:
Install-Package PdhSharp - Use the library to query counters directly:
using PdhSharp; using System; public class PdhDiskMetricsCollector { public static void CollectMetrics() { using var query = new PdhQuery(); // Add counters for a specific disk instance (replace "0 C:" with your disk instance) var avgReadCounter = query.AddCounter(@"\PhysicalDisk(0 C:)\Avg. Disk sec/Read"); var readTimeCounter = query.AddCounter(@"\PhysicalDisk(0 C:)\Disk Read Time"); // Collect initial data query.CollectQueryData(); float initialAvgRead = avgReadCounter.GetValue(); long initialReadTime = readTimeCounter.GetRawValue(); // Wait and collect again to calculate delta System.Threading.Thread.Sleep(1000); query.CollectQueryData(); float updatedAvgRead = avgReadCounter.GetValue(); long updatedReadTime = readTimeCounter.GetRawValue(); Console.WriteLine($"Avg. Disk sec per Read: {updatedAvgRead:F6}"); double readTimeSeconds = (updatedReadTime - initialReadTime) / (double)Stopwatch.Frequency; Console.WriteLine($"Read Time (last 1s): {readTimeSeconds:F2}s"); } }
Benefits
- More control over counter queries compared to the built-in
PerformanceCounter. - Avoids some edge cases with the .NET class, like instance name parsing issues.
3. Direct P/Invoke to Windows PDH API (Advanced)
If you want full control without any dependencies (even the built-in PerformanceCounter), you can directly call the PDH API via P/Invoke. This is more code-heavy but gives you complete flexibility over how you fetch and process metrics.
You'd need to declare P/Invoke methods for functions like PdhOpenQuery, PdhAddCounter, PdhCollectQueryData, and PdhGetFormattedCounterValue. While this works, it's generally overkill unless you have specific needs that the above methods don't meet.
内容的提问来源于stack exchange,提问作者Scorix

