Skip to content

Commit e83098e

Browse files
authored
chore: fix-regression-of-windows-cpudetector (#3127)
1 parent 5b96154 commit e83098e

6 files changed

Lines changed: 147 additions & 20 deletions

File tree

src/BenchmarkDotNet/Detectors/Cpu/Windows/WmiCpuInfoParser.cs renamed to src/BenchmarkDotNet/Detectors/Cpu/Windows/CpuInfoParser.cs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,27 @@
55

66
namespace BenchmarkDotNet.Detectors.Cpu.Windows;
77

8-
internal static class WmiCpuInfoParser
8+
internal static class CpuInfoParser
99
{
10+
/// <summary>
11+
/// Parses Get-CimInstance output and returns <see cref="CpuInfo"/>
12+
/// </summary>
13+
internal static CpuInfo ParseCimOutput(string cimOutput)
14+
{
15+
var processorSections = SectionsHelper.ParseSectionsForPowershellWmi(cimOutput, ':');
16+
return ParseCore(processorSections);
17+
}
18+
1019
/// <summary>
1120
/// Parses wmic output and returns <see cref="CpuInfo"/>
1221
/// </summary>
13-
/// <param name="wmiOutput">
14-
/// Output of `wmic cpu get Name, NumberOfCores, NumberOfLogicalProcessors /Format:List`
15-
/// or
16-
/// Output of `Get-CimInstance Win32_Processor -Property Name, NumberOfCores, NumberOfLogicalProcessors`
17-
/// </param>
18-
internal static CpuInfo Parse(string wmiOutput)
22+
internal static CpuInfo ParseWmicOutput(string wmicOutput)
23+
{
24+
var processorSections = SectionsHelper.ParseSections(wmicOutput, '=');
25+
return ParseCore(processorSections);
26+
}
27+
28+
private static CpuInfo ParseCore(List<Dictionary<string, string>> processors)
1929
{
2030
HashSet<string> processorModelNames = [];
2131
int physicalCoreCount = 0;
@@ -24,7 +34,6 @@ internal static CpuInfo Parse(string wmiOutput)
2434
double maxFrequency = 0.0;
2535
double nominalFrequency = 0.0;
2636

27-
List<Dictionary<string, string>> processors = SectionsHelper.ParseSections(wmiOutput, '=');
2837
foreach (var processor in processors)
2938
{
3039
if (processor.TryGetValue(WmiCpuInfoKeyNames.NumberOfCores, out var numberOfCoresValue) &&

src/BenchmarkDotNet/Detectors/Cpu/Windows/PowershellWmiCpuDetector.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
namespace BenchmarkDotNet.Detectors.Cpu.Windows;
77

88
/// <summary>
9-
/// CPU information from output of the `Get-CimInstance Win32_Processor -Property Name, NumberOfCores, NumberOfLogicalProcessors` command.
9+
/// CPU information from output of the `Get-CimInstance Win32_Processor -Property Name, NumberOfCores, NumberOfLogicalProcessors, MaxClockSpeed` command.
1010
/// Windows only.
1111
/// </summary>
1212
internal class PowershellWmiCpuDetector : ICpuDetector
@@ -24,11 +24,11 @@ internal class PowershellWmiCpuDetector : ICpuDetector
2424
$"{WmiCpuInfoKeyNames.MaxClockSpeed}";
2525

2626
string? output = ProcessHelper.RunAndReadOutput(PowerShellLocator.LocateOnWindows() ?? "PowerShell",
27-
"Get-CimInstance Win32_Processor -Property " + argList);
27+
$"Get-CimInstance Win32_Processor -Property {argList} | Format-List {argList}");
2828

2929
if (output.IsBlank())
3030
return null;
3131

32-
return WmiCpuInfoParser.Parse(output);
32+
return CpuInfoParser.ParseCimOutput(output);
3333
}
3434
}

src/BenchmarkDotNet/Detectors/Cpu/Windows/WmicCpuDetector.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
namespace BenchmarkDotNet.Detectors.Cpu.Windows;
66

77
/// <summary>
8-
/// CPU information from output of the `wmic cpu get Name, NumberOfCores, NumberOfLogicalProcessors /Format:List` command.
8+
/// CPU information from output of the `wmic cpu get Name, NumberOfCores, NumberOfLogicalProcessors, MaxClockSpeed /Format:List` command.
99
/// Windows only.
1010
/// </summary>
1111
/// <remarks>
@@ -34,6 +34,6 @@ internal class WmicCpuDetector : ICpuDetector
3434
if (wmicOutput.IsBlank())
3535
return null;
3636

37-
return WmiCpuInfoParser.Parse(wmicOutput);
37+
return CpuInfoParser.ParseWmicOutput(wmicOutput);
3838
}
3939
}

