Skip to content

Commit 7590b9d

Browse files
Rudra Pratap SInghCopilot
andcommitted
fix: DiskSpdMetricsParser - handle v2.2.0 extended CPU table format
DiskSpd v2.2.0 changed the CPU section header from: Group | CPU | Usage | User | Kernel | Idle to: Socket | Node | Group | Core | CPU | Usage | User | Kernel | Idle The existing Preprocess() logic searched for 'Group' and prefixed a 'CPU' section title, but the extra 'Socket | Node' prefix caused Sectionize() to key the section as 'Socket | Node | CPU' instead of 'CPU', resulting in a KeyNotFoundException at parse time. Fix: detect the v2.2.0 extended header and normalise it to the legacy Group | CPU format before sectionizing, stripping the Socket/Node/Core columns from each data row via regex. Also adds a unit test and example output file based on real v2.2.0 output captured from a Gen11 DiskSpd run (SCHIELC41ABD017). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent ea14f0a commit 7590b9d

3 files changed

Lines changed: 156 additions & 1 deletion

File tree

src/VirtualClient/VirtualClient.Actions.UnitTests/DiskSpd/DiskSpdMetricsParserTests.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,43 @@ public void DiskSpdParserVerifyWriteOnly()
199199
MetricAssert.Exists(metrics, "total latency max", 159.270, "ms");
200200
}
201201

