From 495855a002ddee957993525ec933fe2ab9dcee63 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Wed, 4 Jun 2025 18:20:29 +0100
Subject: [PATCH 01/61] allow MosCpuDetector to run on .NET 5+
---
src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs
index 8ab16535f6..fa47395bdc 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Linq;
using System.Management;
using BenchmarkDotNet.Extensions;
@@ -14,7 +15,8 @@ internal class MosCpuDetector : ICpuDetector
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
#endif
public bool IsApplicable() => OsDetector.IsWindows() &&
- RuntimeInformation.IsFullFramework &&
+ (RuntimeInformation.IsFullFramework ||
+ (RuntimeInformation.IsNetCore && Environment.Version.Major >= 5)) &&
!RuntimeInformation.IsMono;
#if NET6_0_OR_GREATER
From 3a75c1e8c92dce07c610eda611cf3c037d82dc5b Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Wed, 4 Jun 2025 20:03:53 +0100
Subject: [PATCH 02/61] Revert "allow MosCpuDetector to run on .NET 5+"
This reverts commit 495855a002ddee957993525ec933fe2ab9dcee63.
---
src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs
index fa47395bdc..8ab16535f6 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs
@@ -1,5 +1,4 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Linq;
using System.Management;
using BenchmarkDotNet.Extensions;
@@ -15,8 +14,7 @@ internal class MosCpuDetector : ICpuDetector
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
#endif
public bool IsApplicable() => OsDetector.IsWindows() &&
- (RuntimeInformation.IsFullFramework ||
- (RuntimeInformation.IsNetCore && Environment.Version.Major >= 5)) &&
+ RuntimeInformation.IsFullFramework &&
!RuntimeInformation.IsMono;
#if NET6_0_OR_GREATER
From 3fbf726c6f8f2edacedb353d542188fb5b245761 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Wed, 4 Jun 2025 22:15:30 +0100
Subject: [PATCH 03/61] add WmiLightCpu Detector
---
src/BenchmarkDotNet/BenchmarkDotNet.csproj | 1 +
.../Cpu/Windows/WindowsCpuDetector.cs | 3 +-
.../Cpu/Windows/WmiLightCpuDetector.cs | 70 +++++++++++++++++++
3 files changed, 73 insertions(+), 1 deletion(-)
create mode 100644 src/BenchmarkDotNet/Detectors/Cpu/Windows/WmiLightCpuDetector.cs
diff --git a/src/BenchmarkDotNet/BenchmarkDotNet.csproj b/src/BenchmarkDotNet/BenchmarkDotNet.csproj
index 52479a7fab..a22ff8f4e4 100644
--- a/src/BenchmarkDotNet/BenchmarkDotNet.csproj
+++ b/src/BenchmarkDotNet/BenchmarkDotNet.csproj
@@ -24,6 +24,7 @@
+
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WindowsCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WindowsCpuDetector.cs
index 9969a1bca0..8196ad2832 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WindowsCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WindowsCpuDetector.cs
@@ -1,3 +1,4 @@
namespace BenchmarkDotNet.Detectors.Cpu.Windows;
-internal class WindowsCpuDetector() : CpuDetector(new MosCpuDetector(), new WmicCpuDetector());
\ No newline at end of file
+internal class WindowsCpuDetector() : CpuDetector(new MosCpuDetector(),
+ new WmiLightCpuDetector(), new WmicCpuDetector());
\ No newline at end of file
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmiLightCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmiLightCpuDetector.cs
new file mode 100644
index 0000000000..3b522b673f
--- /dev/null
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmiLightCpuDetector.cs
@@ -0,0 +1,70 @@
+using BenchmarkDotNet.Extensions;
+using BenchmarkDotNet.Portability;
+
+using Perfolizer.Horology;
+using Perfolizer.Models;
+
+using System.Collections.Generic;
+
+using WmiLight;
+
+namespace BenchmarkDotNet.Detectors.Cpu.Windows
+{
+ internal class WmiLightCpuDetector : ICpuDetector
+ {
+
+#if NET6_0_OR_GREATER
+ [System.Runtime.Versioning.SupportedOSPlatform("windows")]
+#endif
+ public CpuInfo? Detect()
+ {
+ if (!IsApplicable()) return null;
+
+ HashSet processorModelNames = new HashSet();
+ int physicalCoreCount = 0;
+ int logicalCoreCount = 0;
+ int processorsCount = 0;
+ int sumMaxFrequency = 0;
+
+ using (WmiConnection connection = new WmiConnection())
+ {
+ foreach (WmiObject processor in connection.CreateQuery("SELECT * FROM Win32_Processor"))
+ {
+ string name = processor[WmicCpuInfoKeyNames.Name]?.ToString();
+ if (!string.IsNullOrEmpty(name))
+ {
+ processorModelNames.Add(name);
+ processorsCount++;
+ physicalCoreCount += (int)(uint)processor[WmicCpuInfoKeyNames.NumberOfCores];
+ logicalCoreCount += (int)(uint)processor[WmicCpuInfoKeyNames.NumberOfLogicalProcessors];
+ sumMaxFrequency = (int)(uint)processor[WmicCpuInfoKeyNames.MaxClockSpeed];
+ }
+ }
+ }
+
+ string processorName = processorModelNames.Count > 0 ? string.Join(", ", processorModelNames) : null;
+ Frequency? maxFrequency = sumMaxFrequency > 0 && processorsCount > 0
+ ? Frequency.FromMHz(sumMaxFrequency * 1.0 / processorsCount)
+ : null;
+
+ return new CpuInfo
+ {
+ ProcessorName = processorName,
+ PhysicalProcessorCount = processorsCount > 0 ? processorsCount : null,
+ PhysicalCoreCount = physicalCoreCount > 0 ? physicalCoreCount : null,
+ LogicalCoreCount = logicalCoreCount > 0 ? logicalCoreCount : null,
+ NominalFrequencyHz = maxFrequency?.Hertz.RoundToLong(),
+ MaxFrequencyHz = maxFrequency?.Hertz.RoundToLong()
+ };
+ }
+
+#if NET6_0_OR_GREATER
+ [System.Runtime.Versioning.SupportedOSPlatform("windows")]
+#endif
+ public bool IsApplicable()
+ {
+ return OsDetector.IsWindows() && (RuntimeInformation.IsNetCore ||
+ RuntimeInformation.IsFullFramework) && !RuntimeInformation.IsMono;
+ }
+ }
+}
From 5972f77faf4673f38195d16865f334afc44bd986 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Wed, 4 Jun 2025 22:16:10 +0100
Subject: [PATCH 04/61] Fix WmicCpuDetector being chosen if not available
---
src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuDetector.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuDetector.cs
index 3a92d180b8..d590a5a096 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuDetector.cs
@@ -13,7 +13,7 @@ internal class WmicCpuDetector : ICpuDetector
{
private const string DefaultWmicPath = @"C:\Windows\System32\wbem\WMIC.exe";
- public bool IsApplicable() => OsDetector.IsWindows();
+ public bool IsApplicable() => OsDetector.IsWindows() && File.Exists(DefaultWmicPath);
public CpuInfo? Detect()
{
From 7dc92b07f82b44b787f9f2f8270195aa23f090bc Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Thu, 5 Jun 2025 10:34:53 +0100
Subject: [PATCH 05/61] enable NativeAOT
---
.../Detectors/Cpu/Windows/WmiLightCpuDetector.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmiLightCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmiLightCpuDetector.cs
index 3b522b673f..4276c00599 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmiLightCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmiLightCpuDetector.cs
@@ -64,7 +64,7 @@ internal class WmiLightCpuDetector : ICpuDetector
public bool IsApplicable()
{
return OsDetector.IsWindows() && (RuntimeInformation.IsNetCore ||
- RuntimeInformation.IsFullFramework) && !RuntimeInformation.IsMono;
+ RuntimeInformation.IsFullFramework || RuntimeInformation.IsNativeAOT) && !RuntimeInformation.IsMono;
}
}
}
From fd5f0964a5a0e7f86111ba7f284da8ff445361b2 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Thu, 5 Jun 2025 10:48:05 +0100
Subject: [PATCH 06/61] simplify IsApplicable
---
.../Detectors/Cpu/Windows/WmiLightCpuDetector.cs | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmiLightCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmiLightCpuDetector.cs
index 4276c00599..95ce1cb247 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmiLightCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmiLightCpuDetector.cs
@@ -63,8 +63,7 @@ internal class WmiLightCpuDetector : ICpuDetector
#endif
public bool IsApplicable()
{
- return OsDetector.IsWindows() && (RuntimeInformation.IsNetCore ||
- RuntimeInformation.IsFullFramework || RuntimeInformation.IsNativeAOT) && !RuntimeInformation.IsMono;
+ return OsDetector.IsWindows() && !RuntimeInformation.IsMono;
}
}
}
From 9b9a5ebb68a2e99ee799c0b5fb43530ada5cb6e0 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Thu, 5 Jun 2025 18:20:31 +0100
Subject: [PATCH 07/61] Update spacing of SupportedOsPlatform attribute
Co-authored-by: Tim Cassell
---
.../Detectors/Cpu/Windows/WmiLightCpuDetector.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmiLightCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmiLightCpuDetector.cs
index 95ce1cb247..353b7ad6c5 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmiLightCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmiLightCpuDetector.cs
@@ -59,7 +59,7 @@ internal class WmiLightCpuDetector : ICpuDetector
}
#if NET6_0_OR_GREATER
- [System.Runtime.Versioning.SupportedOSPlatform("windows")]
+ [System.Runtime.Versioning.SupportedOSPlatform("windows")]
#endif
public bool IsApplicable()
{
From 589f23a2be0218c894e6ed3821e69a1b8411e0c0 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Sat, 7 Jun 2025 16:06:10 +0100
Subject: [PATCH 08/61] Revert "Fix WmicCpuDetector being chosen if not
available"
This reverts commit 5972f77faf4673f38195d16865f334afc44bd986.
---
src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuDetector.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuDetector.cs
index d590a5a096..3a92d180b8 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuDetector.cs
@@ -13,7 +13,7 @@ internal class WmicCpuDetector : ICpuDetector
{
private const string DefaultWmicPath = @"C:\Windows\System32\wbem\WMIC.exe";
- public bool IsApplicable() => OsDetector.IsWindows() && File.Exists(DefaultWmicPath);
+ public bool IsApplicable() => OsDetector.IsWindows();
public CpuInfo? Detect()
{
From a62fe32f22a4ee3d6cd8b4232427085466a59b64 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Sat, 7 Jun 2025 16:44:49 +0100
Subject: [PATCH 09/61] add WMIC deprecation remarks
---
src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuDetector.cs | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuDetector.cs
index 3a92d180b8..8c8f277915 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuDetector.cs
@@ -9,6 +9,8 @@ namespace BenchmarkDotNet.Detectors.Cpu.Windows;
/// CPU information from output of the `wmic cpu get Name, NumberOfCores, NumberOfLogicalProcessors /Format:List` command.
/// Windows only.
///
+/// WMIC is deprecated by Microsoft starting with Windows 10 21H1 (including Windows Server), and it is not known whether it still ships with Windows by default.
+/// WMIC may be removed in a future version of Windows. See
internal class WmicCpuDetector : ICpuDetector
{
private const string DefaultWmicPath = @"C:\Windows\System32\wbem\WMIC.exe";
From 56aa5ca1829318c5af98fd577d3879af48c6af36 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Sat, 7 Jun 2025 16:48:00 +0100
Subject: [PATCH 10/61] remove WmiLight code
---
src/BenchmarkDotNet/BenchmarkDotNet.csproj | 1 -
.../Cpu/Windows/WmiLightCpuDetector.cs | 69 -------------------
2 files changed, 70 deletions(-)
delete mode 100644 src/BenchmarkDotNet/Detectors/Cpu/Windows/WmiLightCpuDetector.cs
diff --git a/src/BenchmarkDotNet/BenchmarkDotNet.csproj b/src/BenchmarkDotNet/BenchmarkDotNet.csproj
index ef2d2cd148..7953a036ae 100644
--- a/src/BenchmarkDotNet/BenchmarkDotNet.csproj
+++ b/src/BenchmarkDotNet/BenchmarkDotNet.csproj
@@ -22,7 +22,6 @@
-
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmiLightCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmiLightCpuDetector.cs
deleted file mode 100644
index 353b7ad6c5..0000000000
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmiLightCpuDetector.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-using BenchmarkDotNet.Extensions;
-using BenchmarkDotNet.Portability;
-
-using Perfolizer.Horology;
-using Perfolizer.Models;
-
-using System.Collections.Generic;
-
-using WmiLight;
-
-namespace BenchmarkDotNet.Detectors.Cpu.Windows
-{
- internal class WmiLightCpuDetector : ICpuDetector
- {
-
-#if NET6_0_OR_GREATER
- [System.Runtime.Versioning.SupportedOSPlatform("windows")]
-#endif
- public CpuInfo? Detect()
- {
- if (!IsApplicable()) return null;
-
- HashSet processorModelNames = new HashSet();
- int physicalCoreCount = 0;
- int logicalCoreCount = 0;
- int processorsCount = 0;
- int sumMaxFrequency = 0;
-
- using (WmiConnection connection = new WmiConnection())
- {
- foreach (WmiObject processor in connection.CreateQuery("SELECT * FROM Win32_Processor"))
- {
- string name = processor[WmicCpuInfoKeyNames.Name]?.ToString();
- if (!string.IsNullOrEmpty(name))
- {
- processorModelNames.Add(name);
- processorsCount++;
- physicalCoreCount += (int)(uint)processor[WmicCpuInfoKeyNames.NumberOfCores];
- logicalCoreCount += (int)(uint)processor[WmicCpuInfoKeyNames.NumberOfLogicalProcessors];
- sumMaxFrequency = (int)(uint)processor[WmicCpuInfoKeyNames.MaxClockSpeed];
- }
- }
- }
-
- string processorName = processorModelNames.Count > 0 ? string.Join(", ", processorModelNames) : null;
- Frequency? maxFrequency = sumMaxFrequency > 0 && processorsCount > 0
- ? Frequency.FromMHz(sumMaxFrequency * 1.0 / processorsCount)
- : null;
-
- return new CpuInfo
- {
- ProcessorName = processorName,
- PhysicalProcessorCount = processorsCount > 0 ? processorsCount : null,
- PhysicalCoreCount = physicalCoreCount > 0 ? physicalCoreCount : null,
- LogicalCoreCount = logicalCoreCount > 0 ? logicalCoreCount : null,
- NominalFrequencyHz = maxFrequency?.Hertz.RoundToLong(),
- MaxFrequencyHz = maxFrequency?.Hertz.RoundToLong()
- };
- }
-
-#if NET6_0_OR_GREATER
- [System.Runtime.Versioning.SupportedOSPlatform("windows")]
-#endif
- public bool IsApplicable()
- {
- return OsDetector.IsWindows() && !RuntimeInformation.IsMono;
- }
- }
-}
From e7ad9453338900d98206cee28d8a294a3e05ecb7 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Sat, 7 Jun 2025 17:30:47 +0100
Subject: [PATCH 11/61] update WmiCpuInfoParser to return null if Processor
Name isn't detected
---
.../Detectors/Cpu/Windows/WmicCpuInfoParser.cs | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
index a139d39711..982023f563 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
@@ -12,7 +12,7 @@ internal static class WmicCpuInfoParser
/// Parses wmic output and returns
///
/// Output of `wmic cpu get Name, NumberOfCores, NumberOfLogicalProcessors /Format:List`
- internal static CpuInfo Parse(string? wmicOutput)
+ internal static CpuInfo? Parse(string? wmicOutput)
{
var processorModelNames = new HashSet();
int physicalCoreCount = 0;
@@ -52,6 +52,9 @@ internal static CpuInfo Parse(string? wmicOutput)
? Frequency.FromMHz(sumMaxFrequency / processorsCount)
: null;
+ if (string.IsNullOrEmpty(processorName) || processorName.ToLower().Equals("unknown processor"))
+ return null;
+
return new CpuInfo
{
ProcessorName = processorName,
From 29e2f96788e11ee730941ad805c884e2d9e486b3 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Sat, 7 Jun 2025 17:31:02 +0100
Subject: [PATCH 12/61] remove WmiLightCpuDetector reference from
WindowsCpuDetector
---
.../Detectors/Cpu/Windows/WindowsCpuDetector.cs | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WindowsCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WindowsCpuDetector.cs
index 8196ad2832..9969a1bca0 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WindowsCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WindowsCpuDetector.cs
@@ -1,4 +1,3 @@
namespace BenchmarkDotNet.Detectors.Cpu.Windows;
-internal class WindowsCpuDetector() : CpuDetector(new MosCpuDetector(),
- new WmiLightCpuDetector(), new WmicCpuDetector());
\ No newline at end of file
+internal class WindowsCpuDetector() : CpuDetector(new MosCpuDetector(), new WmicCpuDetector());
\ No newline at end of file
From f9a5c34657aebee54658e591a0c12b54e5276ba6 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Sat, 7 Jun 2025 17:37:48 +0100
Subject: [PATCH 13/61] Update WmicCpuInfoParser.cs
---
src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
index 982023f563..88d3ae9011 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
@@ -52,7 +52,7 @@ internal static class WmicCpuInfoParser
? Frequency.FromMHz(sumMaxFrequency / processorsCount)
: null;
- if (string.IsNullOrEmpty(processorName) || processorName.ToLower().Equals("unknown processor"))
+ if (string.IsNullOrEmpty(processorName))
return null;
return new CpuInfo
From c181db9d4ece571334033aeefb63d7860972e887 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Sat, 7 Jun 2025 17:42:57 +0100
Subject: [PATCH 14/61] check if wmicOutput is null or empty instead
---
.../Detectors/Cpu/Windows/WmicCpuInfoParser.cs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
index 88d3ae9011..9a691fb45a 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
@@ -14,6 +14,9 @@ internal static class WmicCpuInfoParser
/// Output of `wmic cpu get Name, NumberOfCores, NumberOfLogicalProcessors /Format:List`
internal static CpuInfo? Parse(string? wmicOutput)
{
+ if (string.IsNullOrEmpty(wmicOutput))
+ return null;
+
var processorModelNames = new HashSet();
int physicalCoreCount = 0;
int logicalCoreCount = 0;
@@ -52,9 +55,6 @@ internal static class WmicCpuInfoParser
? Frequency.FromMHz(sumMaxFrequency / processorsCount)
: null;
- if (string.IsNullOrEmpty(processorName))
- return null;
-
return new CpuInfo
{
ProcessorName = processorName,
From 18f44b8628cf02b3297d63d8295270c9e325bb58 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Sat, 7 Jun 2025 18:05:56 +0100
Subject: [PATCH 15/61] add PowershellWmiCpuDetector (parser still not
complete)
---
.../Cpu/Windows/PowershellWmiCpuDetector.cs | 46 +++++++++++++++++++
.../Cpu/Windows/PowershellWmiCpuInfoParser.cs | 13 ++++++
2 files changed, 59 insertions(+)
create mode 100644 src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
create mode 100644 src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
new file mode 100644
index 0000000000..0475338123
--- /dev/null
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
@@ -0,0 +1,46 @@
+using System;
+using System.IO;
+using System.Linq;
+using BenchmarkDotNet.Helpers;
+using Perfolizer.Models;
+
+namespace BenchmarkDotNet.Detectors.Cpu.Windows;
+
+///
+/// CPU information from output of the `wmic cpu get Name, NumberOfCores, NumberOfLogicalProcessors /Format:List` command.
+/// Windows only.
+///
+internal class PowershellWmiCpuDetector : ICpuDetector
+{
+ private readonly string windowsPowershellPath =
+ $"{Environment.SystemDirectory}{Path.DirectorySeparatorChar}WindowsPowerShell{Path.DirectorySeparatorChar}" +
+ $"v1.0{Path.DirectorySeparatorChar}powershell.exe";
+
+ public bool IsApplicable() => OsDetector.IsWindows();
+
+ public CpuInfo? Detect()
+ {
+ if (!IsApplicable()) return null;
+
+ string programFiles = Environment.Is64BitOperatingSystem ? Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) : Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
+
+ string powershell7PlusPath = $"{programFiles}{Path.DirectorySeparatorChar}Powershell{Path.DirectorySeparatorChar}";
+
+ if (Directory.Exists(powershell7PlusPath))
+ {
+ //Use .Last so that we get the newest major PowerShell version
+ string subDirectory = Directory.EnumerateDirectories(powershell7PlusPath, "^[a-zA-Z]", SearchOption.AllDirectories).Last();
+
+ powershell7PlusPath = $"{subDirectory}{Path.DirectorySeparatorChar}pwsh.exe";
+ }
+ const string argList = $"{WmicCpuInfoKeyNames.Name}, " +
+ $"{WmicCpuInfoKeyNames.NumberOfCores}, " +
+ $"{WmicCpuInfoKeyNames.NumberOfLogicalProcessors}, " +
+ $"{WmicCpuInfoKeyNames.MaxClockSpeed}";
+
+ // Optimistically, use Cross-platform new PowerShell when available but fallback to Windows PowerShell if not available.
+ string powershellPath = File.Exists(windowsPowershellPath) ? powershell7PlusPath : windowsPowershellPath;
+ string output = ProcessHelper.RunAndReadOutput(powershellPath, "Get-CimInstance Win32_Processor -Property " + argList);
+ return PowershellWmiCpuInfoParser.Parse(output);
+ }
+}
\ No newline at end of file
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
new file mode 100644
index 0000000000..add9188074
--- /dev/null
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+using BenchmarkDotNet.Extensions;
+using BenchmarkDotNet.Helpers;
+using Perfolizer.Horology;
+using Perfolizer.Models;
+
+namespace BenchmarkDotNet.Detectors.Cpu.Windows;
+
+internal static class PowershellWmiCpuInfoParser
+{
+ internal static CpuInfo? Parse(string? powershellWmiOutput)
+ {
+}}
\ No newline at end of file
From fa774626941848e3221daff940a15d27f7f09814 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Sat, 7 Jun 2025 21:33:54 +0100
Subject: [PATCH 16/61] return null if there's no version of powershell
installed
---
.../Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
index 0475338123..a7b445f9d5 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
@@ -40,6 +40,10 @@ internal class PowershellWmiCpuDetector : ICpuDetector
// Optimistically, use Cross-platform new PowerShell when available but fallback to Windows PowerShell if not available.
string powershellPath = File.Exists(windowsPowershellPath) ? powershell7PlusPath : windowsPowershellPath;
+
+ if (File.Exists(powershellPath) == false)
+ return null;
+
string output = ProcessHelper.RunAndReadOutput(powershellPath, "Get-CimInstance Win32_Processor -Property " + argList);
return PowershellWmiCpuInfoParser.Parse(output);
}
From 0f3dd87a6074bc176818df9a67942ab114bcaf48 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Sat, 7 Jun 2025 22:17:59 +0100
Subject: [PATCH 17/61] fix Powershell 7+ check
Co-authored-by: Tim Cassell
---
.../Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
index a7b445f9d5..5c550f502a 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
@@ -39,7 +39,7 @@ internal class PowershellWmiCpuDetector : ICpuDetector
$"{WmicCpuInfoKeyNames.MaxClockSpeed}";
// Optimistically, use Cross-platform new PowerShell when available but fallback to Windows PowerShell if not available.
- string powershellPath = File.Exists(windowsPowershellPath) ? powershell7PlusPath : windowsPowershellPath;
+ string powershellPath = File.Exists(powershell7PlusPath) ? powershell7PlusPath : windowsPowershellPath;
if (File.Exists(powershellPath) == false)
return null;
From b6d9fb47d59449139b8134d03177332029eebce7 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Sat, 7 Jun 2025 22:57:27 +0100
Subject: [PATCH 18/61] rework search statement given that regex isn't
supported
---
.../Cpu/Windows/PowershellWmiCpuDetector.cs | 34 +++++++++++++++++--
1 file changed, 31 insertions(+), 3 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
index 5c550f502a..8e377a8916 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.IO;
using System.Linq;
using BenchmarkDotNet.Helpers;
@@ -26,20 +27,47 @@ internal class PowershellWmiCpuDetector : ICpuDetector
string powershell7PlusPath = $"{programFiles}{Path.DirectorySeparatorChar}Powershell{Path.DirectorySeparatorChar}";
+ bool CheckForPowershell7Plus = true;
+
if (Directory.Exists(powershell7PlusPath))
{
//Use .Last so that we get the newest major PowerShell version
- string subDirectory = Directory.EnumerateDirectories(powershell7PlusPath, "^[a-zA-Z]", SearchOption.AllDirectories).Last();
+ string[] subDirectories = Directory.EnumerateDirectories(powershell7PlusPath, "*", SearchOption.AllDirectories)
+ .ToArray();
+
+ string? subDirectory = null;
+
+ if (subDirectories.Any())
+ {
+ subDirectory = subDirectories.Last();
+ }
- powershell7PlusPath = $"{subDirectory}{Path.DirectorySeparatorChar}pwsh.exe";
+ if (subDirectory is not null)
+ {
+ powershell7PlusPath = $"{subDirectory}{Path.DirectorySeparatorChar}pwsh.exe";
+ }
+ else
+ {
+ CheckForPowershell7Plus = false;
+ }
}
+
const string argList = $"{WmicCpuInfoKeyNames.Name}, " +
$"{WmicCpuInfoKeyNames.NumberOfCores}, " +
$"{WmicCpuInfoKeyNames.NumberOfLogicalProcessors}, " +
$"{WmicCpuInfoKeyNames.MaxClockSpeed}";
+ string powershellPath;
+
// Optimistically, use Cross-platform new PowerShell when available but fallback to Windows PowerShell if not available.
- string powershellPath = File.Exists(powershell7PlusPath) ? powershell7PlusPath : windowsPowershellPath;
+ if (CheckForPowershell7Plus)
+ {
+ powershellPath = File.Exists(powershell7PlusPath) ? powershell7PlusPath : windowsPowershellPath;
+ }
+ else
+ {
+ powershellPath = windowsPowershellPath;
+ }
if (File.Exists(powershellPath) == false)
return null;
From 8d0fbb9d68a0de82cee16105833c55c89cd69001 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Sat, 7 Jun 2025 23:03:11 +0100
Subject: [PATCH 19/61] add parser code
---
.../Cpu/Windows/PowershellWmiCpuInfoParser.cs | 55 ++++++++++++++++++-
1 file changed, 54 insertions(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
index add9188074..2db62ba6e0 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
@@ -10,4 +10,57 @@ internal static class PowershellWmiCpuInfoParser
{
internal static CpuInfo? Parse(string? powershellWmiOutput)
{
-}}
\ No newline at end of file
+ if (string.IsNullOrEmpty(powershellWmiOutput))
+ return null;
+
+ HashSet processorModelNames = new HashSet();
+
+ int physicalCoreCount = 0;
+ int logicalCoreCount = 0;
+ int processorsCount = 0;
+ var sumMaxFrequency = Frequency.Zero;
+
+
+ var processors = SectionsHelper.ParseSections(powershellWmiOutput, ':');
+ foreach (var processor in processors)
+ {
+ if (processor.TryGetValue(WmicCpuInfoKeyNames.NumberOfCores, out string numberOfCoresValue) &&
+ int.TryParse(numberOfCoresValue, out int numberOfCores) &&
+ numberOfCores > 0)
+ physicalCoreCount += numberOfCores;
+
+ if (processor.TryGetValue(WmicCpuInfoKeyNames.NumberOfLogicalProcessors, out string numberOfLogicalValue) &&
+ int.TryParse(numberOfLogicalValue, out int numberOfLogical) &&
+ numberOfLogical > 0)
+ logicalCoreCount += numberOfLogical;
+
+ if (processor.TryGetValue(WmicCpuInfoKeyNames.Name, out string name))
+ {
+ processorModelNames.Add(name);
+ processorsCount++;
+ }
+
+ if (processor.TryGetValue(WmicCpuInfoKeyNames.MaxClockSpeed, out string frequencyValue)
+ && int.TryParse(frequencyValue, out int frequency)
+ && frequency > 0)
+ {
+ sumMaxFrequency += frequency;
+ }
+ }
+
+ string? processorName = processorModelNames.Count > 0 ? string.Join(", ", processorModelNames) : null;
+ Frequency? maxFrequency = sumMaxFrequency > 0 && processorsCount > 0
+ ? Frequency.FromMHz(sumMaxFrequency / processorsCount)
+ : null;
+
+ return new CpuInfo
+ {
+ ProcessorName = processorName,
+ PhysicalProcessorCount = processorsCount > 0 ? processorsCount : null,
+ PhysicalCoreCount = physicalCoreCount > 0 ? physicalCoreCount : null,
+ LogicalCoreCount = logicalCoreCount > 0 ? logicalCoreCount : null,
+ NominalFrequencyHz = maxFrequency?.Hertz.RoundToLong(),
+ MaxFrequencyHz = maxFrequency?.Hertz.RoundToLong()
+ };
+ }
+}
\ No newline at end of file
From aca21d0c67f84ab3a9b628375fc059f0f188f734 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Sat, 7 Jun 2025 23:22:11 +0100
Subject: [PATCH 20/61] add PowershellWmiCpuDetector to WindowsCpuDetector
---
.../Detectors/Cpu/Windows/WindowsCpuDetector.cs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WindowsCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WindowsCpuDetector.cs
index 9969a1bca0..1de238b93f 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WindowsCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WindowsCpuDetector.cs
@@ -1,3 +1,4 @@
namespace BenchmarkDotNet.Detectors.Cpu.Windows;
-internal class WindowsCpuDetector() : CpuDetector(new MosCpuDetector(), new WmicCpuDetector());
\ No newline at end of file
+internal class WindowsCpuDetector() : CpuDetector(new MosCpuDetector(), new PowershellWmiCpuDetector(),
+ new WmicCpuDetector());
\ No newline at end of file
From 74c1b6c53874660013674b11e747eeb1f38ec05f Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Sat, 7 Jun 2025 23:23:58 +0100
Subject: [PATCH 21/61] rename variable to lower case
---
.../Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
index 8e377a8916..675694df36 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
@@ -27,7 +27,7 @@ internal class PowershellWmiCpuDetector : ICpuDetector
string powershell7PlusPath = $"{programFiles}{Path.DirectorySeparatorChar}Powershell{Path.DirectorySeparatorChar}";
- bool CheckForPowershell7Plus = true;
+ bool checkForPowershell7Plus = true;
if (Directory.Exists(powershell7PlusPath))
{
@@ -48,7 +48,7 @@ internal class PowershellWmiCpuDetector : ICpuDetector
}
else
{
- CheckForPowershell7Plus = false;
+ checkForPowershell7Plus = false;
}
}
@@ -60,7 +60,7 @@ internal class PowershellWmiCpuDetector : ICpuDetector
string powershellPath;
// Optimistically, use Cross-platform new PowerShell when available but fallback to Windows PowerShell if not available.
- if (CheckForPowershell7Plus)
+ if (checkForPowershell7Plus)
{
powershellPath = File.Exists(powershell7PlusPath) ? powershell7PlusPath : windowsPowershellPath;
}
From 52155fae9831f753051b5d6c16533447012b2b5e Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Sat, 7 Jun 2025 23:50:17 +0100
Subject: [PATCH 22/61] improve checking of latest powershell 7+ version
---
.../Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
index 675694df36..66cc23b710 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Text.RegularExpressions;
using BenchmarkDotNet.Helpers;
using Perfolizer.Models;
@@ -39,7 +40,10 @@ internal class PowershellWmiCpuDetector : ICpuDetector
if (subDirectories.Any())
{
- subDirectory = subDirectories.Last();
+ subDirectory = subDirectories.Where(x => Regex.IsMatch(x, "[0-9]"))
+ .Select(numStr => new { Value = numStr, Number = int.Parse(numStr) })
+ .OrderByDescending(x => x.Number)
+ .Select(x => x.Value).FirstOrDefault();
}
if (subDirectory is not null)
From d974b1a60b7058d8956eef1e2c52f1e8381bfdae Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Sat, 7 Jun 2025 23:50:41 +0100
Subject: [PATCH 23/61] use explicit typing
---
.../Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
index 2db62ba6e0..86902ca2e8 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
@@ -18,11 +18,11 @@ internal static class PowershellWmiCpuInfoParser
int physicalCoreCount = 0;
int logicalCoreCount = 0;
int processorsCount = 0;
- var sumMaxFrequency = Frequency.Zero;
+ Frequency sumMaxFrequency = Frequency.Zero;
- var processors = SectionsHelper.ParseSections(powershellWmiOutput, ':');
- foreach (var processor in processors)
+ List> processors = SectionsHelper.ParseSections(powershellWmiOutput, ':');
+ foreach (Dictionary processor in processors)
{
if (processor.TryGetValue(WmicCpuInfoKeyNames.NumberOfCores, out string numberOfCoresValue) &&
int.TryParse(numberOfCoresValue, out int numberOfCores) &&
From c7aa4e2ca92bd02e43783713a90ad5e9e868356f Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Sat, 7 Jun 2025 23:51:36 +0100
Subject: [PATCH 24/61] fix frequency addition issue
---
.../Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
index 86902ca2e8..6777090a69 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
@@ -44,7 +44,10 @@ internal static class PowershellWmiCpuInfoParser
&& int.TryParse(frequencyValue, out int frequency)
&& frequency > 0)
{
- sumMaxFrequency += frequency;
+ if (frequency > sumMaxFrequency)
+ {
+ sumMaxFrequency = frequency;
+ }
}
}
From fa4ea57341a52dffac134b99482986dd78f1ceda Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Sun, 8 Jun 2025 00:24:15 +0100
Subject: [PATCH 25/61] revert to how WMIC parser handles processor frequency
---
.../Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
index 6777090a69..86902ca2e8 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
@@ -44,10 +44,7 @@ internal static class PowershellWmiCpuInfoParser
&& int.TryParse(frequencyValue, out int frequency)
&& frequency > 0)
{
- if (frequency > sumMaxFrequency)
- {
- sumMaxFrequency = frequency;
- }
+ sumMaxFrequency += frequency;
}
}
From 3a8d884bec6167712171731ae2156c2e49e57708 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Sun, 8 Jun 2025 15:48:41 +0100
Subject: [PATCH 26/61] add string is null or empty check to WmiCpuDetector
---
.../Detectors/Cpu/Windows/WmicCpuDetector.cs | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuDetector.cs
index 8c8f277915..fe3434ae7f 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuDetector.cs
@@ -26,7 +26,11 @@ internal class WmicCpuDetector : ICpuDetector
$"{WmicCpuInfoKeyNames.NumberOfLogicalProcessors}, " +
$"{WmicCpuInfoKeyNames.MaxClockSpeed}";
string wmicPath = File.Exists(DefaultWmicPath) ? DefaultWmicPath : "wmic";
- string wmicOutput = ProcessHelper.RunAndReadOutput(wmicPath, $"cpu get {argList} /Format:List");
+ string? wmicOutput = ProcessHelper.RunAndReadOutput(wmicPath, $"cpu get {argList} /Format:List");
+
+ if (string.IsNullOrEmpty(wmicOutput))
+ return null;
+
return WmicCpuInfoParser.Parse(wmicOutput);
}
}
\ No newline at end of file
From b4ceb968b86412f998c94c5450b26634d04f39bb Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Sun, 8 Jun 2025 15:55:41 +0100
Subject: [PATCH 27/61] invoke Powershell as "PowerShell" if the file isn't
found
---
.../Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
index 66cc23b710..80fcc7fd7c 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
@@ -74,7 +74,7 @@ internal class PowershellWmiCpuDetector : ICpuDetector
}
if (File.Exists(powershellPath) == false)
- return null;
+ powershellPath = "PowerShell";
string output = ProcessHelper.RunAndReadOutput(powershellPath, "Get-CimInstance Win32_Processor -Property " + argList);
return PowershellWmiCpuInfoParser.Parse(output);
From bc3b8e7f5306e1e5a6021aa5e2deabb83013245f Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Sun, 8 Jun 2025 18:09:56 +0100
Subject: [PATCH 28/61] add nominal Frequency detection and improve max
frequency detection
---
.../Cpu/Windows/PowershellWmiCpuInfoParser.cs | 31 ++++++++++++++-----
.../Cpu/Windows/WmicCpuInfoParser.cs | 29 +++++++++++++----
2 files changed, 47 insertions(+), 13 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
index 86902ca2e8..27196fb5a5 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
@@ -18,8 +18,8 @@ internal static class PowershellWmiCpuInfoParser
int physicalCoreCount = 0;
int logicalCoreCount = 0;
int processorsCount = 0;
- Frequency sumMaxFrequency = Frequency.Zero;
-
+ Frequency maxFrequency = Frequency.Zero;
+ Frequency nominalFrequency = Frequency.Zero;
List> processors = SectionsHelper.ParseSections(powershellWmiOutput, ':');
foreach (Dictionary processor in processors)
@@ -44,23 +44,40 @@ internal static class PowershellWmiCpuInfoParser
&& int.TryParse(frequencyValue, out int frequency)
&& frequency > 0)
{
- sumMaxFrequency += frequency;
+ if (frequency > maxFrequency)
+ {
+ maxFrequency = frequency;
+ }
+
+ if (frequency < maxFrequency)
+ {
+ if (nominalFrequency != Frequency.Zero)
+ {
+ if (frequency < nominalFrequency)
+ nominalFrequency = frequency;
+ }
+ else
+ nominalFrequency = frequency;
+ }
}
}
string? processorName = processorModelNames.Count > 0 ? string.Join(", ", processorModelNames) : null;
- Frequency? maxFrequency = sumMaxFrequency > 0 && processorsCount > 0
- ? Frequency.FromMHz(sumMaxFrequency / processorsCount)
+ Frequency? maxFrequencyActual = maxFrequency > 0 && processorsCount > 0
+ ? Frequency.FromMHz(maxFrequency)
: null;
+ Frequency? nominalFrequencyActual = nominalFrequency > 0 && processorsCount > 0 ?
+ Frequency.FromMHz(nominalFrequency) : null;
+
return new CpuInfo
{
ProcessorName = processorName,
PhysicalProcessorCount = processorsCount > 0 ? processorsCount : null,
PhysicalCoreCount = physicalCoreCount > 0 ? physicalCoreCount : null,
LogicalCoreCount = logicalCoreCount > 0 ? logicalCoreCount : null,
- NominalFrequencyHz = maxFrequency?.Hertz.RoundToLong(),
- MaxFrequencyHz = maxFrequency?.Hertz.RoundToLong()
+ NominalFrequencyHz = nominalFrequencyActual?.Hertz.RoundToLong(),
+ MaxFrequencyHz = maxFrequencyActual?.Hertz.RoundToLong()
};
}
}
\ No newline at end of file
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
index 9a691fb45a..bea7c47c28 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
@@ -21,7 +21,8 @@ internal static class WmicCpuInfoParser
int physicalCoreCount = 0;
int logicalCoreCount = 0;
int processorsCount = 0;
- var sumMaxFrequency = Frequency.Zero;
+ Frequency maxFrequency = Frequency.Zero;
+ Frequency nominalFrequency = Frequency.Zero;
var processors = SectionsHelper.ParseSections(wmicOutput, '=');
foreach (var processor in processors)
@@ -46,23 +47,39 @@ internal static class WmicCpuInfoParser
&& int.TryParse(frequencyValue, out int frequency)
&& frequency > 0)
{
- sumMaxFrequency += frequency;
+ if (frequency > maxFrequency)
+ {
+ maxFrequency = frequency;
+ }
+
+ if (frequency < maxFrequency)
+ {
+ if (nominalFrequency != Frequency.Zero)
+ {
+ if (frequency < nominalFrequency)
+ nominalFrequency = frequency;
+ }
+ else
+ nominalFrequency = frequency;
+ }
}
}
string? processorName = processorModelNames.Count > 0 ? string.Join(", ", processorModelNames) : null;
- Frequency? maxFrequency = sumMaxFrequency > 0 && processorsCount > 0
- ? Frequency.FromMHz(sumMaxFrequency / processorsCount)
+ Frequency? maxFrequencyActual = maxFrequency > 0 && processorsCount > 0
+ ? Frequency.FromMHz(maxFrequency)
: null;
+ Frequency? nominalFrequencyActual = nominalFrequency > 0 && processorsCount > 0 ? Frequency.FromMHz(nominalFrequency) : null;
+
return new CpuInfo
{
ProcessorName = processorName,
PhysicalProcessorCount = processorsCount > 0 ? processorsCount : null,
PhysicalCoreCount = physicalCoreCount > 0 ? physicalCoreCount : null,
LogicalCoreCount = logicalCoreCount > 0 ? logicalCoreCount : null,
- NominalFrequencyHz = maxFrequency?.Hertz.RoundToLong(),
- MaxFrequencyHz = maxFrequency?.Hertz.RoundToLong()
+ NominalFrequencyHz = nominalFrequencyActual?.Hertz.RoundToLong(),
+ MaxFrequencyHz = maxFrequencyActual?.Hertz.RoundToLong()
};
}
}
\ No newline at end of file
From 06e82da3c2cf91f9b6a142bebb5c25b70d86b891 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Sun, 8 Jun 2025 18:38:15 +0100
Subject: [PATCH 29/61] fix issue with detecting latest Powershell
---
.../Cpu/Windows/PowershellWmiCpuDetector.cs | 13 ++++---------
1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
index 80fcc7fd7c..72fe3ef122 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
@@ -36,15 +36,10 @@ internal class PowershellWmiCpuDetector : ICpuDetector
string[] subDirectories = Directory.EnumerateDirectories(powershell7PlusPath, "*", SearchOption.AllDirectories)
.ToArray();
- string? subDirectory = null;
-
- if (subDirectories.Any())
- {
- subDirectory = subDirectories.Where(x => Regex.IsMatch(x, "[0-9]"))
- .Select(numStr => new { Value = numStr, Number = int.Parse(numStr) })
- .OrderByDescending(x => x.Number)
- .Select(x => x.Value).FirstOrDefault();
- }
+ string? subDirectory = subDirectories.Where(x => Regex.IsMatch(x, "[0-9]"))
+ .Select(x => x)
+ .OrderByDescending(x => x)
+ .FirstOrDefault();
if (subDirectory is not null)
{
From 32f0d57a4960677327b14cef4585fd189c98dbcf Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 10:34:11 +0100
Subject: [PATCH 30/61] update comment
---
.../Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
index 72fe3ef122..0b3e101974 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
@@ -32,10 +32,11 @@ internal class PowershellWmiCpuDetector : ICpuDetector
if (Directory.Exists(powershell7PlusPath))
{
- //Use .Last so that we get the newest major PowerShell version
string[] subDirectories = Directory.EnumerateDirectories(powershell7PlusPath, "*", SearchOption.AllDirectories)
.ToArray();
+ //Use the highest numbered directory for PowerShell so that we get the newest major PowerShell version
+ // Example version directories are 6, 7, and in the future 8.
string? subDirectory = subDirectories.Where(x => Regex.IsMatch(x, "[0-9]"))
.Select(x => x)
.OrderByDescending(x => x)
From ef2385b89621b709b72931131eb54a37d9786906 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 10:35:41 +0100
Subject: [PATCH 31/61] Update PowershellWmiCpuDetector.cs
---
.../Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
index 0b3e101974..e5a3d15d74 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
@@ -35,7 +35,7 @@ internal class PowershellWmiCpuDetector : ICpuDetector
string[] subDirectories = Directory.EnumerateDirectories(powershell7PlusPath, "*", SearchOption.AllDirectories)
.ToArray();
- //Use the highest numbered directory for PowerShell so that we get the newest major PowerShell version
+ //Use the highest number string directory for PowerShell so that we get the newest major PowerShell version
// Example version directories are 6, 7, and in the future 8.
string? subDirectory = subDirectories.Where(x => Regex.IsMatch(x, "[0-9]"))
.Select(x => x)
From fb87c983a7f8dfc935da47595e642bdf9c3543c5 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 10:47:41 +0100
Subject: [PATCH 32/61] refactor Powershell locating code to PowershellLocator
---
.../Cpu/Windows/PowershellWmiCpuDetector.cs | 50 ++---------
.../Helpers/PowerShellLocator.cs | 82 +++++++++++++++++++
2 files changed, 88 insertions(+), 44 deletions(-)
create mode 100644 src/BenchmarkDotNet/Helpers/PowerShellLocator.cs
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
index e5a3d15d74..028d16ebe6 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BenchmarkDotNet.Helpers;
using Perfolizer.Models;
@@ -20,59 +21,20 @@ internal class PowershellWmiCpuDetector : ICpuDetector
public bool IsApplicable() => OsDetector.IsWindows();
+ #if NET6_0_OR_GREATER
+ [SupportedOSPlatform("windows")]
+ #endif
public CpuInfo? Detect()
{
if (!IsApplicable()) return null;
- string programFiles = Environment.Is64BitOperatingSystem ? Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) : Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
-
- string powershell7PlusPath = $"{programFiles}{Path.DirectorySeparatorChar}Powershell{Path.DirectorySeparatorChar}";
-
- bool checkForPowershell7Plus = true;
-
- if (Directory.Exists(powershell7PlusPath))
- {
- string[] subDirectories = Directory.EnumerateDirectories(powershell7PlusPath, "*", SearchOption.AllDirectories)
- .ToArray();
-
- //Use the highest number string directory for PowerShell so that we get the newest major PowerShell version
- // Example version directories are 6, 7, and in the future 8.
- string? subDirectory = subDirectories.Where(x => Regex.IsMatch(x, "[0-9]"))
- .Select(x => x)
- .OrderByDescending(x => x)
- .FirstOrDefault();
-
- if (subDirectory is not null)
- {
- powershell7PlusPath = $"{subDirectory}{Path.DirectorySeparatorChar}pwsh.exe";
- }
- else
- {
- checkForPowershell7Plus = false;
- }
- }
-
const string argList = $"{WmicCpuInfoKeyNames.Name}, " +
$"{WmicCpuInfoKeyNames.NumberOfCores}, " +
$"{WmicCpuInfoKeyNames.NumberOfLogicalProcessors}, " +
$"{WmicCpuInfoKeyNames.MaxClockSpeed}";
- string powershellPath;
-
- // Optimistically, use Cross-platform new PowerShell when available but fallback to Windows PowerShell if not available.
- if (checkForPowershell7Plus)
- {
- powershellPath = File.Exists(powershell7PlusPath) ? powershell7PlusPath : windowsPowershellPath;
- }
- else
- {
- powershellPath = windowsPowershellPath;
- }
-
- if (File.Exists(powershellPath) == false)
- powershellPath = "PowerShell";
-
- string output = ProcessHelper.RunAndReadOutput(powershellPath, "Get-CimInstance Win32_Processor -Property " + argList);
+ string output = ProcessHelper.RunAndReadOutput(PowerShellLocator.LocateOnWindows() ?? "PowerShell",
+ "Get-CimInstance Win32_Processor -Property " + argList);
return PowershellWmiCpuInfoParser.Parse(output);
}
}
\ No newline at end of file
diff --git a/src/BenchmarkDotNet/Helpers/PowerShellLocator.cs b/src/BenchmarkDotNet/Helpers/PowerShellLocator.cs
new file mode 100644
index 0000000000..8f8a910980
--- /dev/null
+++ b/src/BenchmarkDotNet/Helpers/PowerShellLocator.cs
@@ -0,0 +1,82 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Runtime.Versioning;
+using System.Text.RegularExpressions;
+using BenchmarkDotNet.Detectors;
+
+namespace BenchmarkDotNet.Helpers
+{
+ ///
+ /// Locates PowerShell on a system, currently only supports on Windows.
+ ///
+ internal class PowerShellLocator
+ {
+ private static readonly string WindowsPowershellPath =
+ $"{Environment.SystemDirectory}{Path.DirectorySeparatorChar}WindowsPowerShell{Path.DirectorySeparatorChar}" +
+ $"v1.0{Path.DirectorySeparatorChar}powershell.exe";
+
+ #if NET6_0_OR_GREATER
+ [SupportedOSPlatform("windows")]
+ #endif
+ internal static string? LocateOnWindows()
+ {
+ if (OsDetector.IsWindows() == false)
+ return null;
+
+ string powershellPath;
+
+ try
+ {
+ string programFiles = Environment.Is64BitOperatingSystem
+ ? Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)
+ : Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
+
+ string powershell7PlusPath = $"{programFiles}{Path.DirectorySeparatorChar}Powershell{Path.DirectorySeparatorChar}";
+
+ bool checkForPowershell7Plus = true;
+
+ if (Directory.Exists(powershell7PlusPath))
+ {
+ string[] subDirectories = Directory.EnumerateDirectories(powershell7PlusPath, "*", SearchOption.AllDirectories)
+ .ToArray();
+
+ //Use the highest number string directory for PowerShell so that we get the newest major PowerShell version
+ // Example version directories are 6, 7, and in the future 8.
+ string? subDirectory = subDirectories.Where(x => Regex.IsMatch(x, "[0-9]"))
+ .Select(x => x)
+ .OrderByDescending(x => x)
+ .FirstOrDefault();
+
+ if (subDirectory is not null)
+ {
+ powershell7PlusPath = $"{subDirectory}{Path.DirectorySeparatorChar}pwsh.exe";
+ }
+ else
+ {
+ checkForPowershell7Plus = false;
+ }
+ }
+
+ // Optimistically, use Cross-platform new PowerShell when available but fallback to Windows PowerShell if not available.
+ if (checkForPowershell7Plus)
+ {
+ powershellPath = File.Exists(powershell7PlusPath) ? powershell7PlusPath : WindowsPowershellPath;
+ }
+ else
+ {
+ powershellPath = WindowsPowershellPath;
+ }
+
+ if (File.Exists(powershellPath) == false)
+ powershellPath = "PowerShell";
+ }
+ catch
+ {
+ powershellPath = "PowerShell";
+ }
+
+ return powershellPath;
+ }
+ }
+}
\ No newline at end of file
From 59b36be50382b32c91e90c83c4ba8ea9852b186a Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 11:03:37 +0100
Subject: [PATCH 33/61] simplify frequency checks
---
.../Cpu/Windows/PowershellWmiCpuInfoParser.cs | 34 ++++++-------------
.../Cpu/Windows/WmicCpuInfoParser.cs | 28 +++++----------
2 files changed, 19 insertions(+), 43 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
index 27196fb5a5..d92e74a0d9 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using BenchmarkDotNet.Extensions;
using BenchmarkDotNet.Helpers;
using Perfolizer.Horology;
@@ -17,9 +18,9 @@ internal static class PowershellWmiCpuInfoParser
int physicalCoreCount = 0;
int logicalCoreCount = 0;
- int processorsCount = 0;
- Frequency maxFrequency = Frequency.Zero;
- Frequency nominalFrequency = Frequency.Zero;
+ int processorCount = 0;
+ double maxFrequency = 0.0;
+ double nominalFrequency = 0.0;
List> processors = SectionsHelper.ParseSections(powershellWmiOutput, ':');
foreach (Dictionary processor in processors)
@@ -37,43 +38,30 @@ internal static class PowershellWmiCpuInfoParser
if (processor.TryGetValue(WmicCpuInfoKeyNames.Name, out string name))
{
processorModelNames.Add(name);
- processorsCount++;
+ processorCount++;
}
if (processor.TryGetValue(WmicCpuInfoKeyNames.MaxClockSpeed, out string frequencyValue)
&& int.TryParse(frequencyValue, out int frequency)
&& frequency > 0)
{
- if (frequency > maxFrequency)
- {
- maxFrequency = frequency;
- }
-
- if (frequency < maxFrequency)
- {
- if (nominalFrequency != Frequency.Zero)
- {
- if (frequency < nominalFrequency)
- nominalFrequency = frequency;
- }
- else
- nominalFrequency = frequency;
- }
+ nominalFrequency = nominalFrequency == 0 ? frequency : Math.Min(nominalFrequency, frequency);
+ maxFrequency = maxFrequency == 0 ? frequency : Math.Max(maxFrequency, nominalFrequency);
}
}
string? processorName = processorModelNames.Count > 0 ? string.Join(", ", processorModelNames) : null;
- Frequency? maxFrequencyActual = maxFrequency > 0 && processorsCount > 0
+ Frequency? maxFrequencyActual = maxFrequency > 0 && processorCount > 0
? Frequency.FromMHz(maxFrequency)
: null;
- Frequency? nominalFrequencyActual = nominalFrequency > 0 && processorsCount > 0 ?
+ Frequency? nominalFrequencyActual = nominalFrequency > 0 && processorCount > 0 ?
Frequency.FromMHz(nominalFrequency) : null;
return new CpuInfo
{
ProcessorName = processorName,
- PhysicalProcessorCount = processorsCount > 0 ? processorsCount : null,
+ PhysicalProcessorCount = processorCount > 0 ? processorCount : null,
PhysicalCoreCount = physicalCoreCount > 0 ? physicalCoreCount : null,
LogicalCoreCount = logicalCoreCount > 0 ? logicalCoreCount : null,
NominalFrequencyHz = nominalFrequencyActual?.Hertz.RoundToLong(),
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
index bea7c47c28..dde304df8f 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using BenchmarkDotNet.Extensions;
using BenchmarkDotNet.Helpers;
using Perfolizer.Horology;
@@ -17,14 +18,14 @@ internal static class WmicCpuInfoParser
if (string.IsNullOrEmpty(wmicOutput))
return null;
- var processorModelNames = new HashSet();
+ HashSet processorModelNames = new HashSet();
int physicalCoreCount = 0;
int logicalCoreCount = 0;
int processorsCount = 0;
- Frequency maxFrequency = Frequency.Zero;
- Frequency nominalFrequency = Frequency.Zero;
+ double maxFrequency = 0.0;
+ double nominalFrequency = 0.0;
- var processors = SectionsHelper.ParseSections(wmicOutput, '=');
+ List> processors = SectionsHelper.ParseSections(wmicOutput, '=');
foreach (var processor in processors)
{
if (processor.TryGetValue(WmicCpuInfoKeyNames.NumberOfCores, out string numberOfCoresValue) &&
@@ -47,21 +48,8 @@ internal static class WmicCpuInfoParser
&& int.TryParse(frequencyValue, out int frequency)
&& frequency > 0)
{
- if (frequency > maxFrequency)
- {
- maxFrequency = frequency;
- }
-
- if (frequency < maxFrequency)
- {
- if (nominalFrequency != Frequency.Zero)
- {
- if (frequency < nominalFrequency)
- nominalFrequency = frequency;
- }
- else
- nominalFrequency = frequency;
- }
+ nominalFrequency = nominalFrequency == 0 ? frequency : Math.Min(nominalFrequency, frequency);
+ maxFrequency = Math.Max(maxFrequency, frequency);
}
}
From be3fbfe86039d905cab940f4cd1c55ef03deb8df Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 11:15:14 +0100
Subject: [PATCH 34/61] Create PowershellWmiParserTests.cs
---
.../Detectors/Cpu/PowershellWmiParserTests.cs | 122 ++++++++++++++++++
1 file changed, 122 insertions(+)
create mode 100644 tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiParserTests.cs
diff --git a/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiParserTests.cs b/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiParserTests.cs
new file mode 100644
index 0000000000..edb8ec8c83
--- /dev/null
+++ b/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiParserTests.cs
@@ -0,0 +1,122 @@
+using BenchmarkDotNet.Detectors.Cpu.Windows;
+using Perfolizer.Models;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace BenchmarkDotNet.Tests.Detectors.Cpu;
+
+public class PowershellWmiParserTests(ITestOutputHelper output)
+{
+ private ITestOutputHelper Output { get; } = output;
+
+
+ [Fact]
+ public void EmptyTest()
+ {
+ CpuInfo? actual = PowershellWmiCpuInfoParser.Parse(string.Empty);
+ CpuInfo expected = new CpuInfo();
+ Output.AssertEqual(expected, actual);
+ }
+
+ [Fact]
+ public void MalformedTest()
+ {
+ CpuInfo? actual = PowershellWmiCpuInfoParser
+ .Parse("malformedkey=malformedvalue\n\nmalformedkey2=malformedvalue2");
+ CpuInfo expected = new CpuInfo();
+ Output.AssertEqual(expected, actual);
+ }
+
+ [Fact]
+ public void RealTwoProcessorEightCoresTest()
+ {
+ const string cpuInfo = @"
+
+MaxClockSpeed:2400
+Name:Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz
+NumberOfCores:8
+NumberOfLogicalProcessors:16
+
+
+MaxClockSpeed:2400
+Name:Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz
+NumberOfCores:8
+NumberOfLogicalProcessors:16
+
+";
+ CpuInfo? actual = PowershellWmiCpuInfoParser.Parse(cpuInfo);
+
+ CpuInfo expected = new CpuInfo
+ {
+ ProcessorName = "Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz",
+ PhysicalProcessorCount = 2,
+ PhysicalCoreCount = 16,
+ LogicalCoreCount = 32,
+ NominalFrequencyHz = 2_400_000_000,
+ MaxFrequencyHz = 2_400_000_000,
+ };
+
+ Output.AssertEqual(expected, actual);
+ }
+
+ [Fact]
+ public void RealTwoProcessorEightCoresWithWmicBugTest()
+ {
+ const string cpuInfo =
+ "\r\r\n" +
+ "\r\r\n" +
+ "MaxClockSpeed:3111\r\r\n" +
+ "Name:Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz\r\r\n" +
+ "NumberOfCores:8\r\r\n" +
+ "NumberOfLogicalProcessors:16\r\r\n" +
+ "\r\r\n" +
+ "\r\r\n" +
+ "MaxClockSpeed:3111\r\r\n" +
+ "Name:Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz\r\r\n" +
+ "NumberOfCores:8\r\r\n" +
+ "NumberOfLogicalProcessors:16\r\r\n" +
+ "\r\r\n" +
+ "\r\r\n" +
+ "\r\r\n";
+
+ CpuInfo? actual = PowershellWmiCpuInfoParser.Parse(cpuInfo);
+
+ CpuInfo expected = new CpuInfo
+ {
+ ProcessorName = "Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz",
+ PhysicalProcessorCount = 2,
+ PhysicalCoreCount = 16,
+ LogicalCoreCount = 32,
+ NominalFrequencyHz = 3_111_000_000,
+ MaxFrequencyHz = 3_111_000_000,
+ };
+
+ Output.AssertEqual(expected, actual);
+ }
+
+ [Fact]
+ public void RealOneProcessorFourCoresTest()
+ {
+ const string cpuInfo = @"
+
+MaxClockSpeed:2500
+Name:Intel(R) Core(TM) i7-4710MQ CPU @ 2.50GHz
+NumberOfCores:4
+NumberOfLogicalProcessors:8
+
+";
+
+ CpuInfo? actual = PowershellWmiCpuInfoParser.Parse(cpuInfo);
+ CpuInfo expected = new CpuInfo
+ {
+ ProcessorName = "Intel(R) Core(TM) i7-4710MQ CPU @ 2.50GHz",
+ PhysicalProcessorCount = 1,
+ PhysicalCoreCount = 4,
+ LogicalCoreCount = 8,
+ NominalFrequencyHz = 2_500_000_000,
+ MaxFrequencyHz = 2_500_000_000,
+ };
+
+ Output.AssertEqual(expected, actual);
+ }
+}
\ No newline at end of file
From 677bd1b9cdd1be92ee351f291b1d2193d7a32753 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 11:15:33 +0100
Subject: [PATCH 35/61] fix null being returned when object is expected.
---
.../Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs | 2 +-
src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
index d92e74a0d9..0c8c81036a 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
@@ -12,7 +12,7 @@ internal static class PowershellWmiCpuInfoParser
internal static CpuInfo? Parse(string? powershellWmiOutput)
{
if (string.IsNullOrEmpty(powershellWmiOutput))
- return null;
+ return CpuInfo.Unknown;
HashSet processorModelNames = new HashSet();
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
index dde304df8f..7279b79cf8 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
@@ -16,7 +16,7 @@ internal static class WmicCpuInfoParser
internal static CpuInfo? Parse(string? wmicOutput)
{
if (string.IsNullOrEmpty(wmicOutput))
- return null;
+ return CpuInfo.Unknown;
HashSet processorModelNames = new HashSet();
int physicalCoreCount = 0;
From c856ab05923c4bc1c30baabda323bb8c9b09126f Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 11:18:17 +0100
Subject: [PATCH 36/61] rename test
---
...hellWmiParserTests.cs => PowershellWmiCpuInfoParserTests.cs} | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
rename tests/BenchmarkDotNet.Tests/Detectors/Cpu/{PowershellWmiParserTests.cs => PowershellWmiCpuInfoParserTests.cs} (97%)
diff --git a/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiParserTests.cs b/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiCpuInfoParserTests.cs
similarity index 97%
rename from tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiParserTests.cs
rename to tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiCpuInfoParserTests.cs
index edb8ec8c83..435aedf76f 100644
--- a/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiParserTests.cs
+++ b/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiCpuInfoParserTests.cs
@@ -5,7 +5,7 @@
namespace BenchmarkDotNet.Tests.Detectors.Cpu;
-public class PowershellWmiParserTests(ITestOutputHelper output)
+public class PowershellWmiCpuInfoParserTests(ITestOutputHelper output)
{
private ITestOutputHelper Output { get; } = output;
From c54ee5189f9aa81da727034d0fcebff6d2625f25 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 19:54:38 +0100
Subject: [PATCH 37/61] simplify max frequency check
Co-authored-by: Tim Cassell
---
.../Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
index 0c8c81036a..7a0148cb16 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
@@ -46,7 +46,7 @@ internal static class PowershellWmiCpuInfoParser
&& frequency > 0)
{
nominalFrequency = nominalFrequency == 0 ? frequency : Math.Min(nominalFrequency, frequency);
- maxFrequency = maxFrequency == 0 ? frequency : Math.Max(maxFrequency, nominalFrequency);
+ maxFrequency = Math.Max(maxFrequency, frequency);
}
}
From 1d86ff251b4e6b4d1873cd595b5ee5cee4b78114 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 19:55:12 +0100
Subject: [PATCH 38/61] use """ for string in parser test
---
.../Cpu/PowershellWmiCpuInfoParserTests.cs | 21 ++++++++++---------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiCpuInfoParserTests.cs b/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiCpuInfoParserTests.cs
index 435aedf76f..17e09b1d7f 100644
--- a/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiCpuInfoParserTests.cs
+++ b/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiCpuInfoParserTests.cs
@@ -18,6 +18,7 @@ public void EmptyTest()
Output.AssertEqual(expected, actual);
}
+
[Fact]
public void MalformedTest()
{
@@ -30,20 +31,20 @@ public void MalformedTest()
[Fact]
public void RealTwoProcessorEightCoresTest()
{
- const string cpuInfo = @"
+ const string cpuInfo = """
-MaxClockSpeed:2400
-Name:Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz
-NumberOfCores:8
-NumberOfLogicalProcessors:16
+ MaxClockSpeed:2400
+ Name:Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz
+ NumberOfCores:8
+ NumberOfLogicalProcessors:16
-MaxClockSpeed:2400
-Name:Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz
-NumberOfCores:8
-NumberOfLogicalProcessors:16
+ MaxClockSpeed:2400
+ Name:Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz
+ NumberOfCores:8
+ NumberOfLogicalProcessors:16
-";
+ """;
CpuInfo? actual = PowershellWmiCpuInfoParser.Parse(cpuInfo);
CpuInfo expected = new CpuInfo
From 589566fbe191ca2823a1fdfb02b50060de8af36e Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 19:56:21 +0100
Subject: [PATCH 39/61] Update PowershellWmiCpuInfoParserTests.cs
---
.../Cpu/PowershellWmiCpuInfoParserTests.cs | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiCpuInfoParserTests.cs b/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiCpuInfoParserTests.cs
index 17e09b1d7f..d8c3539275 100644
--- a/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiCpuInfoParserTests.cs
+++ b/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiCpuInfoParserTests.cs
@@ -98,14 +98,13 @@ public void RealTwoProcessorEightCoresWithWmicBugTest()
[Fact]
public void RealOneProcessorFourCoresTest()
{
- const string cpuInfo = @"
-
-MaxClockSpeed:2500
-Name:Intel(R) Core(TM) i7-4710MQ CPU @ 2.50GHz
-NumberOfCores:4
-NumberOfLogicalProcessors:8
+ const string cpuInfo = """
-";
+ MaxClockSpeed:2500
+ Name:Intel(R) Core(TM) i7-4710MQ CPU @ 2.50GHz
+ NumberOfCores:4
+ NumberOfLogicalProcessors:8
+ """;
CpuInfo? actual = PowershellWmiCpuInfoParser.Parse(cpuInfo);
CpuInfo expected = new CpuInfo
From 3e3d67bd099b9fd1c392838ed5096b3ecf65ab1f Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 20:07:08 +0100
Subject: [PATCH 40/61] reduce indentation with """
---
.../Cpu/PowershellWmiCpuInfoParserTests.cs | 28 +++++++++----------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiCpuInfoParserTests.cs b/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiCpuInfoParserTests.cs
index d8c3539275..410019ba62 100644
--- a/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiCpuInfoParserTests.cs
+++ b/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiCpuInfoParserTests.cs
@@ -31,20 +31,20 @@ public void MalformedTest()
[Fact]
public void RealTwoProcessorEightCoresTest()
{
- const string cpuInfo = """
-
- MaxClockSpeed:2400
- Name:Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz
- NumberOfCores:8
- NumberOfLogicalProcessors:16
-
-
- MaxClockSpeed:2400
- Name:Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz
- NumberOfCores:8
- NumberOfLogicalProcessors:16
-
- """;
+ const string cpuInfo =
+ """
+ MaxClockSpeed:2400
+ Name:Intel(R) Xeon(R) CPU E5-2630 v3
+ NumberOfCores:8
+ NumberOfLogicalProcessors:16
+
+
+ MaxClockSpeed:2400
+ Name:Intel(R) Xeon(R) CPU E5-2630 v3
+ NumberOfCores:8
+ NumberOfLogicalProcessors:16
+
+ """;
CpuInfo? actual = PowershellWmiCpuInfoParser.Parse(cpuInfo);
CpuInfo expected = new CpuInfo
From 106cac1d055a072fd191ad0626e8858c2ba2b901 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 20:07:22 +0100
Subject: [PATCH 41/61] remove unnecessary test info
---
.../Detectors/Cpu/PowershellWmiCpuInfoParserTests.cs | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiCpuInfoParserTests.cs b/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiCpuInfoParserTests.cs
index 410019ba62..a781d70021 100644
--- a/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiCpuInfoParserTests.cs
+++ b/tests/BenchmarkDotNet.Tests/Detectors/Cpu/PowershellWmiCpuInfoParserTests.cs
@@ -49,7 +49,7 @@ public void RealTwoProcessorEightCoresTest()
CpuInfo expected = new CpuInfo
{
- ProcessorName = "Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz",
+ ProcessorName = "Intel(R) Xeon(R) CPU E5-2630 v3",
PhysicalProcessorCount = 2,
PhysicalCoreCount = 16,
LogicalCoreCount = 32,
@@ -67,13 +67,13 @@ public void RealTwoProcessorEightCoresWithWmicBugTest()
"\r\r\n" +
"\r\r\n" +
"MaxClockSpeed:3111\r\r\n" +
- "Name:Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz\r\r\n" +
+ "Name:Intel(R) Xeon(R) CPU E5-2687W 0\r\r\n" +
"NumberOfCores:8\r\r\n" +
"NumberOfLogicalProcessors:16\r\r\n" +
"\r\r\n" +
"\r\r\n" +
"MaxClockSpeed:3111\r\r\n" +
- "Name:Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz\r\r\n" +
+ "Name:Intel(R) Xeon(R) CPU E5-2687W 0\r\r\n" +
"NumberOfCores:8\r\r\n" +
"NumberOfLogicalProcessors:16\r\r\n" +
"\r\r\n" +
@@ -84,7 +84,7 @@ public void RealTwoProcessorEightCoresWithWmicBugTest()
CpuInfo expected = new CpuInfo
{
- ProcessorName = "Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz",
+ ProcessorName = "Intel(R) Xeon(R) CPU E5-2687W 0",
PhysicalProcessorCount = 2,
PhysicalCoreCount = 16,
LogicalCoreCount = 32,
@@ -101,7 +101,7 @@ public void RealOneProcessorFourCoresTest()
const string cpuInfo = """
MaxClockSpeed:2500
- Name:Intel(R) Core(TM) i7-4710MQ CPU @ 2.50GHz
+ Name:Intel(R) Core(TM) i7-4710MQ
NumberOfCores:4
NumberOfLogicalProcessors:8
""";
@@ -109,7 +109,7 @@ public void RealOneProcessorFourCoresTest()
CpuInfo? actual = PowershellWmiCpuInfoParser.Parse(cpuInfo);
CpuInfo expected = new CpuInfo
{
- ProcessorName = "Intel(R) Core(TM) i7-4710MQ CPU @ 2.50GHz",
+ ProcessorName = "Intel(R) Core(TM) i7-4710MQ",
PhysicalProcessorCount = 1,
PhysicalCoreCount = 4,
LogicalCoreCount = 8,
From 24135298baada62ce418363231464088a4d139dc Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 20:08:59 +0100
Subject: [PATCH 42/61] move string null check to caller
---
.../Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs | 4 ++++
.../Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs | 3 ---
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
index 028d16ebe6..788757bcdf 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
@@ -35,6 +35,10 @@ internal class PowershellWmiCpuDetector : ICpuDetector
string output = ProcessHelper.RunAndReadOutput(PowerShellLocator.LocateOnWindows() ?? "PowerShell",
"Get-CimInstance Win32_Processor -Property " + argList);
+
+ if (string.IsNullOrEmpty(output))
+ return CpuInfo.Unknown;
+
return PowershellWmiCpuInfoParser.Parse(output);
}
}
\ No newline at end of file
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
index 7a0148cb16..7f7b72cafe 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
@@ -11,9 +11,6 @@ internal static class PowershellWmiCpuInfoParser
{
internal static CpuInfo? Parse(string? powershellWmiOutput)
{
- if (string.IsNullOrEmpty(powershellWmiOutput))
- return CpuInfo.Unknown;
-
HashSet processorModelNames = new HashSet();
int physicalCoreCount = 0;
From 476cad558ee60f54ed44b92e8b48db2d7f121c9c Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 20:13:45 +0100
Subject: [PATCH 43/61] add nominal frequency support for MosCpuDetector
---
.../Detectors/Cpu/Windows/MosCpuDetector.cs | 22 +++++++++++++------
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs
index 8ab16535f6..39db4664fa 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Linq;
using System.Management;
using BenchmarkDotNet.Extensions;
@@ -28,7 +29,8 @@ public bool IsApplicable() => OsDetector.IsWindows() &&
int physicalCoreCount = 0;
int logicalCoreCount = 0;
int processorsCount = 0;
- int sumMaxFrequency = 0;
+ double maxFrequency = 0;
+ double nominalFrequency = 0;
using (var mosProcessor = new ManagementObjectSearcher("SELECT * FROM Win32_Processor"))
{
@@ -41,14 +43,20 @@ public bool IsApplicable() => OsDetector.IsWindows() &&
processorsCount++;
physicalCoreCount += (int)(uint)moProcessor[WmicCpuInfoKeyNames.NumberOfCores];
logicalCoreCount += (int)(uint)moProcessor[WmicCpuInfoKeyNames.NumberOfLogicalProcessors];
- sumMaxFrequency = (int)(uint)moProcessor[WmicCpuInfoKeyNames.MaxClockSpeed];
+ double tempMaxFrequency = (double)moProcessor[WmicCpuInfoKeyNames.MaxClockSpeed];
+
+ nominalFrequency = nominalFrequency == 0 ? maxFrequency : Math.Min(nominalFrequency, maxFrequency);
+ maxFrequency = Math.Max(maxFrequency, tempMaxFrequency);
}
}
}
string processorName = processorModelNames.Count > 0 ? string.Join(", ", processorModelNames) : null;
- Frequency? maxFrequency = sumMaxFrequency > 0 && processorsCount > 0
- ? Frequency.FromMHz(sumMaxFrequency * 1.0 / processorsCount)
+ Frequency? maxFrequencyActual = maxFrequency > 0 && processorsCount > 0
+ ? Frequency.FromMHz(maxFrequency)
+ : null;
+ Frequency? nominalFrequencyActual = nominalFrequency > 0 && processorsCount > 0
+ ? Frequency.FromMHz(nominalFrequency)
: null;
return new CpuInfo
@@ -57,8 +65,8 @@ public bool IsApplicable() => OsDetector.IsWindows() &&
PhysicalProcessorCount = processorsCount > 0 ? processorsCount : null,
PhysicalCoreCount = physicalCoreCount > 0 ? physicalCoreCount : null,
LogicalCoreCount = logicalCoreCount > 0 ? logicalCoreCount : null,
- NominalFrequencyHz = maxFrequency?.Hertz.RoundToLong(),
- MaxFrequencyHz = maxFrequency?.Hertz.RoundToLong()
+ NominalFrequencyHz = nominalFrequencyActual?.Hertz.RoundToLong(),
+ MaxFrequencyHz = maxFrequencyActual?.Hertz.RoundToLong()
};
}
}
\ No newline at end of file
From caf07ad817c7cb911c01d44f1a75b3bbef5f8c93 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 20:15:55 +0100
Subject: [PATCH 44/61] Update
src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
Co-authored-by: Tim Cassell
---
.../Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
index 788757bcdf..7f61c1b8fc 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs
@@ -37,7 +37,7 @@ internal class PowershellWmiCpuDetector : ICpuDetector
"Get-CimInstance Win32_Processor -Property " + argList);
if (string.IsNullOrEmpty(output))
- return CpuInfo.Unknown;
+ return null;
return PowershellWmiCpuInfoParser.Parse(output);
}
From 2e0867aeb8f970ccda82a126df53d15eac7456a7 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 20:16:47 +0100
Subject: [PATCH 45/61] remove nullability of parser
Co-authored-by: Tim Cassell
---
.../Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
index 7f7b72cafe..3e0a0f9ac7 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
@@ -9,7 +9,7 @@ namespace BenchmarkDotNet.Detectors.Cpu.Windows;
internal static class PowershellWmiCpuInfoParser
{
- internal static CpuInfo? Parse(string? powershellWmiOutput)
+ internal static CpuInfo Parse(string powershellWmiOutput)
{
HashSet processorModelNames = new HashSet();
From 30768de1af940dd1c3e48bbacffb15e1880ab9fd Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 20:22:19 +0100
Subject: [PATCH 46/61] check if tempMaxFrequency > 0 before assignment
Co-authored-by: Tim Cassell
---
src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs
index 39db4664fa..eeab5fa0fb 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs
@@ -45,7 +45,10 @@ public bool IsApplicable() => OsDetector.IsWindows() &&
logicalCoreCount += (int)(uint)moProcessor[WmicCpuInfoKeyNames.NumberOfLogicalProcessors];
double tempMaxFrequency = (double)moProcessor[WmicCpuInfoKeyNames.MaxClockSpeed];
- nominalFrequency = nominalFrequency == 0 ? maxFrequency : Math.Min(nominalFrequency, maxFrequency);
+ if (tempMaxFrequency > 0)
+ {
+ nominalFrequency = nominalFrequency == 0 ? tempMaxFrequency : Math.Min(nominalFrequency, tempMaxFrequency);
+ }
maxFrequency = Math.Max(maxFrequency, tempMaxFrequency);
}
}
From afb3220ffb03a50f16b7787375abde242534d4a1 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 20:35:08 +0100
Subject: [PATCH 47/61] remove nullability of WmicCpuInfoParser
---
.../Detectors/Cpu/Windows/WmicCpuInfoParser.cs | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
index 7279b79cf8..9d774326a4 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
@@ -13,11 +13,8 @@ internal static class WmicCpuInfoParser
/// Parses wmic output and returns
///
/// Output of `wmic cpu get Name, NumberOfCores, NumberOfLogicalProcessors /Format:List`
- internal static CpuInfo? Parse(string? wmicOutput)
+ internal static CpuInfo Parse(string wmicOutput)
{
- if (string.IsNullOrEmpty(wmicOutput))
- return CpuInfo.Unknown;
-
HashSet processorModelNames = new HashSet();
int physicalCoreCount = 0;
int logicalCoreCount = 0;
From b60ad9f093e4d5567adf4aeb4901d4a722001d0a Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 20:46:11 +0100
Subject: [PATCH 48/61] use file scoped namespace
---
.../Helpers/PowerShellLocator.cs | 103 +++++++++---------
1 file changed, 51 insertions(+), 52 deletions(-)
diff --git a/src/BenchmarkDotNet/Helpers/PowerShellLocator.cs b/src/BenchmarkDotNet/Helpers/PowerShellLocator.cs
index 8f8a910980..28b8e910f7 100644
--- a/src/BenchmarkDotNet/Helpers/PowerShellLocator.cs
+++ b/src/BenchmarkDotNet/Helpers/PowerShellLocator.cs
@@ -5,78 +5,77 @@
using System.Text.RegularExpressions;
using BenchmarkDotNet.Detectors;
-namespace BenchmarkDotNet.Helpers
+namespace BenchmarkDotNet.Helpers;
+
+///
+/// Locates PowerShell on a system, currently only supports on Windows.
+///
+internal class PowerShellLocator
{
- ///
- /// Locates PowerShell on a system, currently only supports on Windows.
- ///
- internal class PowerShellLocator
- {
- private static readonly string WindowsPowershellPath =
- $"{Environment.SystemDirectory}{Path.DirectorySeparatorChar}WindowsPowerShell{Path.DirectorySeparatorChar}" +
- $"v1.0{Path.DirectorySeparatorChar}powershell.exe";
+ private static readonly string WindowsPowershellPath =
+ $"{Environment.SystemDirectory}{Path.DirectorySeparatorChar}WindowsPowerShell{Path.DirectorySeparatorChar}" +
+ $"v1.0{Path.DirectorySeparatorChar}powershell.exe";
- #if NET6_0_OR_GREATER
+#if NET6_0_OR_GREATER
[SupportedOSPlatform("windows")]
- #endif
- internal static string? LocateOnWindows()
- {
- if (OsDetector.IsWindows() == false)
- return null;
+#endif
+ internal static string? LocateOnWindows()
+ {
+ if (OsDetector.IsWindows() == false)
+ return null;
- string powershellPath;
+ string powershellPath;
- try
- {
- string programFiles = Environment.Is64BitOperatingSystem
- ? Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)
- : Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
+ try
+ {
+ string programFiles = Environment.Is64BitOperatingSystem
+ ? Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)
+ : Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
- string powershell7PlusPath = $"{programFiles}{Path.DirectorySeparatorChar}Powershell{Path.DirectorySeparatorChar}";
+ string powershell7PlusPath = $"{programFiles}{Path.DirectorySeparatorChar}Powershell{Path.DirectorySeparatorChar}";
- bool checkForPowershell7Plus = true;
+ bool checkForPowershell7Plus = true;
- if (Directory.Exists(powershell7PlusPath))
- {
- string[] subDirectories = Directory.EnumerateDirectories(powershell7PlusPath, "*", SearchOption.AllDirectories)
- .ToArray();
+ if (Directory.Exists(powershell7PlusPath))
+ {
+ string[] subDirectories = Directory.EnumerateDirectories(powershell7PlusPath, "*", SearchOption.AllDirectories)
+ .ToArray();
- //Use the highest number string directory for PowerShell so that we get the newest major PowerShell version
- // Example version directories are 6, 7, and in the future 8.
- string? subDirectory = subDirectories.Where(x => Regex.IsMatch(x, "[0-9]"))
- .Select(x => x)
- .OrderByDescending(x => x)
- .FirstOrDefault();
+ //Use the highest number string directory for PowerShell so that we get the newest major PowerShell version
+ // Example version directories are 6, 7, and in the future 8.
+ string? subDirectory = subDirectories.Where(x => Regex.IsMatch(x, "[0-9]"))
+ .Select(x => x)
+ .OrderByDescending(x => x)
+ .FirstOrDefault();
- if (subDirectory is not null)
- {
- powershell7PlusPath = $"{subDirectory}{Path.DirectorySeparatorChar}pwsh.exe";
- }
- else
- {
- checkForPowershell7Plus = false;
- }
- }
-
- // Optimistically, use Cross-platform new PowerShell when available but fallback to Windows PowerShell if not available.
- if (checkForPowershell7Plus)
+ if (subDirectory is not null)
{
- powershellPath = File.Exists(powershell7PlusPath) ? powershell7PlusPath : WindowsPowershellPath;
+ powershell7PlusPath = $"{subDirectory}{Path.DirectorySeparatorChar}pwsh.exe";
}
else
{
- powershellPath = WindowsPowershellPath;
+ checkForPowershell7Plus = false;
}
+ }
- if (File.Exists(powershellPath) == false)
- powershellPath = "PowerShell";
+ // Optimistically, use Cross-platform new PowerShell when available but fallback to Windows PowerShell if not available.
+ if (checkForPowershell7Plus)
+ {
+ powershellPath = File.Exists(powershell7PlusPath) ? powershell7PlusPath : WindowsPowershellPath;
}
- catch
+ else
{
- powershellPath = "PowerShell";
+ powershellPath = WindowsPowershellPath;
}
- return powershellPath;
+ if (File.Exists(powershellPath) == false)
+ powershellPath = "PowerShell";
+ }
+ catch
+ {
+ powershellPath = "PowerShell";
}
+
+ return powershellPath;
}
}
\ No newline at end of file
From f300e4e3895e2851ddccd5581d96ca0ba78e1d8f Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 20:46:33 +0100
Subject: [PATCH 49/61] use double instead of int
---
.../Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs | 2 +-
src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
index 3e0a0f9ac7..d15b3eaa5f 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
@@ -39,7 +39,7 @@ internal static CpuInfo Parse(string powershellWmiOutput)
}
if (processor.TryGetValue(WmicCpuInfoKeyNames.MaxClockSpeed, out string frequencyValue)
- && int.TryParse(frequencyValue, out int frequency)
+ && double.TryParse(frequencyValue, out double frequency)
&& frequency > 0)
{
nominalFrequency = nominalFrequency == 0 ? frequency : Math.Min(nominalFrequency, frequency);
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
index 9d774326a4..295d76262e 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuInfoParser.cs
@@ -42,7 +42,7 @@ internal static CpuInfo Parse(string wmicOutput)
}
if (processor.TryGetValue(WmicCpuInfoKeyNames.MaxClockSpeed, out string frequencyValue)
- && int.TryParse(frequencyValue, out int frequency)
+ && double.TryParse(frequencyValue, out double frequency)
&& frequency > 0)
{
nominalFrequency = nominalFrequency == 0 ? frequency : Math.Min(nominalFrequency, frequency);
From 85d6f1b4cd0df94777afa68c991d1f5e399c7176 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 20:47:07 +0100
Subject: [PATCH 50/61] add null check to LinuxCpuDetector
---
.../Detectors/Cpu/Linux/LinuxCpuDetector.cs | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuDetector.cs
index 12c3b188d4..2ddad3dd41 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuDetector.cs
@@ -24,8 +24,12 @@ internal class LinuxCpuDetector : ICpuDetector
["LANGUAGE"] = "C"
};
- string cpuInfo = ProcessHelper.RunAndReadOutput("cat", "/proc/cpuinfo") ?? "";
- string lscpu = ProcessHelper.RunAndReadOutput("/bin/bash", "-c \"lscpu\"", environmentVariables: languageInvariantEnvironment);
+ string? cpuInfo = ProcessHelper.RunAndReadOutput("cat", "/proc/cpuinfo");
+ string? lscpu = ProcessHelper.RunAndReadOutput("/bin/bash", "-c \"lscpu\"", environmentVariables: languageInvariantEnvironment);
+
+ if (cpuInfo is null || lscpu is null)
+ return null;
+
return LinuxCpuInfoParser.Parse(cpuInfo, lscpu);
}
}
\ No newline at end of file
From f6d6eafd9417b92aff453db22b9e546934e0dde2 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 20:47:37 +0100
Subject: [PATCH 51/61] change nullability of LinuxCpuParser
---
src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs
index ed93999653..937dc98df6 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs
@@ -28,7 +28,7 @@ private static class Lscpu
/// Output of `cat /proc/cpuinfo`
/// Output of `lscpu`
- internal static CpuInfo Parse(string? cpuInfo, string? lscpu)
+ internal static CpuInfo Parse(string cpuInfo, string lscpu)
{
var processorModelNames = new HashSet();
var processorsToPhysicalCoreCount = new Dictionary();
From a5f715325ef788f57242b7c9404b6a5627007b17 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 21:01:17 +0100
Subject: [PATCH 52/61] update LinuxCpuInfoParser nominal and max frequency
detection
---
.../Detectors/Cpu/Linux/LinuxCpuInfoParser.cs | 47 ++++++++++++++-----
1 file changed, 35 insertions(+), 12 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs
index 937dc98df6..30a33cc0e8 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using BenchmarkDotNet.Extensions;
@@ -17,6 +18,7 @@ private static class ProcCpu
internal const string CpuCores = "cpu cores";
internal const string ModelName = "model name";
internal const string MaxFrequency = "max freq";
+ internal const string NominalFrequency = "cpu MHz";
}
private static class Lscpu
@@ -33,7 +35,8 @@ internal static CpuInfo Parse(string cpuInfo, string lscpu)
var processorModelNames = new HashSet();
var processorsToPhysicalCoreCount = new Dictionary();
int logicalCoreCount = 0;
- Frequency? maxFrequency = null;
+ double maxFrequency = 0.0;
+ double nominalFrequency = 0.0;
var logicalCores = SectionsHelper.ParseSections(cpuInfo, ':');
foreach (var logicalCore in logicalCores)
@@ -51,9 +54,17 @@ internal static CpuInfo Parse(string cpuInfo, string lscpu)
}
if (logicalCore.TryGetValue(ProcCpu.MaxFrequency, out string maxCpuFreqValue) &&
- Frequency.TryParseMHz(maxCpuFreqValue, out var maxCpuFreq))
+ double.TryParse(maxCpuFreqValue, out double maxCpuFreq)
+ && maxCpuFreq > 0)
{
- maxFrequency = maxCpuFreq;
+ maxFrequency = Math.Max(maxFrequency, maxCpuFreq);
+ }
+
+ if (logicalCore.TryGetValue(ProcCpu.NominalFrequency, out string nominalFreqValue) &&
+ double.TryParse(nominalFreqValue, out double nominalCpuFreq))
+ {
+ if (nominalCpuFreq > 0)
+ nominalFrequency = Math.Min(nominalFrequency, nominalCpuFreq);
}
}
@@ -71,7 +82,7 @@ internal static CpuInfo Parse(string cpuInfo, string lscpu)
if (name.EqualsWithIgnoreCase(Lscpu.MaxFrequency) &&
Frequency.TryParseMHz(value.Replace(',', '.'), out var maxFrequencyParsed)) // Example: `CPU max MHz: 3200,0000`
- maxFrequency = maxFrequencyParsed;
+ maxFrequency = Math.Max(maxFrequency, maxFrequencyParsed);
if (name.EqualsWithIgnoreCase(Lscpu.ModelName))
processorModelNames.Add(value);
@@ -81,22 +92,34 @@ internal static CpuInfo Parse(string cpuInfo, string lscpu)
coresPerSocket = coreCount;
}
}
-
- var nominalFrequency = processorModelNames
- .Select(ParseFrequencyFromBrandString)
- .WhereNotNull()
- .FirstOrDefault() ?? maxFrequency;
+
string processorName = processorModelNames.Count > 0 ? string.Join(", ", processorModelNames) : null;
int? physicalProcessorCount = processorsToPhysicalCoreCount.Count > 0 ? processorsToPhysicalCoreCount.Count : null;
int? physicalCoreCount = processorsToPhysicalCoreCount.Count > 0 ? processorsToPhysicalCoreCount.Values.Sum() : coresPerSocket;
+
+ Frequency? maxFrequencyActual = maxFrequency > 0 && physicalProcessorCount > 0
+ ? Frequency.FromMHz(maxFrequency)
+ : null;
+
+ Frequency? nominalFrequencyActual = nominalFrequency > 0 && physicalProcessorCount > 0 ? Frequency.FromMHz(nominalFrequency) : null;
+
+ if (nominalFrequencyActual is null)
+ {
+ bool nominalFrequencyInBrandString = processorModelNames.Any(x => ParseFrequencyFromBrandString(x) is not null);
+
+ if (nominalFrequencyInBrandString)
+ nominalFrequencyActual = processorModelNames.Select(x => ParseFrequencyFromBrandString(x))
+ .First(x => x is not null);
+ }
+
return new CpuInfo
{
ProcessorName = processorName,
PhysicalProcessorCount = physicalProcessorCount,
PhysicalCoreCount = physicalCoreCount,
LogicalCoreCount = logicalCoreCount > 0 ? logicalCoreCount : null,
- NominalFrequencyHz = nominalFrequency?.Hertz.RoundToLong(),
- MaxFrequencyHz = maxFrequency?.Hertz.RoundToLong()
+ NominalFrequencyHz = nominalFrequencyActual?.Hertz.RoundToLong(),
+ MaxFrequencyHz = maxFrequencyActual?.Hertz.RoundToLong()
};
}
From 65c45b9f8cb5ec84c03e984c187c5cffb560ddd3 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 21:01:33 +0100
Subject: [PATCH 53/61] Update LinuxCpuInfoParser.cs
---
src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs
index 30a33cc0e8..7f3def59f2 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs
@@ -92,7 +92,7 @@ internal static CpuInfo Parse(string cpuInfo, string lscpu)
coresPerSocket = coreCount;
}
}
-
+
string processorName = processorModelNames.Count > 0 ? string.Join(", ", processorModelNames) : null;
int? physicalProcessorCount = processorsToPhysicalCoreCount.Count > 0 ? processorsToPhysicalCoreCount.Count : null;
int? physicalCoreCount = processorsToPhysicalCoreCount.Count > 0 ? processorsToPhysicalCoreCount.Values.Sum() : coresPerSocket;
From d2741e1f77f43034e91f6d30c01b798c4e83f17a Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 21:03:50 +0100
Subject: [PATCH 54/61] fix nullability check
---
src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuDetector.cs | 6 +++---
.../Detectors/Cpu/Linux/LinuxCpuInfoParser.cs | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuDetector.cs
index 2ddad3dd41..44973b27e9 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuDetector.cs
@@ -24,10 +24,10 @@ internal class LinuxCpuDetector : ICpuDetector
["LANGUAGE"] = "C"
};
- string? cpuInfo = ProcessHelper.RunAndReadOutput("cat", "/proc/cpuinfo");
- string? lscpu = ProcessHelper.RunAndReadOutput("/bin/bash", "-c \"lscpu\"", environmentVariables: languageInvariantEnvironment);
+ string? cpuInfo = ProcessHelper.RunAndReadOutput("cat", "/proc/cpuinfo") ?? string.Empty;
+ string? lscpu = ProcessHelper.RunAndReadOutput("/bin/bash", "-c \"lscpu\"", environmentVariables: languageInvariantEnvironment) ?? string.Empty;
- if (cpuInfo is null || lscpu is null)
+ if (cpuInfo == string.Empty && lscpu == string.Empty)
return null;
return LinuxCpuInfoParser.Parse(cpuInfo, lscpu);
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs
index 7f3def59f2..bb248b3842 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs
@@ -69,7 +69,7 @@ internal static CpuInfo Parse(string cpuInfo, string lscpu)
}
int? coresPerSocket = null;
- if (lscpu != null)
+ if (string.IsNullOrEmpty(lscpu) == false)
{
var lscpuParts = lscpu.Split('\n')
.Where(line => line.Contains(':'))
From d1172a39fe331c3d730a98c23bb58a7150245028 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 21:42:06 +0100
Subject: [PATCH 55/61] simplify nominal frequency comparison
Co-authored-by: Tim Cassell
---
.../Detectors/Cpu/Linux/LinuxCpuInfoParser.cs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs
index bb248b3842..88124ca3cf 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs
@@ -61,10 +61,10 @@ internal static CpuInfo Parse(string cpuInfo, string lscpu)
}
if (logicalCore.TryGetValue(ProcCpu.NominalFrequency, out string nominalFreqValue) &&
- double.TryParse(nominalFreqValue, out double nominalCpuFreq))
+ double.TryParse(nominalFreqValue, out double nominalCpuFreq)
+ && nominalCpuFreq > 0)
{
- if (nominalCpuFreq > 0)
- nominalFrequency = Math.Min(nominalFrequency, nominalCpuFreq);
+ nominalFrequency = nominalFrequency == 0 ? nominalCpuFreq : Math.Min(nominalFrequency, nominalCpuFreq);
}
}
From 8307016f7b6dcb0cc05804cd3ad43f078a1a7d47 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 21:49:29 +0100
Subject: [PATCH 56/61] add null check to macOS
---
src/BenchmarkDotNet/Detectors/Cpu/macOS/MacOsCpuDetector.cs | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/macOS/MacOsCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/macOS/MacOsCpuDetector.cs
index f34de47ac9..2f540e82d3 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/macOS/MacOsCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/macOS/MacOsCpuDetector.cs
@@ -15,7 +15,11 @@ internal class MacOsCpuDetector : ICpuDetector
{
if (!IsApplicable()) return null;
- string sysctlOutput = ProcessHelper.RunAndReadOutput("sysctl", "-a");
+ string? sysctlOutput = ProcessHelper.RunAndReadOutput("sysctl", "-a");
+
+ if (sysctlOutput is null)
+ return null;
+
return SysctlCpuInfoParser.Parse(sysctlOutput);
}
}
\ No newline at end of file
From d5eb7e49c15c125cff6303ab387e9a38620a895e Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Mon, 9 Jun 2025 22:05:43 +0100
Subject: [PATCH 57/61] don't accept null string from detector
---
src/BenchmarkDotNet/Detectors/Cpu/macOS/SysctlCpuInfoParser.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/macOS/SysctlCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/macOS/SysctlCpuInfoParser.cs
index 58d1b53766..5cd4d11c8a 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/macOS/SysctlCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/macOS/SysctlCpuInfoParser.cs
@@ -20,7 +20,7 @@ private static class Sysctl
/// Output of `sysctl -a`
[SuppressMessage("ReSharper", "StringLiteralTypo")]
- internal static CpuInfo Parse(string? sysctlOutput)
+ internal static CpuInfo Parse(string sysctlOutput)
{
var sysctl = SectionsHelper.ParseSection(sysctlOutput, ':');
string processorName = sysctl.GetValueOrDefault(Sysctl.ProcessorName);
From b85d12d9ea13c6037461137ed63af364a6896928 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Wed, 11 Jun 2025 14:00:39 +0100
Subject: [PATCH 58/61] fix LinuxCpuInfo parser test issues and improve
robustness of Linux Cpu checks
---
.../Detectors/Cpu/Linux/LinuxCpuInfoParser.cs | 44 ++++++++++++++-----
.../Detectors/Cpu/LinuxCpuInfoParserTests.cs | 12 ++---
2 files changed, 39 insertions(+), 17 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs
index 88124ca3cf..7d79c3262f 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Linux/LinuxCpuInfoParser.cs
@@ -18,6 +18,7 @@ private static class ProcCpu
internal const string CpuCores = "cpu cores";
internal const string ModelName = "model name";
internal const string MaxFrequency = "max freq";
+ internal const string NominalFrequencyBackup = "nominal freq";
internal const string NominalFrequency = "cpu MHz";
}
@@ -54,17 +55,38 @@ internal static CpuInfo Parse(string cpuInfo, string lscpu)
}
if (logicalCore.TryGetValue(ProcCpu.MaxFrequency, out string maxCpuFreqValue) &&
- double.TryParse(maxCpuFreqValue, out double maxCpuFreq)
+ Frequency.TryParseMHz(maxCpuFreqValue.Replace(',', '.'), out Frequency maxCpuFreq)
&& maxCpuFreq > 0)
{
- maxFrequency = Math.Max(maxFrequency, maxCpuFreq);
+ maxFrequency = Math.Max(maxFrequency, maxCpuFreq.ToMHz());
}
- if (logicalCore.TryGetValue(ProcCpu.NominalFrequency, out string nominalFreqValue) &&
- double.TryParse(nominalFreqValue, out double nominalCpuFreq)
+ bool nominalFrequencyHasValue = logicalCore.TryGetValue(ProcCpu.NominalFrequency, out string nominalFreqValue);
+ bool nominalFrequencyBackupHasValue = logicalCore.TryGetValue(ProcCpu.NominalFrequencyBackup, out string nominalFreqBackupValue);
+
+ double nominalCpuFreq = 0.0;
+ double nominalCpuBackupFreq = 0.0;
+
+ if (nominalFrequencyHasValue &&
+ double.TryParse(nominalFreqValue, out nominalCpuFreq)
&& nominalCpuFreq > 0)
{
- nominalFrequency = nominalFrequency == 0 ? nominalCpuFreq : Math.Min(nominalFrequency, nominalCpuFreq);
+ nominalCpuFreq = nominalFrequency == 0 ? nominalCpuFreq : Math.Min(nominalFrequency, nominalCpuFreq);
+ }
+ if (nominalFrequencyBackupHasValue &&
+ double.TryParse(nominalFreqBackupValue, out nominalCpuBackupFreq)
+ && nominalCpuBackupFreq > 0)
+ {
+ nominalCpuBackupFreq = nominalFrequency == 0 ? nominalCpuBackupFreq : Math.Min(nominalFrequency, nominalCpuBackupFreq);
+ }
+
+ if (nominalFrequencyHasValue && nominalFrequencyBackupHasValue)
+ {
+ nominalFrequency = Math.Min(nominalCpuFreq, nominalCpuBackupFreq);
+ }
+ else
+ {
+ nominalFrequency = nominalCpuFreq == 0.0 ? nominalCpuBackupFreq : nominalCpuFreq;
}
}
@@ -81,8 +103,8 @@ internal static CpuInfo Parse(string cpuInfo, string lscpu)
string value = lscpuParts[i + 1].Trim();
if (name.EqualsWithIgnoreCase(Lscpu.MaxFrequency) &&
- Frequency.TryParseMHz(value.Replace(',', '.'), out var maxFrequencyParsed)) // Example: `CPU max MHz: 3200,0000`
- maxFrequency = Math.Max(maxFrequency, maxFrequencyParsed);
+ Frequency.TryParseMHz(value.Replace(',', '.'), out Frequency maxFrequencyParsed)) // Example: `CPU max MHz: 3200,0000`
+ maxFrequency = Math.Max(maxFrequency, maxFrequencyParsed.ToMHz());
if (name.EqualsWithIgnoreCase(Lscpu.ModelName))
processorModelNames.Add(value);
@@ -98,10 +120,10 @@ internal static CpuInfo Parse(string cpuInfo, string lscpu)
int? physicalCoreCount = processorsToPhysicalCoreCount.Count > 0 ? processorsToPhysicalCoreCount.Values.Sum() : coresPerSocket;
Frequency? maxFrequencyActual = maxFrequency > 0 && physicalProcessorCount > 0
- ? Frequency.FromMHz(maxFrequency)
- : null;
+ ? Frequency.FromMHz(maxFrequency) : null;
- Frequency? nominalFrequencyActual = nominalFrequency > 0 && physicalProcessorCount > 0 ? Frequency.FromMHz(nominalFrequency) : null;
+ Frequency? nominalFrequencyActual = nominalFrequency > 0 && physicalProcessorCount > 0
+ ? Frequency.FromMHz(nominalFrequency) : null;
if (nominalFrequencyActual is null)
{
@@ -130,7 +152,7 @@ internal static CpuInfo Parse(string cpuInfo, string lscpu)
if (matches.Count > 0 && matches[0].Groups.Count > 1)
{
string match = Regex.Matches(brandString, pattern, RegexOptions.IgnoreCase)[0].Groups[1].ToString();
- return Frequency.TryParseGHz(match, out var result) ? result : null;
+ return Frequency.TryParseGHz(match, out Frequency result) ? result : null;
}
return null;
diff --git a/tests/BenchmarkDotNet.Tests/Detectors/Cpu/LinuxCpuInfoParserTests.cs b/tests/BenchmarkDotNet.Tests/Detectors/Cpu/LinuxCpuInfoParserTests.cs
index d229a2b06d..0d4de2d9cc 100644
--- a/tests/BenchmarkDotNet.Tests/Detectors/Cpu/LinuxCpuInfoParserTests.cs
+++ b/tests/BenchmarkDotNet.Tests/Detectors/Cpu/LinuxCpuInfoParserTests.cs
@@ -22,7 +22,7 @@ public void EmptyTest()
[Fact]
public void MalformedTest()
{
- var actual = LinuxCpuInfoParser.Parse("malformedkey: malformedvalue\n\nmalformedkey2: malformedvalue2", null);
+ var actual = LinuxCpuInfoParser.Parse("malformedkey: malformedvalue\n\nmalformedkey2: malformedvalue2", string.Empty);
var expected = new CpuInfo();
Output.AssertEqual(expected, actual);
}
@@ -31,7 +31,7 @@ public void MalformedTest()
public void TwoProcessorWithDifferentCoresCountTest()
{
string cpuInfo = TestHelper.ReadTestFile("ProcCpuInfoProcessorWithDifferentCoresCount.txt");
- var actual = LinuxCpuInfoParser.Parse(cpuInfo, null);
+ var actual = LinuxCpuInfoParser.Parse(cpuInfo, string.Empty);
var expected = new CpuInfo
{
ProcessorName = "Unknown processor with 2 cores and hyper threading, Unknown processor with 4 cores",
@@ -49,7 +49,7 @@ public void TwoProcessorWithDifferentCoresCountTest()
public void RealOneProcessorTwoCoresTest()
{
string cpuInfo = TestHelper.ReadTestFile("ProcCpuInfoRealOneProcessorTwoCores.txt");
- var actual = LinuxCpuInfoParser.Parse(cpuInfo, null);
+ var actual = LinuxCpuInfoParser.Parse(cpuInfo, string.Empty);
var expected = new CpuInfo
{
ProcessorName = "Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz",
@@ -66,14 +66,14 @@ public void RealOneProcessorTwoCoresTest()
public void RealOneProcessorFourCoresTest()
{
string cpuInfo = TestHelper.ReadTestFile("ProcCpuInfoRealOneProcessorFourCores.txt");
- var actual = LinuxCpuInfoParser.Parse(cpuInfo, null);
+ var actual = LinuxCpuInfoParser.Parse(cpuInfo, string.Empty);
var expected = new CpuInfo
{
ProcessorName = "Intel(R) Core(TM) i7-4710MQ CPU @ 2.50GHz",
PhysicalProcessorCount = 1,
PhysicalCoreCount = 4,
LogicalCoreCount = 8,
- NominalFrequencyHz = 2_500_000_000,
+ NominalFrequencyHz = 2_494_300_000,
MaxFrequencyHz = 2_500_000_000
};
Output.AssertEqual(expected, actual);
@@ -154,7 +154,7 @@ r smca fsrm flush_l1d
PhysicalProcessorCount = 1,
PhysicalCoreCount = 16,
LogicalCoreCount = 32,
- NominalFrequencyHz = 5_881_000_000,
+ NominalFrequencyHz = 400_000_000,
MaxFrequencyHz = 5_881_000_000
};
Output.AssertEqual(expected, actual);
From 9609f83f60252c79e7c652c2ac78122367c422e5 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Wed, 11 Jun 2025 14:08:06 +0100
Subject: [PATCH 59/61] fix Powershell Wmi Parser parsing issues
---
.../Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs | 5 ++---
src/BenchmarkDotNet/Helpers/SectionsHelper.cs | 9 +++++++++
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
index d15b3eaa5f..15ad4d6c77 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuInfoParser.cs
@@ -19,7 +19,7 @@ internal static CpuInfo Parse(string powershellWmiOutput)
double maxFrequency = 0.0;
double nominalFrequency = 0.0;
- List> processors = SectionsHelper.ParseSections(powershellWmiOutput, ':');
+ List> processors = SectionsHelper.ParseSectionsForPowershellWmi(powershellWmiOutput, ':');
foreach (Dictionary processor in processors)
{
if (processor.TryGetValue(WmicCpuInfoKeyNames.NumberOfCores, out string numberOfCoresValue) &&
@@ -49,8 +49,7 @@ internal static CpuInfo Parse(string powershellWmiOutput)
string? processorName = processorModelNames.Count > 0 ? string.Join(", ", processorModelNames) : null;
Frequency? maxFrequencyActual = maxFrequency > 0 && processorCount > 0
- ? Frequency.FromMHz(maxFrequency)
- : null;
+ ? Frequency.FromMHz(maxFrequency) : null;
Frequency? nominalFrequencyActual = nominalFrequency > 0 && processorCount > 0 ?
Frequency.FromMHz(nominalFrequency) : null;
diff --git a/src/BenchmarkDotNet/Helpers/SectionsHelper.cs b/src/BenchmarkDotNet/Helpers/SectionsHelper.cs
index 15c54fd8f9..e16442d0fb 100644
--- a/src/BenchmarkDotNet/Helpers/SectionsHelper.cs
+++ b/src/BenchmarkDotNet/Helpers/SectionsHelper.cs
@@ -32,5 +32,14 @@ public static List> ParseSections(string? content, ch
.Where(s => s.Count > 0)
.ToList();
}
+
+ public static List> ParseSectionsForPowershellWmi(string? content, char separator)
+ {
+ return
+ Regex.Split(content ?? "", "(\r*\n)")
+ .Select(s => ParseSection(s, separator))
+ .Where(s => s.Count > 0)
+ .ToList();
+ }
}
}
\ No newline at end of file
From 8059686d971cf7b4e2b5be516bd5c3c749551af9 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Wed, 11 Jun 2025 14:19:09 +0100
Subject: [PATCH 60/61] fix .net framework cpu parsing issue
---
src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs
index eeab5fa0fb..b3bc6922cd 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs
@@ -43,11 +43,11 @@ public bool IsApplicable() => OsDetector.IsWindows() &&
processorsCount++;
physicalCoreCount += (int)(uint)moProcessor[WmicCpuInfoKeyNames.NumberOfCores];
logicalCoreCount += (int)(uint)moProcessor[WmicCpuInfoKeyNames.NumberOfLogicalProcessors];
- double tempMaxFrequency = (double)moProcessor[WmicCpuInfoKeyNames.MaxClockSpeed];
+ double tempMaxFrequency = Convert.ToDouble((uint)moProcessor[WmicCpuInfoKeyNames.MaxClockSpeed]);
if (tempMaxFrequency > 0)
{
- nominalFrequency = nominalFrequency == 0 ? tempMaxFrequency : Math.Min(nominalFrequency, tempMaxFrequency);
+ nominalFrequency = nominalFrequency == 0 ? Convert.ToDouble(tempMaxFrequency) : Math.Min(nominalFrequency, tempMaxFrequency);
}
maxFrequency = Math.Max(maxFrequency, tempMaxFrequency);
}
From 183f35325e8b59baf3a195a629767c5d1e27b094 Mon Sep 17 00:00:00 2001
From: Alastair Lundy <133523182+alastairlundy@users.noreply.github.com>
Date: Fri, 13 Jun 2025 23:50:12 +0100
Subject: [PATCH 61/61] do implicit conversion to double from uint
---
src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs b/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs
index b3bc6922cd..edc48ba25d 100644
--- a/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs
+++ b/src/BenchmarkDotNet/Detectors/Cpu/Windows/MosCpuDetector.cs
@@ -43,11 +43,11 @@ public bool IsApplicable() => OsDetector.IsWindows() &&
processorsCount++;
physicalCoreCount += (int)(uint)moProcessor[WmicCpuInfoKeyNames.NumberOfCores];
logicalCoreCount += (int)(uint)moProcessor[WmicCpuInfoKeyNames.NumberOfLogicalProcessors];
- double tempMaxFrequency = Convert.ToDouble((uint)moProcessor[WmicCpuInfoKeyNames.MaxClockSpeed]);
+ double tempMaxFrequency = (uint)moProcessor[WmicCpuInfoKeyNames.MaxClockSpeed];
if (tempMaxFrequency > 0)
{
- nominalFrequency = nominalFrequency == 0 ? Convert.ToDouble(tempMaxFrequency) : Math.Min(nominalFrequency, tempMaxFrequency);
+ nominalFrequency = nominalFrequency == 0 ? tempMaxFrequency : Math.Min(nominalFrequency, tempMaxFrequency);
}
maxFrequency = Math.Max(maxFrequency, tempMaxFrequency);
}