tests/unit/test-smp-parse: Test "drawers" parameter in -smp
[qemu/kevin.git] / tests / unit / test-smp-parse.c
blobaea1b2e73a55a7623af0295627ce24c372a0b7d6
1 /*
2 * SMP parsing unit-tests
4 * Copyright (c) 2021 Huawei Technologies Co., Ltd
6 * Authors:
7 * Yanan Wang <wangyanan55@huawei.com>
9 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10 * See the COPYING.LIB file in the top-level directory.
13 #include "qemu/osdep.h"
14 #include "qom/object.h"
15 #include "qemu/module.h"
16 #include "qapi/error.h"
18 #include "hw/boards.h"
20 #define T true
21 #define F false
23 #define MIN_CPUS 1 /* set the min CPUs supported by the machine as 1 */
24 #define MAX_CPUS 4096 /* set the max CPUs supported by the machine as 4096 */
26 #define SMP_MACHINE_NAME "TEST-SMP"
29 * Used to define the generic 3-level CPU topology hierarchy
30 * -sockets/cores/threads
32 #define SMP_CONFIG_GENERIC(ha, a, hb, b, hc, c, hd, d, he, e) \
33 { \
34 .has_cpus = ha, .cpus = a, \
35 .has_sockets = hb, .sockets = b, \
36 .has_cores = hc, .cores = c, \
37 .has_threads = hd, .threads = d, \
38 .has_maxcpus = he, .maxcpus = e, \
41 #define CPU_TOPOLOGY_GENERIC(a, b, c, d, e) \
42 { \
43 .cpus = a, \
44 .sockets = b, \
45 .cores = c, \
46 .threads = d, \
47 .max_cpus = e, \
51 * Currently a 4-level topology hierarchy is supported on PC machines
52 * -sockets/dies/cores/threads
54 #define SMP_CONFIG_WITH_DIES(ha, a, hb, b, hc, c, hd, d, he, e, hf, f) \
55 { \
56 .has_cpus = ha, .cpus = a, \
57 .has_sockets = hb, .sockets = b, \
58 .has_dies = hc, .dies = c, \
59 .has_cores = hd, .cores = d, \
60 .has_threads = he, .threads = e, \
61 .has_maxcpus = hf, .maxcpus = f, \
65 * Currently a 4-level topology hierarchy is supported on ARM virt machines
66 * -sockets/clusters/cores/threads
68 #define SMP_CONFIG_WITH_CLUSTERS(ha, a, hb, b, hc, c, hd, d, he, e, hf, f) \
69 { \
70 .has_cpus = ha, .cpus = a, \
71 .has_sockets = hb, .sockets = b, \
72 .has_clusters = hc, .clusters = c, \
73 .has_cores = hd, .cores = d, \
74 .has_threads = he, .threads = e, \
75 .has_maxcpus = hf, .maxcpus = f, \
79 * Currently a 5-level topology hierarchy is supported on s390 ccw machines
80 * -drawers/books/sockets/cores/threads
82 #define SMP_CONFIG_WITH_BOOKS_DRAWERS(ha, a, hb, b, hc, c, hd, \
83 d, he, e, hf, f, hg, g) \
84 { \
85 .has_cpus = ha, .cpus = a, \
86 .has_drawers = hb, .drawers = b, \
87 .has_books = hc, .books = c, \
88 .has_sockets = hd, .sockets = d, \
89 .has_cores = he, .cores = e, \
90 .has_threads = hf, .threads = f, \
91 .has_maxcpus = hg, .maxcpus = g, \
94 /**
95 * @config - the given SMP configuration
96 * @expect_prefer_sockets - the expected parsing result for the
97 * valid configuration, when sockets are preferred over cores
98 * @expect_prefer_cores - the expected parsing result for the
99 * valid configuration, when cores are preferred over sockets
100 * @expect_error - the expected error report when the given
101 * configuration is invalid
103 typedef struct SMPTestData {
104 SMPConfiguration config;
105 CpuTopology expect_prefer_sockets;
106 CpuTopology expect_prefer_cores;
107 const char *expect_error;
108 } SMPTestData;
111 * List all the possible valid sub-collections of the generic 5
112 * topology parameters (i.e. cpus/maxcpus/sockets/cores/threads),
113 * then test the automatic calculation algorithm of the missing
114 * values in the parser.
116 static const struct SMPTestData data_generic_valid[] = {
118 /* config: no configuration provided
119 * expect: cpus=1,sockets=1,cores=1,threads=1,maxcpus=1 */
120 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, F, 0, F, 0),
121 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(1, 1, 1, 1, 1),
122 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(1, 1, 1, 1, 1),
123 }, {
124 /* config: -smp 8
125 * prefer_sockets: cpus=8,sockets=8,cores=1,threads=1,maxcpus=8
126 * prefer_cores: cpus=8,sockets=1,cores=8,threads=1,maxcpus=8 */
127 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, F, 0, F, 0),
128 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 8, 1, 1, 8),
129 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 8, 1, 8),
130 }, {
131 /* config: -smp sockets=2
132 * expect: cpus=2,sockets=2,cores=1,threads=1,maxcpus=2 */
133 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, F, 0, F, 0),
134 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(2, 2, 1, 1, 2),
135 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(2, 2, 1, 1, 2),
136 }, {
137 /* config: -smp cores=4
138 * expect: cpus=4,sockets=1,cores=4,threads=1,maxcpus=4 */
139 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, F, 0, F, 0),
140 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(4, 1, 4, 1, 4),
141 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(4, 1, 4, 1, 4),
142 }, {
143 /* config: -smp threads=2
144 * expect: cpus=2,sockets=1,cores=1,threads=2,maxcpus=2 */
145 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, T, 2, F, 0),
146 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(2, 1, 1, 2, 2),
147 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(2, 1, 1, 2, 2),
148 }, {
149 /* config: -smp maxcpus=16
150 * prefer_sockets: cpus=16,sockets=16,cores=1,threads=1,maxcpus=16
151 * prefer_cores: cpus=16,sockets=1,cores=16,threads=1,maxcpus=16 */
152 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, F, 0, T, 16),
153 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 16, 1, 1, 16),
154 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 1, 16, 1, 16),
155 }, {
156 /* config: -smp 8,sockets=2
157 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */
158 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, F, 0, F, 0),
159 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
160 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
161 }, {
162 /* config: -smp 8,cores=4
163 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */
164 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, F, 0, F, 0),
165 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
166 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
167 }, {
168 /* config: -smp 8,threads=2
169 * prefer_sockets: cpus=8,sockets=4,cores=1,threads=2,maxcpus=8
170 * prefer_cores: cpus=8,sockets=1,cores=4,threads=2,maxcpus=8 */
171 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, T, 2, F, 0),
172 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 4, 1, 2, 8),
173 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8),
174 }, {
175 /* config: -smp 8,maxcpus=16
176 * prefer_sockets: cpus=8,sockets=16,cores=1,threads=1,maxcpus=16
177 * prefer_cores: cpus=8,sockets=1,cores=16,threads=1,maxcpus=16 */
178 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, F, 0, T, 16),
179 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 16, 1, 1, 16),
180 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 16, 1, 16),
181 }, {
182 /* config: -smp sockets=2,cores=4
183 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */
184 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, F, 0, F, 0),
185 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
186 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
187 }, {
188 /* config: -smp sockets=2,threads=2
189 * expect: cpus=4,sockets=2,cores=1,threads=2,maxcpus=4 */
190 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, T, 2, F, 0),
191 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(4, 2, 1, 2, 4),
192 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(4, 2, 1, 2, 4),
193 }, {
194 /* config: -smp sockets=2,maxcpus=16
195 * expect: cpus=16,sockets=2,cores=8,threads=1,maxcpus=16 */
196 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, F, 0, T, 16),
197 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 8, 1, 16),
198 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 8, 1, 16),
199 }, {
200 /* config: -smp cores=4,threads=2
201 * expect: cpus=8,sockets=1,cores=4,threads=2,maxcpus=8 */
202 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, T, 2, F, 0),
203 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8),
204 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8),
205 }, {
206 /* config: -smp cores=4,maxcpus=16
207 * expect: cpus=16,sockets=4,cores=4,threads=1,maxcpus=16 */
208 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, F, 0, T, 16),
209 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 4, 4, 1, 16),
210 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 4, 4, 1, 16),
211 }, {
212 /* config: -smp threads=2,maxcpus=16
213 * prefer_sockets: cpus=16,sockets=8,cores=1,threads=2,maxcpus=16
214 * prefer_cores: cpus=16,sockets=1,cores=8,threads=2,maxcpus=16 */
215 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, T, 2, T, 16),
216 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 8, 1, 2, 16),
217 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 1, 8, 2, 16),
218 }, {
219 /* config: -smp 8,sockets=2,cores=4
220 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */
221 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, F, 0, F, 0),
222 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
223 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
224 }, {
225 /* config: -smp 8,sockets=2,threads=2
226 * expect: cpus=8,sockets=2,cores=2,threads=2,maxcpus=8 */
227 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, T, 2, F, 0),
228 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 2, 2, 8),
229 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 2, 2, 8),
230 }, {
231 /* config: -smp 8,sockets=2,maxcpus=16
232 * expect: cpus=8,sockets=2,cores=8,threads=1,maxcpus=16 */
233 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, F, 0, T, 16),
234 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 8, 1, 16),
235 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 8, 1, 16),
236 }, {
237 /* config: -smp 8,cores=4,threads=2
238 * expect: cpus=8,sockets=1,cores=4,threads=2,maxcpus=8 */
239 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, T, 2, F, 0),
240 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8),
241 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8),
242 }, {
243 /* config: -smp 8,cores=4,maxcpus=16
244 * expect: cpus=8,sockets=4,cores=4,threads=1,maxcpus=16 */
245 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, F, 0, T, 16),
246 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 4, 4, 1, 16),
247 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 4, 4, 1, 16),
248 }, {
249 /* config: -smp 8,threads=2,maxcpus=16
250 * prefer_sockets: cpus=8,sockets=8,cores=1,threads=2,maxcpus=16
251 * prefer_cores: cpus=8,sockets=1,cores=8,threads=2,maxcpus=16 */
252 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, T, 2, T, 16),
253 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 8, 1, 2, 16),
254 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 8, 2, 16),
255 }, {
256 /* config: -smp sockets=2,cores=4,threads=2
257 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */
258 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, T, 2, F, 0),
259 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
260 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
261 }, {
262 /* config: -smp sockets=2,cores=4,maxcpus=16
263 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */
264 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, F, 0, T, 16),
265 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
266 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
267 }, {
268 /* config: -smp sockets=2,threads=2,maxcpus=16
269 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */
270 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, T, 2, T, 16),
271 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
272 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
273 }, {
274 /* config: -smp cores=4,threads=2,maxcpus=16
275 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */
276 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, T, 2, T, 16),
277 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
278 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
279 }, {
280 /* config: -smp 8,sockets=2,cores=4,threads=1
281 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */
282 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 1, F, 0),
283 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
284 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
285 }, {
286 /* config: -smp 8,sockets=2,cores=4,maxcpus=16
287 * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */
288 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, F, 0, T, 16),
289 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
290 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
291 }, {
292 /* config: -smp 8,sockets=2,threads=2,maxcpus=16
293 * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */
294 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, T, 2, T, 16),
295 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
296 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
297 }, {
298 /* config: -smp 8,cores=4,threads=2,maxcpus=16
299 * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */
300 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, T, 2, T, 16),
301 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
302 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
303 }, {
304 /* config: -smp sockets=2,cores=4,threads=2,maxcpus=16
305 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */
306 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, T, 2, T, 16),
307 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
308 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
309 }, {
310 /* config: -smp 8,sockets=2,cores=4,threads=2,maxcpus=16
311 * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */
312 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 2, T, 16),
313 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
314 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
318 static const struct SMPTestData data_generic_invalid[] = {
320 /* config: -smp 2,dies=2 */
321 .config = SMP_CONFIG_WITH_DIES(T, 2, F, 0, T, 2, F, 0, F, 0, F, 0),
322 .expect_error = "dies not supported by this machine's CPU topology",
323 }, {
324 /* config: -smp 2,clusters=2 */
325 .config = SMP_CONFIG_WITH_CLUSTERS(T, 2, F, 0, T, 2, F, 0, F, 0, F, 0),
326 .expect_error = "clusters not supported by this machine's CPU topology",
327 }, {
328 /* config: -smp 2,books=2 */
329 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 2, F, 0, T, 2, F,
330 0, F, 0, F, 0, F, 0),
331 .expect_error = "books not supported by this machine's CPU topology",
332 }, {
333 /* config: -smp 2,drawers=2 */
334 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 2, T, 2, F, 0, F,
335 0, F, 0, F, 0, F, 0),
336 .expect_error = "drawers not supported by this machine's CPU topology",
337 }, {
338 /* config: -smp 8,sockets=2,cores=4,threads=2,maxcpus=8 */
339 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 2, T, 8),
340 .expect_error = "Invalid CPU topology: "
341 "product of the hierarchy must match maxcpus: "
342 "sockets (2) * cores (4) * threads (2) "
343 "!= maxcpus (8)",
344 }, {
345 /* config: -smp 18,sockets=2,cores=4,threads=2,maxcpus=16 */
346 .config = SMP_CONFIG_GENERIC(T, 18, T, 2, T, 4, T, 2, T, 16),
347 .expect_error = "Invalid CPU topology: "
348 "maxcpus must be equal to or greater than smp: "
349 "sockets (2) * cores (4) * threads (2) "
350 "== maxcpus (16) < smp_cpus (18)",
351 }, {
353 * config: -smp 1
354 * The test machine should tweak the supported min CPUs to
355 * 2 (MIN_CPUS + 1) for testing.
357 .config = SMP_CONFIG_GENERIC(T, MIN_CPUS, F, 0, F, 0, F, 0, F, 0),
358 .expect_error = "Invalid SMP CPUs 1. The min CPUs supported "
359 "by machine '" SMP_MACHINE_NAME "' is 2",
360 }, {
362 * config: -smp 4096
363 * The test machine should tweak the supported max CPUs to
364 * 4095 (MAX_CPUS - 1) for testing.
366 .config = SMP_CONFIG_GENERIC(T, 4096, F, 0, F, 0, F, 0, F, 0),
367 .expect_error = "Invalid SMP CPUs 4096. The max CPUs supported "
368 "by machine '" SMP_MACHINE_NAME "' is 4095",
372 static const struct SMPTestData data_with_dies_invalid[] = {
374 /* config: -smp 16,sockets=2,dies=2,cores=4,threads=2,maxcpus=16 */
375 .config = SMP_CONFIG_WITH_DIES(T, 16, T, 2, T, 2, T, 4, T, 2, T, 16),
376 .expect_error = "Invalid CPU topology: "
377 "product of the hierarchy must match maxcpus: "
378 "sockets (2) * dies (2) * cores (4) * threads (2) "
379 "!= maxcpus (16)",
380 }, {
381 /* config: -smp 34,sockets=2,dies=2,cores=4,threads=2,maxcpus=32 */
382 .config = SMP_CONFIG_WITH_DIES(T, 34, T, 2, T, 2, T, 4, T, 2, T, 32),
383 .expect_error = "Invalid CPU topology: "
384 "maxcpus must be equal to or greater than smp: "
385 "sockets (2) * dies (2) * cores (4) * threads (2) "
386 "== maxcpus (32) < smp_cpus (34)",
390 static const struct SMPTestData data_with_clusters_invalid[] = {
392 /* config: -smp 16,sockets=2,clusters=2,cores=4,threads=2,maxcpus=16 */
393 .config = SMP_CONFIG_WITH_CLUSTERS(T, 16, T, 2, T, 2, T, 4, T, 2, T, 16),
394 .expect_error = "Invalid CPU topology: "
395 "product of the hierarchy must match maxcpus: "
396 "sockets (2) * clusters (2) * cores (4) * threads (2) "
397 "!= maxcpus (16)",
398 }, {
399 /* config: -smp 34,sockets=2,clusters=2,cores=4,threads=2,maxcpus=32 */
400 .config = SMP_CONFIG_WITH_CLUSTERS(T, 34, T, 2, T, 2, T, 4, T, 2, T, 32),
401 .expect_error = "Invalid CPU topology: "
402 "maxcpus must be equal to or greater than smp: "
403 "sockets (2) * clusters (2) * cores (4) * threads (2) "
404 "== maxcpus (32) < smp_cpus (34)",
408 static const struct SMPTestData data_with_books_invalid[] = {
410 /* config: -smp 16,books=2,sockets=2,cores=4,threads=2,maxcpus=16 */
411 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 16, F, 1, T, 2, T,
412 2, T, 4, T, 2, T, 16),
413 .expect_error = "Invalid CPU topology: "
414 "product of the hierarchy must match maxcpus: "
415 "books (2) * sockets (2) * cores (4) * threads (2) "
416 "!= maxcpus (16)",
417 }, {
418 /* config: -smp 34,books=2,sockets=2,cores=4,threads=2,maxcpus=32 */
419 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 34, F, 1, T, 2, T,
420 2, T, 4, T, 2, T, 32),
421 .expect_error = "Invalid CPU topology: "
422 "maxcpus must be equal to or greater than smp: "
423 "books (2) * sockets (2) * cores (4) * threads (2) "
424 "== maxcpus (32) < smp_cpus (34)",
428 static const struct SMPTestData data_with_drawers_invalid[] = {
430 /* config: -smp 16,drawers=2,sockets=2,cores=4,threads=2,maxcpus=16 */
431 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 16, T, 2, F, 1, T,
432 2, T, 4, T, 2, T, 16),
433 .expect_error = "Invalid CPU topology: "
434 "product of the hierarchy must match maxcpus: "
435 "drawers (2) * sockets (2) * cores (4) * threads (2) "
436 "!= maxcpus (16)",
437 }, {
438 /* config: -smp 34,drawers=2,sockets=2,cores=4,threads=2,maxcpus=32 */
439 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 34, T, 2, F, 1, T,
440 2, T, 4, T, 2, T, 32),
441 .expect_error = "Invalid CPU topology: "
442 "maxcpus must be equal to or greater than smp: "
443 "drawers (2) * sockets (2) * cores (4) * threads (2) "
444 "== maxcpus (32) < smp_cpus (34)",
448 static char *smp_config_to_string(const SMPConfiguration *config)
450 return g_strdup_printf(
451 "(SMPConfiguration) {\n"
452 " .has_cpus = %5s, cpus = %" PRId64 ",\n"
453 " .has_drawers = %5s, drawers = %" PRId64 ",\n"
454 " .has_books = %5s, books = %" PRId64 ",\n"
455 " .has_sockets = %5s, sockets = %" PRId64 ",\n"
456 " .has_dies = %5s, dies = %" PRId64 ",\n"
457 " .has_clusters = %5s, clusters = %" PRId64 ",\n"
458 " .has_cores = %5s, cores = %" PRId64 ",\n"
459 " .has_threads = %5s, threads = %" PRId64 ",\n"
460 " .has_maxcpus = %5s, maxcpus = %" PRId64 ",\n"
461 "}",
462 config->has_cpus ? "true" : "false", config->cpus,
463 config->has_drawers ? "true" : "false", config->drawers,
464 config->has_books ? "true" : "false", config->books,
465 config->has_sockets ? "true" : "false", config->sockets,
466 config->has_dies ? "true" : "false", config->dies,
467 config->has_clusters ? "true" : "false", config->clusters,
468 config->has_cores ? "true" : "false", config->cores,
469 config->has_threads ? "true" : "false", config->threads,
470 config->has_maxcpus ? "true" : "false", config->maxcpus);
473 /* Use the different calculation than machine_topo_get_threads_per_socket(). */
474 static unsigned int cpu_topology_get_threads_per_socket(const CpuTopology *topo)
476 /* Check the divisor to avoid invalid topology examples causing SIGFPE. */
477 if (!topo->drawers || !topo->books || !topo->sockets) {
478 return 0;
479 } else {
480 return topo->max_cpus / topo->drawers / topo->books / topo->sockets;
484 /* Use the different calculation than machine_topo_get_cores_per_socket(). */
485 static unsigned int cpu_topology_get_cores_per_socket(const CpuTopology *topo)
487 /* Check the divisor to avoid invalid topology examples causing SIGFPE. */
488 if (!topo->threads) {
489 return 0;
490 } else {
491 return cpu_topology_get_threads_per_socket(topo) / topo->threads;
495 static char *cpu_topology_to_string(const CpuTopology *topo,
496 unsigned int threads_per_socket,
497 unsigned int cores_per_socket)
499 return g_strdup_printf(
500 "(CpuTopology) {\n"
501 " .cpus = %u,\n"
502 " .drawers = %u,\n"
503 " .books = %u,\n"
504 " .sockets = %u,\n"
505 " .dies = %u,\n"
506 " .clusters = %u,\n"
507 " .cores = %u,\n"
508 " .threads = %u,\n"
509 " .max_cpus = %u,\n"
510 " .threads_per_socket = %u,\n"
511 " .cores_per_socket = %u,\n"
512 "}",
513 topo->cpus, topo->drawers, topo->books,
514 topo->sockets, topo->dies, topo->clusters,
515 topo->cores, topo->threads, topo->max_cpus,
516 threads_per_socket, cores_per_socket);
519 static void check_parse(MachineState *ms, const SMPConfiguration *config,
520 const CpuTopology *expect_topo, const char *expect_err,
521 bool is_valid)
523 g_autofree char *config_str = smp_config_to_string(config);
524 g_autofree char *expect_topo_str = NULL, *output_topo_str = NULL;
525 unsigned int expect_threads_per_socket, expect_cores_per_socket;
526 unsigned int ms_threads_per_socket, ms_cores_per_socket;
527 Error *err = NULL;
529 expect_threads_per_socket =
530 cpu_topology_get_threads_per_socket(expect_topo);
531 expect_cores_per_socket =
532 cpu_topology_get_cores_per_socket(expect_topo);
533 expect_topo_str = cpu_topology_to_string(expect_topo,
534 expect_threads_per_socket,
535 expect_cores_per_socket);
537 /* call the generic parser */
538 machine_parse_smp_config(ms, config, &err);
540 ms_threads_per_socket = machine_topo_get_threads_per_socket(ms);
541 ms_cores_per_socket = machine_topo_get_cores_per_socket(ms);
542 output_topo_str = cpu_topology_to_string(&ms->smp, ms_threads_per_socket,
543 ms_cores_per_socket);
545 /* when the configuration is supposed to be valid */
546 if (is_valid) {
547 if ((err == NULL) &&
548 (ms->smp.cpus == expect_topo->cpus) &&
549 (ms->smp.drawers == expect_topo->drawers) &&
550 (ms->smp.books == expect_topo->books) &&
551 (ms->smp.sockets == expect_topo->sockets) &&
552 (ms->smp.dies == expect_topo->dies) &&
553 (ms->smp.clusters == expect_topo->clusters) &&
554 (ms->smp.cores == expect_topo->cores) &&
555 (ms->smp.threads == expect_topo->threads) &&
556 (ms->smp.max_cpus == expect_topo->max_cpus) &&
557 (ms_threads_per_socket == expect_threads_per_socket) &&
558 (ms_cores_per_socket == expect_cores_per_socket)) {
559 return;
562 if (err != NULL) {
563 g_printerr("Test smp_parse failed!\n"
564 "Input configuration: %s\n"
565 "Should be valid: yes\n"
566 "Expected topology: %s\n\n"
567 "Result is valid: no\n"
568 "Output error report: %s\n",
569 config_str, expect_topo_str, error_get_pretty(err));
570 goto end;
573 g_printerr("Test smp_parse failed!\n"
574 "Input configuration: %s\n"
575 "Should be valid: yes\n"
576 "Expected topology: %s\n\n"
577 "Result is valid: yes\n"
578 "Output topology: %s\n",
579 config_str, expect_topo_str, output_topo_str);
580 goto end;
583 /* when the configuration is supposed to be invalid */
584 if (err != NULL) {
585 if (expect_err == NULL ||
586 g_str_equal(expect_err, error_get_pretty(err))) {
587 error_free(err);
588 return;
591 g_printerr("Test smp_parse failed!\n"
592 "Input configuration: %s\n"
593 "Should be valid: no\n"
594 "Expected error report: %s\n\n"
595 "Result is valid: no\n"
596 "Output error report: %s\n",
597 config_str, expect_err, error_get_pretty(err));
598 goto end;
601 g_printerr("Test smp_parse failed!\n"
602 "Input configuration: %s\n"
603 "Should be valid: no\n"
604 "Expected error report: %s\n\n"
605 "Result is valid: yes\n"
606 "Output topology: %s\n",
607 config_str, expect_err, output_topo_str);
609 end:
610 if (err != NULL) {
611 error_free(err);
614 abort();
617 static void smp_parse_test(MachineState *ms, SMPTestData *data, bool is_valid)
619 MachineClass *mc = MACHINE_GET_CLASS(ms);
621 mc->smp_props.prefer_sockets = true;
622 check_parse(ms, &data->config, &data->expect_prefer_sockets,
623 data->expect_error, is_valid);
625 mc->smp_props.prefer_sockets = false;
626 check_parse(ms, &data->config, &data->expect_prefer_cores,
627 data->expect_error, is_valid);
630 /* The parsed results of the unsupported parameters should be 1 */
631 static void unsupported_params_init(const MachineClass *mc, SMPTestData *data)
633 if (!mc->smp_props.dies_supported) {
634 data->expect_prefer_sockets.dies = 1;
635 data->expect_prefer_cores.dies = 1;
638 if (!mc->smp_props.clusters_supported) {
639 data->expect_prefer_sockets.clusters = 1;
640 data->expect_prefer_cores.clusters = 1;
643 if (!mc->smp_props.books_supported) {
644 data->expect_prefer_sockets.books = 1;
645 data->expect_prefer_cores.books = 1;
648 if (!mc->smp_props.drawers_supported) {
649 data->expect_prefer_sockets.drawers = 1;
650 data->expect_prefer_cores.drawers = 1;
654 static void machine_base_class_init(ObjectClass *oc, void *data)
656 MachineClass *mc = MACHINE_CLASS(oc);
658 mc->min_cpus = MIN_CPUS;
659 mc->max_cpus = MAX_CPUS;
661 mc->name = g_strdup(SMP_MACHINE_NAME);
664 static void machine_generic_invalid_class_init(ObjectClass *oc, void *data)
666 MachineClass *mc = MACHINE_CLASS(oc);
668 /* Force invalid min CPUs and max CPUs */
669 mc->min_cpus = MIN_CPUS + 1;
670 mc->max_cpus = MAX_CPUS - 1;
673 static void machine_with_dies_class_init(ObjectClass *oc, void *data)
675 MachineClass *mc = MACHINE_CLASS(oc);
677 mc->smp_props.dies_supported = true;
680 static void machine_with_clusters_class_init(ObjectClass *oc, void *data)
682 MachineClass *mc = MACHINE_CLASS(oc);
684 mc->smp_props.clusters_supported = true;
687 static void machine_with_books_class_init(ObjectClass *oc, void *data)
689 MachineClass *mc = MACHINE_CLASS(oc);
691 mc->smp_props.books_supported = true;
694 static void machine_with_drawers_class_init(ObjectClass *oc, void *data)
696 MachineClass *mc = MACHINE_CLASS(oc);
698 mc->smp_props.drawers_supported = true;
701 static void test_generic_valid(const void *opaque)
703 const char *machine_type = opaque;
704 Object *obj = object_new(machine_type);
705 MachineState *ms = MACHINE(obj);
706 MachineClass *mc = MACHINE_GET_CLASS(obj);
707 SMPTestData data = {};
708 int i;
710 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
711 data = data_generic_valid[i];
712 unsupported_params_init(mc, &data);
714 smp_parse_test(ms, &data, true);
717 object_unref(obj);
720 static void test_generic_invalid(const void *opaque)
722 const char *machine_type = opaque;
723 Object *obj = object_new(machine_type);
724 MachineState *ms = MACHINE(obj);
725 MachineClass *mc = MACHINE_GET_CLASS(obj);
726 SMPTestData data = {};
727 int i;
729 for (i = 0; i < ARRAY_SIZE(data_generic_invalid); i++) {
730 data = data_generic_invalid[i];
731 unsupported_params_init(mc, &data);
733 smp_parse_test(ms, &data, false);
736 object_unref(obj);
739 static void test_with_dies(const void *opaque)
741 const char *machine_type = opaque;
742 Object *obj = object_new(machine_type);
743 MachineState *ms = MACHINE(obj);
744 MachineClass *mc = MACHINE_GET_CLASS(obj);
745 SMPTestData data = {};
746 unsigned int num_dies = 2;
747 int i;
749 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
750 data = data_generic_valid[i];
751 unsupported_params_init(mc, &data);
753 /* when dies parameter is omitted, it will be set as 1 */
754 data.expect_prefer_sockets.dies = 1;
755 data.expect_prefer_cores.dies = 1;
757 smp_parse_test(ms, &data, true);
759 /* when dies parameter is specified */
760 data.config.has_dies = true;
761 data.config.dies = num_dies;
762 if (data.config.has_cpus) {
763 data.config.cpus *= num_dies;
765 if (data.config.has_maxcpus) {
766 data.config.maxcpus *= num_dies;
769 data.expect_prefer_sockets.dies = num_dies;
770 data.expect_prefer_sockets.cpus *= num_dies;
771 data.expect_prefer_sockets.max_cpus *= num_dies;
772 data.expect_prefer_cores.dies = num_dies;
773 data.expect_prefer_cores.cpus *= num_dies;
774 data.expect_prefer_cores.max_cpus *= num_dies;
776 smp_parse_test(ms, &data, true);
779 for (i = 0; i < ARRAY_SIZE(data_with_dies_invalid); i++) {
780 data = data_with_dies_invalid[i];
781 unsupported_params_init(mc, &data);
783 smp_parse_test(ms, &data, false);
786 object_unref(obj);
789 static void test_with_clusters(const void *opaque)
791 const char *machine_type = opaque;
792 Object *obj = object_new(machine_type);
793 MachineState *ms = MACHINE(obj);
794 MachineClass *mc = MACHINE_GET_CLASS(obj);
795 SMPTestData data = {};
796 unsigned int num_clusters = 2;
797 int i;
799 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
800 data = data_generic_valid[i];
801 unsupported_params_init(mc, &data);
803 /* when clusters parameter is omitted, it will be set as 1 */
804 data.expect_prefer_sockets.clusters = 1;
805 data.expect_prefer_cores.clusters = 1;
807 smp_parse_test(ms, &data, true);
809 /* when clusters parameter is specified */
810 data.config.has_clusters = true;
811 data.config.clusters = num_clusters;
812 if (data.config.has_cpus) {
813 data.config.cpus *= num_clusters;
815 if (data.config.has_maxcpus) {
816 data.config.maxcpus *= num_clusters;
819 data.expect_prefer_sockets.clusters = num_clusters;
820 data.expect_prefer_sockets.cpus *= num_clusters;
821 data.expect_prefer_sockets.max_cpus *= num_clusters;
822 data.expect_prefer_cores.clusters = num_clusters;
823 data.expect_prefer_cores.cpus *= num_clusters;
824 data.expect_prefer_cores.max_cpus *= num_clusters;
826 smp_parse_test(ms, &data, true);
829 for (i = 0; i < ARRAY_SIZE(data_with_clusters_invalid); i++) {
830 data = data_with_clusters_invalid[i];
831 unsupported_params_init(mc, &data);
833 smp_parse_test(ms, &data, false);
836 object_unref(obj);
839 static void test_with_books(const void *opaque)
841 const char *machine_type = opaque;
842 Object *obj = object_new(machine_type);
843 MachineState *ms = MACHINE(obj);
844 MachineClass *mc = MACHINE_GET_CLASS(obj);
845 SMPTestData data = {};
846 unsigned int num_books = 2;
847 int i;
849 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
850 data = data_generic_valid[i];
851 unsupported_params_init(mc, &data);
853 /* when books parameter is omitted, it will be set as 1 */
854 data.expect_prefer_sockets.books = 1;
855 data.expect_prefer_cores.books = 1;
857 smp_parse_test(ms, &data, true);
859 /* when books parameter is specified */
860 data.config.has_books = true;
861 data.config.books = num_books;
862 if (data.config.has_cpus) {
863 data.config.cpus *= num_books;
865 if (data.config.has_maxcpus) {
866 data.config.maxcpus *= num_books;
869 data.expect_prefer_sockets.books = num_books;
870 data.expect_prefer_sockets.cpus *= num_books;
871 data.expect_prefer_sockets.max_cpus *= num_books;
872 data.expect_prefer_cores.books = num_books;
873 data.expect_prefer_cores.cpus *= num_books;
874 data.expect_prefer_cores.max_cpus *= num_books;
876 smp_parse_test(ms, &data, true);
879 for (i = 0; i < ARRAY_SIZE(data_with_books_invalid); i++) {
880 data = data_with_books_invalid[i];
881 unsupported_params_init(mc, &data);
883 smp_parse_test(ms, &data, false);
886 object_unref(obj);
889 static void test_with_drawers(const void *opaque)
891 const char *machine_type = opaque;
892 Object *obj = object_new(machine_type);
893 MachineState *ms = MACHINE(obj);
894 MachineClass *mc = MACHINE_GET_CLASS(obj);
895 SMPTestData data = {};
896 unsigned int num_drawers = 2;
897 int i;
899 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
900 data = data_generic_valid[i];
901 unsupported_params_init(mc, &data);
903 /* when drawers parameter is omitted, it will be set as 1 */
904 data.expect_prefer_sockets.drawers = 1;
905 data.expect_prefer_cores.drawers = 1;
907 smp_parse_test(ms, &data, true);
909 /* when drawers parameter is specified */
910 data.config.has_drawers = true;
911 data.config.drawers = num_drawers;
912 if (data.config.has_cpus) {
913 data.config.cpus *= num_drawers;
915 if (data.config.has_maxcpus) {
916 data.config.maxcpus *= num_drawers;
919 data.expect_prefer_sockets.drawers = num_drawers;
920 data.expect_prefer_sockets.cpus *= num_drawers;
921 data.expect_prefer_sockets.max_cpus *= num_drawers;
922 data.expect_prefer_cores.drawers = num_drawers;
923 data.expect_prefer_cores.cpus *= num_drawers;
924 data.expect_prefer_cores.max_cpus *= num_drawers;
926 smp_parse_test(ms, &data, true);
929 for (i = 0; i < ARRAY_SIZE(data_with_drawers_invalid); i++) {
930 data = data_with_drawers_invalid[i];
931 unsupported_params_init(mc, &data);
933 smp_parse_test(ms, &data, false);
936 object_unref(obj);
939 /* Type info of the tested machine */
940 static const TypeInfo smp_machine_types[] = {
942 .name = TYPE_MACHINE,
943 .parent = TYPE_OBJECT,
944 .abstract = true,
945 .class_init = machine_base_class_init,
946 .class_size = sizeof(MachineClass),
947 .instance_size = sizeof(MachineState),
948 }, {
949 .name = MACHINE_TYPE_NAME("smp-generic-valid"),
950 .parent = TYPE_MACHINE,
951 }, {
952 .name = MACHINE_TYPE_NAME("smp-generic-invalid"),
953 .parent = TYPE_MACHINE,
954 .class_init = machine_generic_invalid_class_init,
955 }, {
956 .name = MACHINE_TYPE_NAME("smp-with-dies"),
957 .parent = TYPE_MACHINE,
958 .class_init = machine_with_dies_class_init,
959 }, {
960 .name = MACHINE_TYPE_NAME("smp-with-clusters"),
961 .parent = TYPE_MACHINE,
962 .class_init = machine_with_clusters_class_init,
963 }, {
964 .name = MACHINE_TYPE_NAME("smp-with-books"),
965 .parent = TYPE_MACHINE,
966 .class_init = machine_with_books_class_init,
967 }, {
968 .name = MACHINE_TYPE_NAME("smp-with-drawers"),
969 .parent = TYPE_MACHINE,
970 .class_init = machine_with_drawers_class_init,
974 DEFINE_TYPES(smp_machine_types)
976 int main(int argc, char *argv[])
978 module_call_init(MODULE_INIT_QOM);
980 g_test_init(&argc, &argv, NULL);
982 g_test_add_data_func("/test-smp-parse/generic/valid",
983 MACHINE_TYPE_NAME("smp-generic-valid"),
984 test_generic_valid);
985 g_test_add_data_func("/test-smp-parse/generic/invalid",
986 MACHINE_TYPE_NAME("smp-generic-invalid"),
987 test_generic_invalid);
988 g_test_add_data_func("/test-smp-parse/with_dies",
989 MACHINE_TYPE_NAME("smp-with-dies"),
990 test_with_dies);
991 g_test_add_data_func("/test-smp-parse/with_clusters",
992 MACHINE_TYPE_NAME("smp-with-clusters"),
993 test_with_clusters);
994 g_test_add_data_func("/test-smp-parse/with_books",
995 MACHINE_TYPE_NAME("smp-with-books"),
996 test_with_books);
997 g_test_add_data_func("/test-smp-parse/with_drawers",
998 MACHINE_TYPE_NAME("smp-with-drawers"),
999 test_with_drawers);
1001 g_test_run();
1003 return 0;