202+
[Test]
203+
public void DiskSpdParserVerifyWriteOnlyV220FormatWithSocketNodeCoreColumns()
204+
{
205+
// DiskSpd v2.2.0 changed the CPU table to include Socket | Node | Group | Core | CPU columns.
206+
// The parser must normalise this extended header without throwing a KeyNotFoundException.
207+
string results = File.ReadAllText(MockFixture.GetDirectory(typeof(DiskSpdMetricsParserTests), "Examples", "DiskSpd", "DiskSpdExample-WriteOnly-v2.2.0.txt"));
208+
var parser = new DiskSpdMetricsParser(results, "diskspd.exe -b4K -r4K -t160 -o3 -w100 -d900 -Suw -W15 -D -L -Rtext D:\\diskspd-test.dat");
209+
210+
IList<Metric> metrics = parser.Parse();
211+
212+
// cpu metrics – rows 0,1 and avg from the truncated table
213+
MetricAssert.Exists(metrics, "cpu usage 0", 98.74, "percentage");
214+
MetricAssert.Exists(metrics, "cpu usage 1", 98.69, "percentage");
215+
MetricAssert.Exists(metrics, "cpu usage average", 98.59, "percentage");
216+
MetricAssert.Exists(metrics, "cpu user average", 0.75, "percentage");
217+
MetricAssert.Exists(metrics, "cpu kernel average", 97.84, "percentage");
218+
219+
// Total IO
220+
MetricAssert.Exists(metrics, "total bytes 0", 9466327040, "bytes");
221+
MetricAssert.Exists(metrics, "total throughput 0", 10.03, "MiB/s");
222+
MetricAssert.Exists(metrics, "total iops 0", 2567.89, "iops");
223+
MetricAssert.Exists(metrics, "total bytes total", 8265251819520, "bytes");
224+
MetricAssert.Exists(metrics, "total throughput total", 8758.14, "MiB/s");
225+
MetricAssert.Exists(metrics, "total iops total", 2242082.85, "iops");
226+
227+
// Write IO
228+
MetricAssert.Exists(metrics, "write bytes total", 8265251819520, "bytes");
229+
MetricAssert.Exists(metrics, "write throughput total", 8758.14, "MiB/s");
230+
MetricAssert.Exists(metrics, "write iops total", 2242082.85, "iops");
231+
232+
// Latency
233+
MetricAssert.Exists(metrics, "write latency min", 0.013, "ms");
234+
MetricAssert.Exists(metrics, "write latency 50th", 0.146, "ms");
235+
MetricAssert.Exists(metrics, "write latency 99th", 12.018, "ms");
236+
MetricAssert.Exists(metrics, "total latency max", 5543.894, "ms");
237+
}
238+
202239
[Test]
203240
public void DiskSpdParserVerifyForCoreCountGreaterThan64WhichAddsProcessorGrouping()
204241
{
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
2+
Command Line: C:\VirtualClient\content\win-x64\packages\diskspd.2.2.0\win-x64\diskspd.exe -c496G -b4K -r4K -t160 -o3 -w100 -d900 -Suw -W15 -D -L -Rtext D:\diskspd-test.dat
3+
4+
Input parameters:
5+
6+
timespan: 1
7+
-------------
8+
duration: 900s
9+
warm up time: 15s
10+
cool down time: 0s
11+
measuring latency
12+
gathering IOPS at intervals of 1000ms
13+
random seed: 0
14+
path: 'D:\diskspd-test.dat'
15+
think time: 0ms
16+
burst size: 0
17+
software cache disabled
18+
hardware write cache disabled, writethrough on
19+
performing write test
20+
block size: 4KiB
21+
using random I/O (alignment: 4KiB)
22+
number of outstanding I/O operations per thread: 3
23+
threads per file: 160
24+
using I/O Completion Ports
25+
IO priority: normal
26+
27+
System information:
28+
29+
computer name: SCHIELC41ABD017
30+
start time: 2026/05/22 07:21:47 UTC
31+
32+
cpu count: 320
33+
core count: 160
34+
group count: 5
35+
node count: 4
36+
socket count: 2
37+
heterogeneous cores: n
38+
39+
Results for timespan 1:
40+
*******************************************************************************
41+
42+
actual test time: 900.00s
43+
thread count: 800
44+
45+
Socket | Node | Group | Core | CPU | Usage | User | Kernel | Idle
46+
-----------------------------------------------------------------------
47+
0| 0| 0| 0| 0| 98.74%| 0.89%| 97.85%| 1.26%
48+
0| 0| 0| 0| 1| 98.69%| 0.89%| 97.79%| 1.31%
49+
0| 0| 0| 1| 2| 99.98%| 0.87%| 99.11%| 0.02%
50+
0| 0| 0| 1| 3| 100.00%| 0.94%| 99.06%| 0.00%
51+
-----------------------------------------------------------------------
52+
avg.| 98.59%| 0.75%| 97.84%| 1.41%
53+
54+
Total IO
55+
thread | bytes | I/Os | MiB/s | I/O per s | AvgLat | IopsStdDev | LatStdDev | file
56+
------------------------------------------------------------------------------------------------------------------
57+
0 | 9466327040 | 2311115 | 10.03 | 2567.89 | 0.974 | 432.90 | 2.469 | D:\diskspd-test.dat (496GiB)
58+
1 | 9458679808 | 2309248 | 10.02 | 2565.82 | 0.970 | 437.51 | 2.456 | D:\diskspd-test.dat (496GiB)
59+
------------------------------------------------------------------------------------------------------------------
60+
total: 8265251819520 | 2017883745 | 8758.14 | 2242082.85 | 0.861 | 135948.98 | 3.327
61+
62+
Read IO
63+
thread | bytes | I/Os | MiB/s | I/O per s | AvgLat | IopsStdDev | LatStdDev | file
64+
------------------------------------------------------------------------------------------------------------------
65+
0 | 0 | 0 | 0.00 | 0.00 | 0.000 | 0.00 | N/A | D:\diskspd-test.dat (496GiB)
66+
1 | 0 | 0 | 0.00 | 0.00 | 0.000 | 0.00 | N/A | D:\diskspd-test.dat (496GiB)
67+
------------------------------------------------------------------------------------------------------------------
68+
total: 0 | 0 | 0.00 | 0.00 | 0.000 | 0.00 | N/A
69+
70+
Write IO
71+
thread | bytes | I/Os | MiB/s | I/O per s | AvgLat | IopsStdDev | LatStdDev | file
72+
------------------------------------------------------------------------------------------------------------------
73+
0 | 9466327040 | 2311115 | 10.03 | 2567.89 | 0.974 | 432.90 | 2.469 | D:\diskspd-test.dat (496GiB)
74+
1 | 9458679808 | 2309248 | 10.02 | 2565.82 | 0.970 | 437.51 | 2.456 | D:\diskspd-test.dat (496GiB)
75+
------------------------------------------------------------------------------------------------------------------
76+
total: 8265251819520 | 2017883745 | 8758.14 | 2242082.85 | 0.861 | 135948.98 | 3.327
77+
78+
79+
80+
total:
81+
%-ile | Read (ms) | Write (ms) | Total (ms)
82+
----------------------------------------------
83+
min | N/A | 0.013 | 0.013
84+
25th | N/A | 0.080 | 0.080
85+
50th | N/A | 0.146 | 0.146
86+
75th | N/A | 0.470 | 0.470
87+
90th | N/A | 1.683 | 1.683
88+
95th | N/A | 3.151 | 3.151
89+
99th | N/A | 12.018 | 12.018
90+
3-nines | N/A | 37.418 | 37.418
91+
4-nines | N/A | 62.504 | 62.504
92+
5-nines | N/A | 77.135 | 77.135
93+
6-nines | N/A | 148.814 | 148.814
94+
7-nines | N/A | 2247.379 | 2247.379
95+
8-nines | N/A | 5497.506 | 5497.506
96+
9-nines | N/A | 5543.894 | 5543.894
97+
max | N/A | 5543.894 | 5543.894

src/VirtualClient/VirtualClient.Actions/DiskSpd/DiskSpdMetricsParser.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,28 @@ protected override void Preprocess()
111111
* Group | CPU | Usage | User | Kernel | Idle
112112
*/
113113

114-
if (this.PreprocessedText.Contains("Group"))
114+
/*
115+
* DiskSpd v2.2.0 added Socket, Node, Core columns to the CPU table:
116+
*
117+
* Socket | Node | Group | Core | CPU | Usage | User | Kernel | Idle
118+
*
119+
* Normalize this to the existing Group | CPU format by:
120+
* 1. Replacing the extended header so sectionizing produces a "CPU" section.
121+
* 2. Stripping Socket, Node, Core from every data row.
122+
*/
123+
if (this.PreprocessedText.Contains("Socket | Node | Group | Core | CPU"))
124+
{
125+
this.PreprocessedText = this.PreprocessedText.Replace(
126+
"Socket | Node | Group | Core | CPU",
127+
$"CPU{Environment.NewLine}Group | CPU");
128+
129+
this.PreprocessedText = Regex.Replace(
130+
this.PreprocessedText,
131+
@"^\s*(\d+)\s*\|\s*(\d+)\s*\|\s*(\d+)\s*\|\s*(\d+)\s*\|\s*(\d+)\s*\|",
132+
" $3| $5|",
133+
RegexOptions.Multiline);
134+
}
135+
else if (this.PreprocessedText.Contains("Group"))
115136
{
116137
this.PreprocessedText = this.PreprocessedText.Replace("Group", $"CPU{Environment.NewLine}Group");
117138
}

0 commit comments

Comments
 (0)