tests/BenchmarkDotNet.Tests/BenchmarkDotNet.Tests.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@
5858
</None>
5959
</ItemGroup>
6060
<ItemGroup>
61-
<Folder Include="Detectors\" />
6261
<Folder Include="Perfonar\VerifiedFiles\" />
6362
</ItemGroup>
6463
<Import Project="..\..\build\common.targets" />
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
using BenchmarkDotNet.Detectors.Cpu.Windows;
2+
using Perfolizer.Models;
3+
4+
namespace BenchmarkDotNet.Tests.Detectors.Cpu;
5+
6+
public class CimCpuInfoParserTests_Cim(ITestOutputHelper output)
7+
{
8+
private ITestOutputHelper Output { get; } = output;
9+
10+
11+
[Fact]
12+
public void EmptyTest()
13+
{
14+
CpuInfo? actual = CpuInfoParser.ParseCimOutput(string.Empty);
15+
CpuInfo expected = new CpuInfo();
16+
Output.AssertEqual(expected, actual);
17+
}
18+
19+
20+
[Fact]
21+
public void MalformedTest()
22+
{
23+
CpuInfo? actual = CpuInfoParser.ParseCimOutput("malformedkey=malformedvalue\n\nmalformedkey2=malformedvalue2");
24+
CpuInfo expected = new CpuInfo();
25+
Output.AssertEqual(expected, actual);
26+
}
27+
28+
[Fact]
29+
public void RealTwoProcessorEightCoresTest()
30+
{
31+
const string cpuInfo =
32+
"""
33+
MaxClockSpeed:2400
34+
Name:Intel(R) Xeon(R) CPU E5-2630 v3
35+
NumberOfCores:8
36+
NumberOfLogicalProcessors:16
37+
38+
39+
MaxClockSpeed:2400
40+
Name:Intel(R) Xeon(R) CPU E5-2630 v3
41+
NumberOfCores:8
42+
NumberOfLogicalProcessors:16
43+
44+
""";
45+
CpuInfo? actual = CpuInfoParser.ParseCimOutput(cpuInfo);
46+
47+
CpuInfo expected = new CpuInfo
48+
{
49+
ProcessorName = "Intel(R) Xeon(R) CPU E5-2630 v3",
50+
PhysicalProcessorCount = 2,
51+
PhysicalCoreCount = 16,
52+
LogicalCoreCount = 32,
53+
NominalFrequencyHz = 2_400_000_000,
54+
MaxFrequencyHz = 2_400_000_000,
55+
};
56+
57+
Output.AssertEqual(expected, actual);
58+
}
59+
60+
[Fact]
61+
public void RealTwoProcessorEightCoresWithWmicBugTest()
62+
{
63+
const string cpuInfo =
64+
"\r\r\n" +
65+
"\r\r\n" +
66+
"MaxClockSpeed:3111\r\r\n" +
67+
"Name:Intel(R) Xeon(R) CPU E5-2687W 0\r\r\n" +
68+
"NumberOfCores:8\r\r\n" +
69+
"NumberOfLogicalProcessors:16\r\r\n" +
70+
"\r\r\n" +
71+
"\r\r\n" +
72+
"MaxClockSpeed:3111\r\r\n" +
73+
"Name:Intel(R) Xeon(R) CPU E5-2687W 0\r\r\n" +
74+
"NumberOfCores:8\r\r\n" +
75+
"NumberOfLogicalProcessors:16\r\r\n" +
76+
"\r\r\n" +
77+
"\r\r\n" +
78+
"\r\r\n";
79+
80+
CpuInfo? actual = CpuInfoParser.ParseCimOutput(cpuInfo);
81+
82+
CpuInfo expected = new CpuInfo
83+
{
84+
ProcessorName = "Intel(R) Xeon(R) CPU E5-2687W 0",
85+
PhysicalProcessorCount = 2,
86+
PhysicalCoreCount = 16,
87+
LogicalCoreCount = 32,
88+
NominalFrequencyHz = 3_111_000_000,
89+
MaxFrequencyHz = 3_111_000_000,
90+
};
91+
92+
Output.AssertEqual(expected, actual);
93+
}
94+
95+
[Fact]
96+
public void RealOneProcessorFourCoresTest()
97+
{
98+
const string cpuInfo = """
99+
100+
MaxClockSpeed:2500
101+
Name:Intel(R) Core(TM) i7-4710MQ
102+
NumberOfCores:4
103+
NumberOfLogicalProcessors:8
104+
""";
105+
106+
CpuInfo? actual = CpuInfoParser.ParseCimOutput(cpuInfo);
107+
CpuInfo expected = new CpuInfo
108+
{
109+
ProcessorName = "Intel(R) Core(TM) i7-4710MQ",
110+
PhysicalProcessorCount = 1,
111+
PhysicalCoreCount = 4,
112+
LogicalCoreCount = 8,
113+
NominalFrequencyHz = 2_500_000_000,
114+
MaxFrequencyHz = 2_500_000_000,
115+
};
116+
117+
Output.AssertEqual(expected, actual);
118+
}
119+
}

tests/BenchmarkDotNet.Tests/Detectors/Cpu/WmiCpuInfoParserTests.cs renamed to tests/BenchmarkDotNet.Tests/Detectors/Cpu/CpuInfoParserTests_Wmic.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,22 @@
44
namespace BenchmarkDotNet.Tests.Detectors.Cpu;
55

66
// ReSharper disable StringLiteralTypo
7-
public class WmiCpuInfoParserTests(ITestOutputHelper output)
7+
public class WmiCpuInfoParserTests_Wmic(ITestOutputHelper output)
88
{
99
private ITestOutputHelper Output { get; } = output;
1010

1111
[Fact]
1212
public void EmptyTest()
1313
{
14-
var actual = WmiCpuInfoParser.Parse(string.Empty);
14+
var actual = CpuInfoParser.ParseWmicOutput(string.Empty);
1515
var expected = new CpuInfo();
1616
Output.AssertEqual(expected, actual);
1717
}
1818

1919
[Fact]
2020
public void MalformedTest()
2121
{
22-
var actual = WmiCpuInfoParser.Parse("malformedkey=malformedvalue\n\nmalformedkey2=malformedvalue2");
22+
var actual = CpuInfoParser.ParseWmicOutput("malformedkey=malformedvalue\n\nmalformedkey2=malformedvalue2");
2323
var expected = new CpuInfo();
2424
Output.AssertEqual(expected, actual);
2525
}
@@ -41,7 +41,7 @@ public void RealTwoProcessorEightCoresTest()
4141
NumberOfLogicalProcessors=16
4242
4343
""";
44-
var actual = WmiCpuInfoParser.Parse(cpuInfo);
44+
var actual = CpuInfoParser.ParseWmicOutput(cpuInfo);
4545
var expected = new CpuInfo
4646
{
4747
ProcessorName = "Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz",
@@ -73,7 +73,7 @@ public void RealTwoProcessorEightCoresWithWmicBugTest()
7373
"\r\r\n" +
7474
"\r\r\n" +
7575
"\r\r\n";
76-
var actual = WmiCpuInfoParser.Parse(cpuInfo);
76+
var actual = CpuInfoParser.ParseWmicOutput(cpuInfo);
7777
var expected = new CpuInfo
7878
{
7979
ProcessorName = "Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz",
@@ -98,7 +98,7 @@ public void RealOneProcessorFourCoresTest()
9898
9999
""";
100100

101-
var actual = WmiCpuInfoParser.Parse(cpuInfo);
101+
var actual = CpuInfoParser.ParseWmicOutput(cpuInfo);
102102
var expected = new CpuInfo
103103
{
104104
ProcessorName = "Intel(R) Core(TM) i7-4710MQ CPU @ 2.50GHz",

0 commit comments

Comments
 (0)