2 * SMP parsing unit-tests
4 * Copyright (c) 2021 Huawei Technologies Co., Ltd
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"
23 #define MIN_CPUS 1 /* set the min CPUs supported by the machine as 1 */
24 #define MAX_CPUS 512 /* set the max CPUs supported by the machine as 512 */
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) \
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) \
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) \
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) \
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 * @config - the given SMP configuration
80 * @expect_prefer_sockets - the expected parsing result for the
81 * valid configuration, when sockets are preferred over cores
82 * @expect_prefer_cores - the expected parsing result for the
83 * valid configuration, when cores are preferred over sockets
84 * @expect_error - the expected error report when the given
85 * configuration is invalid
87 typedef struct SMPTestData
{
88 SMPConfiguration config
;
89 CpuTopology expect_prefer_sockets
;
90 CpuTopology expect_prefer_cores
;
91 const char *expect_error
;
95 * List all the possible valid sub-collections of the generic 5
96 * topology parameters (i.e. cpus/maxcpus/sockets/cores/threads),
97 * then test the automatic calculation algorithm of the missing
98 * values in the parser.
100 static const struct SMPTestData data_generic_valid
[] = {
102 /* config: no configuration provided
103 * expect: cpus=1,sockets=1,cores=1,threads=1,maxcpus=1 */
104 .config
= SMP_CONFIG_GENERIC(F
, 0, F
, 0, F
, 0, F
, 0, F
, 0),
105 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(1, 1, 1, 1, 1),
106 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(1, 1, 1, 1, 1),
109 * prefer_sockets: cpus=8,sockets=8,cores=1,threads=1,maxcpus=8
110 * prefer_cores: cpus=8,sockets=1,cores=8,threads=1,maxcpus=8 */
111 .config
= SMP_CONFIG_GENERIC(T
, 8, F
, 0, F
, 0, F
, 0, F
, 0),
112 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(8, 8, 1, 1, 8),
113 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(8, 1, 8, 1, 8),
115 /* config: -smp sockets=2
116 * expect: cpus=2,sockets=2,cores=1,threads=1,maxcpus=2 */
117 .config
= SMP_CONFIG_GENERIC(F
, 0, T
, 2, F
, 0, F
, 0, F
, 0),
118 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(2, 2, 1, 1, 2),
119 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(2, 2, 1, 1, 2),
121 /* config: -smp cores=4
122 * expect: cpus=4,sockets=1,cores=4,threads=1,maxcpus=4 */
123 .config
= SMP_CONFIG_GENERIC(F
, 0, F
, 0, T
, 4, F
, 0, F
, 0),
124 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(4, 1, 4, 1, 4),
125 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(4, 1, 4, 1, 4),
127 /* config: -smp threads=2
128 * expect: cpus=2,sockets=1,cores=1,threads=2,maxcpus=2 */
129 .config
= SMP_CONFIG_GENERIC(F
, 0, F
, 0, F
, 0, T
, 2, F
, 0),
130 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(2, 1, 1, 2, 2),
131 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(2, 1, 1, 2, 2),
133 /* config: -smp maxcpus=16
134 * prefer_sockets: cpus=16,sockets=16,cores=1,threads=1,maxcpus=16
135 * prefer_cores: cpus=16,sockets=1,cores=16,threads=1,maxcpus=16 */
136 .config
= SMP_CONFIG_GENERIC(F
, 0, F
, 0, F
, 0, F
, 0, T
, 16),
137 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(16, 16, 1, 1, 16),
138 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(16, 1, 16, 1, 16),
140 /* config: -smp 8,sockets=2
141 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */
142 .config
= SMP_CONFIG_GENERIC(T
, 8, T
, 2, F
, 0, F
, 0, F
, 0),
143 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
144 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
146 /* config: -smp 8,cores=4
147 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */
148 .config
= SMP_CONFIG_GENERIC(T
, 8, F
, 0, T
, 4, F
, 0, F
, 0),
149 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
150 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
152 /* config: -smp 8,threads=2
153 * prefer_sockets: cpus=8,sockets=4,cores=1,threads=2,maxcpus=8
154 * prefer_cores: cpus=8,sockets=1,cores=4,threads=2,maxcpus=8 */
155 .config
= SMP_CONFIG_GENERIC(T
, 8, F
, 0, F
, 0, T
, 2, F
, 0),
156 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(8, 4, 1, 2, 8),
157 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8),
159 /* config: -smp 8,maxcpus=16
160 * prefer_sockets: cpus=8,sockets=16,cores=1,threads=1,maxcpus=16
161 * prefer_cores: cpus=8,sockets=1,cores=16,threads=1,maxcpus=16 */
162 .config
= SMP_CONFIG_GENERIC(T
, 8, F
, 0, F
, 0, F
, 0, T
, 16),
163 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(8, 16, 1, 1, 16),
164 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(8, 1, 16, 1, 16),
166 /* config: -smp sockets=2,cores=4
167 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */
168 .config
= SMP_CONFIG_GENERIC(F
, 0, T
, 2, T
, 4, F
, 0, F
, 0),
169 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
170 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
172 /* config: -smp sockets=2,threads=2
173 * expect: cpus=4,sockets=2,cores=1,threads=2,maxcpus=4 */
174 .config
= SMP_CONFIG_GENERIC(F
, 0, T
, 2, F
, 0, T
, 2, F
, 0),
175 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(4, 2, 1, 2, 4),
176 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(4, 2, 1, 2, 4),
178 /* config: -smp sockets=2,maxcpus=16
179 * expect: cpus=16,sockets=2,cores=8,threads=1,maxcpus=16 */
180 .config
= SMP_CONFIG_GENERIC(F
, 0, T
, 2, F
, 0, F
, 0, T
, 16),
181 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(16, 2, 8, 1, 16),
182 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(16, 2, 8, 1, 16),
184 /* config: -smp cores=4,threads=2
185 * expect: cpus=8,sockets=1,cores=4,threads=2,maxcpus=8 */
186 .config
= SMP_CONFIG_GENERIC(F
, 0, F
, 0, T
, 4, T
, 2, F
, 0),
187 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8),
188 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8),
190 /* config: -smp cores=4,maxcpus=16
191 * expect: cpus=16,sockets=4,cores=4,threads=1,maxcpus=16 */
192 .config
= SMP_CONFIG_GENERIC(F
, 0, F
, 0, T
, 4, F
, 0, T
, 16),
193 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(16, 4, 4, 1, 16),
194 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(16, 4, 4, 1, 16),
196 /* config: -smp threads=2,maxcpus=16
197 * prefer_sockets: cpus=16,sockets=8,cores=1,threads=2,maxcpus=16
198 * prefer_cores: cpus=16,sockets=1,cores=8,threads=2,maxcpus=16 */
199 .config
= SMP_CONFIG_GENERIC(F
, 0, F
, 0, F
, 0, T
, 2, T
, 16),
200 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(16, 8, 1, 2, 16),
201 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(16, 1, 8, 2, 16),
203 /* config: -smp 8,sockets=2,cores=4
204 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */
205 .config
= SMP_CONFIG_GENERIC(T
, 8, T
, 2, T
, 4, F
, 0, F
, 0),
206 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
207 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
209 /* config: -smp 8,sockets=2,threads=2
210 * expect: cpus=8,sockets=2,cores=2,threads=2,maxcpus=8 */
211 .config
= SMP_CONFIG_GENERIC(T
, 8, T
, 2, F
, 0, T
, 2, F
, 0),
212 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(8, 2, 2, 2, 8),
213 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(8, 2, 2, 2, 8),
215 /* config: -smp 8,sockets=2,maxcpus=16
216 * expect: cpus=8,sockets=2,cores=8,threads=1,maxcpus=16 */
217 .config
= SMP_CONFIG_GENERIC(T
, 8, T
, 2, F
, 0, F
, 0, T
, 16),
218 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(8, 2, 8, 1, 16),
219 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(8, 2, 8, 1, 16),
221 /* config: -smp 8,cores=4,threads=2
222 * expect: cpus=8,sockets=1,cores=4,threads=2,maxcpus=8 */
223 .config
= SMP_CONFIG_GENERIC(T
, 8, F
, 0, T
, 4, T
, 2, F
, 0),
224 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8),
225 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8),
227 /* config: -smp 8,cores=4,maxcpus=16
228 * expect: cpus=8,sockets=4,cores=4,threads=1,maxcpus=16 */
229 .config
= SMP_CONFIG_GENERIC(T
, 8, F
, 0, T
, 4, F
, 0, T
, 16),
230 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(8, 4, 4, 1, 16),
231 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(8, 4, 4, 1, 16),
233 /* config: -smp 8,threads=2,maxcpus=16
234 * prefer_sockets: cpus=8,sockets=8,cores=1,threads=2,maxcpus=16
235 * prefer_cores: cpus=8,sockets=1,cores=8,threads=2,maxcpus=16 */
236 .config
= SMP_CONFIG_GENERIC(T
, 8, F
, 0, F
, 0, T
, 2, T
, 16),
237 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(8, 8, 1, 2, 16),
238 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(8, 1, 8, 2, 16),
240 /* config: -smp sockets=2,cores=4,threads=2
241 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */
242 .config
= SMP_CONFIG_GENERIC(F
, 0, T
, 2, T
, 4, T
, 2, F
, 0),
243 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
244 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
246 /* config: -smp sockets=2,cores=4,maxcpus=16
247 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */
248 .config
= SMP_CONFIG_GENERIC(F
, 0, T
, 2, T
, 4, F
, 0, T
, 16),
249 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
250 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
252 /* config: -smp sockets=2,threads=2,maxcpus=16
253 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */
254 .config
= SMP_CONFIG_GENERIC(F
, 0, T
, 2, F
, 0, T
, 2, T
, 16),
255 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
256 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
258 /* config: -smp cores=4,threads=2,maxcpus=16
259 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */
260 .config
= SMP_CONFIG_GENERIC(F
, 0, F
, 0, T
, 4, T
, 2, T
, 16),
261 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
262 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
264 /* config: -smp 8,sockets=2,cores=4,threads=1
265 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */
266 .config
= SMP_CONFIG_GENERIC(T
, 8, T
, 2, T
, 4, T
, 1, F
, 0),
267 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
268 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
270 /* config: -smp 8,sockets=2,cores=4,maxcpus=16
271 * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */
272 .config
= SMP_CONFIG_GENERIC(T
, 8, T
, 2, T
, 4, F
, 0, T
, 16),
273 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
274 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
276 /* config: -smp 8,sockets=2,threads=2,maxcpus=16
277 * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */
278 .config
= SMP_CONFIG_GENERIC(T
, 8, T
, 2, F
, 0, T
, 2, T
, 16),
279 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
280 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
282 /* config: -smp 8,cores=4,threads=2,maxcpus=16
283 * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */
284 .config
= SMP_CONFIG_GENERIC(T
, 8, F
, 0, T
, 4, T
, 2, T
, 16),
285 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
286 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
288 /* config: -smp sockets=2,cores=4,threads=2,maxcpus=16
289 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */
290 .config
= SMP_CONFIG_GENERIC(F
, 0, T
, 2, T
, 4, T
, 2, T
, 16),
291 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
292 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
294 /* config: -smp 8,sockets=2,cores=4,threads=2,maxcpus=16
295 * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */
296 .config
= SMP_CONFIG_GENERIC(T
, 8, T
, 2, T
, 4, T
, 2, T
, 16),
297 .expect_prefer_sockets
= CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
298 .expect_prefer_cores
= CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
302 static const struct SMPTestData data_generic_invalid
[] = {
304 /* config: -smp 2,dies=2 */
305 .config
= SMP_CONFIG_WITH_DIES(T
, 2, F
, 0, T
, 2, F
, 0, F
, 0, F
, 0),
306 .expect_error
= "dies not supported by this machine's CPU topology",
308 /* config: -smp 2,clusters=2 */
309 .config
= SMP_CONFIG_WITH_CLUSTERS(T
, 2, F
, 0, T
, 2, F
, 0, F
, 0, F
, 0),
310 .expect_error
= "clusters not supported by this machine's CPU topology",
312 /* config: -smp 8,sockets=2,cores=4,threads=2,maxcpus=8 */
313 .config
= SMP_CONFIG_GENERIC(T
, 8, T
, 2, T
, 4, T
, 2, T
, 8),
314 .expect_error
= "Invalid CPU topology: "
315 "product of the hierarchy must match maxcpus: "
316 "sockets (2) * cores (4) * threads (2) "
319 /* config: -smp 18,sockets=2,cores=4,threads=2,maxcpus=16 */
320 .config
= SMP_CONFIG_GENERIC(T
, 18, T
, 2, T
, 4, T
, 2, T
, 16),
321 .expect_error
= "Invalid CPU topology: "
322 "maxcpus must be equal to or greater than smp: "
323 "sockets (2) * cores (4) * threads (2) "
324 "== maxcpus (16) < smp_cpus (18)",
327 * should tweak the supported min CPUs to 2 for testing */
328 .config
= SMP_CONFIG_GENERIC(T
, 1, F
, 0, F
, 0, F
, 0, F
, 0),
329 .expect_error
= "Invalid SMP CPUs 1. The min CPUs supported "
330 "by machine '" SMP_MACHINE_NAME
"' is 2",
333 * should tweak the supported max CPUs to 511 for testing */
334 .config
= SMP_CONFIG_GENERIC(T
, 512, F
, 0, F
, 0, F
, 0, F
, 0),
335 .expect_error
= "Invalid SMP CPUs 512. The max CPUs supported "
336 "by machine '" SMP_MACHINE_NAME
"' is 511",
340 static const struct SMPTestData data_with_dies_invalid
[] = {
342 /* config: -smp 16,sockets=2,dies=2,cores=4,threads=2,maxcpus=16 */
343 .config
= SMP_CONFIG_WITH_DIES(T
, 16, T
, 2, T
, 2, T
, 4, T
, 2, T
, 16),
344 .expect_error
= "Invalid CPU topology: "
345 "product of the hierarchy must match maxcpus: "
346 "sockets (2) * dies (2) * cores (4) * threads (2) "
349 /* config: -smp 34,sockets=2,dies=2,cores=4,threads=2,maxcpus=32 */
350 .config
= SMP_CONFIG_WITH_DIES(T
, 34, T
, 2, T
, 2, T
, 4, T
, 2, T
, 32),
351 .expect_error
= "Invalid CPU topology: "
352 "maxcpus must be equal to or greater than smp: "
353 "sockets (2) * dies (2) * cores (4) * threads (2) "
354 "== maxcpus (32) < smp_cpus (34)",
358 static const struct SMPTestData data_with_clusters_invalid
[] = {
360 /* config: -smp 16,sockets=2,clusters=2,cores=4,threads=2,maxcpus=16 */
361 .config
= SMP_CONFIG_WITH_CLUSTERS(T
, 16, T
, 2, T
, 2, T
, 4, T
, 2, T
, 16),
362 .expect_error
= "Invalid CPU topology: "
363 "product of the hierarchy must match maxcpus: "
364 "sockets (2) * clusters (2) * cores (4) * threads (2) "
367 /* config: -smp 34,sockets=2,clusters=2,cores=4,threads=2,maxcpus=32 */
368 .config
= SMP_CONFIG_WITH_CLUSTERS(T
, 34, T
, 2, T
, 2, T
, 4, T
, 2, T
, 32),
369 .expect_error
= "Invalid CPU topology: "
370 "maxcpus must be equal to or greater than smp: "
371 "sockets (2) * clusters (2) * cores (4) * threads (2) "
372 "== maxcpus (32) < smp_cpus (34)",
376 static char *smp_config_to_string(const SMPConfiguration
*config
)
378 return g_strdup_printf(
379 "(SMPConfiguration) {\n"
380 " .has_cpus = %5s, cpus = %" PRId64
",\n"
381 " .has_sockets = %5s, sockets = %" PRId64
",\n"
382 " .has_dies = %5s, dies = %" PRId64
",\n"
383 " .has_clusters = %5s, clusters = %" PRId64
",\n"
384 " .has_cores = %5s, cores = %" PRId64
",\n"
385 " .has_threads = %5s, threads = %" PRId64
",\n"
386 " .has_maxcpus = %5s, maxcpus = %" PRId64
",\n"
388 config
->has_cpus
? "true" : "false", config
->cpus
,
389 config
->has_sockets
? "true" : "false", config
->sockets
,
390 config
->has_dies
? "true" : "false", config
->dies
,
391 config
->has_clusters
? "true" : "false", config
->clusters
,
392 config
->has_cores
? "true" : "false", config
->cores
,
393 config
->has_threads
? "true" : "false", config
->threads
,
394 config
->has_maxcpus
? "true" : "false", config
->maxcpus
);
397 static char *cpu_topology_to_string(const CpuTopology
*topo
)
399 return g_strdup_printf(
409 topo
->cpus
, topo
->sockets
, topo
->dies
, topo
->clusters
,
410 topo
->cores
, topo
->threads
, topo
->max_cpus
);
413 static void check_parse(MachineState
*ms
, const SMPConfiguration
*config
,
414 const CpuTopology
*expect_topo
, const char *expect_err
,
417 g_autofree
char *config_str
= smp_config_to_string(config
);
418 g_autofree
char *expect_topo_str
= cpu_topology_to_string(expect_topo
);
419 g_autofree
char *output_topo_str
= NULL
;
422 /* call the generic parser */
423 machine_parse_smp_config(ms
, config
, &err
);
425 output_topo_str
= cpu_topology_to_string(&ms
->smp
);
427 /* when the configuration is supposed to be valid */
430 (ms
->smp
.cpus
== expect_topo
->cpus
) &&
431 (ms
->smp
.sockets
== expect_topo
->sockets
) &&
432 (ms
->smp
.dies
== expect_topo
->dies
) &&
433 (ms
->smp
.clusters
== expect_topo
->clusters
) &&
434 (ms
->smp
.cores
== expect_topo
->cores
) &&
435 (ms
->smp
.threads
== expect_topo
->threads
) &&
436 (ms
->smp
.max_cpus
== expect_topo
->max_cpus
)) {
441 g_printerr("Test smp_parse failed!\n"
442 "Input configuration: %s\n"
443 "Should be valid: yes\n"
444 "Expected topology: %s\n\n"
445 "Result is valid: no\n"
446 "Output error report: %s\n",
447 config_str
, expect_topo_str
, error_get_pretty(err
));
451 g_printerr("Test smp_parse failed!\n"
452 "Input configuration: %s\n"
453 "Should be valid: yes\n"
454 "Expected topology: %s\n\n"
455 "Result is valid: yes\n"
456 "Output topology: %s\n",
457 config_str
, expect_topo_str
, output_topo_str
);
461 /* when the configuration is supposed to be invalid */
463 if (expect_err
== NULL
||
464 g_str_equal(expect_err
, error_get_pretty(err
))) {
469 g_printerr("Test smp_parse failed!\n"
470 "Input configuration: %s\n"
471 "Should be valid: no\n"
472 "Expected error report: %s\n\n"
473 "Result is valid: no\n"
474 "Output error report: %s\n",
475 config_str
, expect_err
, error_get_pretty(err
));
479 g_printerr("Test smp_parse failed!\n"
480 "Input configuration: %s\n"
481 "Should be valid: no\n"
482 "Expected error report: %s\n\n"
483 "Result is valid: yes\n"
484 "Output topology: %s\n",
485 config_str
, expect_err
, output_topo_str
);
495 static void smp_parse_test(MachineState
*ms
, SMPTestData
*data
, bool is_valid
)
497 MachineClass
*mc
= MACHINE_GET_CLASS(ms
);
499 mc
->smp_props
.prefer_sockets
= true;
500 check_parse(ms
, &data
->config
, &data
->expect_prefer_sockets
,
501 data
->expect_error
, is_valid
);
503 mc
->smp_props
.prefer_sockets
= false;
504 check_parse(ms
, &data
->config
, &data
->expect_prefer_cores
,
505 data
->expect_error
, is_valid
);
508 /* The parsed results of the unsupported parameters should be 1 */
509 static void unsupported_params_init(const MachineClass
*mc
, SMPTestData
*data
)
511 if (!mc
->smp_props
.dies_supported
) {
512 data
->expect_prefer_sockets
.dies
= 1;
513 data
->expect_prefer_cores
.dies
= 1;
516 if (!mc
->smp_props
.clusters_supported
) {
517 data
->expect_prefer_sockets
.clusters
= 1;
518 data
->expect_prefer_cores
.clusters
= 1;
522 static void machine_base_class_init(ObjectClass
*oc
, void *data
)
524 MachineClass
*mc
= MACHINE_CLASS(oc
);
526 mc
->min_cpus
= MIN_CPUS
;
527 mc
->max_cpus
= MAX_CPUS
;
529 mc
->name
= g_strdup(SMP_MACHINE_NAME
);
532 static void machine_generic_invalid_class_init(ObjectClass
*oc
, void *data
)
534 MachineClass
*mc
= MACHINE_CLASS(oc
);
536 /* Force invalid min CPUs and max CPUs */
541 static void machine_with_dies_class_init(ObjectClass
*oc
, void *data
)
543 MachineClass
*mc
= MACHINE_CLASS(oc
);
545 mc
->smp_props
.dies_supported
= true;
548 static void machine_with_clusters_class_init(ObjectClass
*oc
, void *data
)
550 MachineClass
*mc
= MACHINE_CLASS(oc
);
552 mc
->smp_props
.clusters_supported
= true;
555 static void test_generic_valid(const void *opaque
)
557 const char *machine_type
= opaque
;
558 Object
*obj
= object_new(machine_type
);
559 MachineState
*ms
= MACHINE(obj
);
560 MachineClass
*mc
= MACHINE_GET_CLASS(obj
);
561 SMPTestData data
= {};
564 for (i
= 0; i
< ARRAY_SIZE(data_generic_valid
); i
++) {
565 data
= data_generic_valid
[i
];
566 unsupported_params_init(mc
, &data
);
568 smp_parse_test(ms
, &data
, true);
570 /* Unsupported parameters can be provided with their values as 1 */
571 data
.config
.has_dies
= true;
572 data
.config
.dies
= 1;
573 smp_parse_test(ms
, &data
, true);
579 static void test_generic_invalid(const void *opaque
)
581 const char *machine_type
= opaque
;
582 Object
*obj
= object_new(machine_type
);
583 MachineState
*ms
= MACHINE(obj
);
584 MachineClass
*mc
= MACHINE_GET_CLASS(obj
);
585 SMPTestData data
= {};
588 for (i
= 0; i
< ARRAY_SIZE(data_generic_invalid
); i
++) {
589 data
= data_generic_invalid
[i
];
590 unsupported_params_init(mc
, &data
);
592 smp_parse_test(ms
, &data
, false);
598 static void test_with_dies(const void *opaque
)
600 const char *machine_type
= opaque
;
601 Object
*obj
= object_new(machine_type
);
602 MachineState
*ms
= MACHINE(obj
);
603 MachineClass
*mc
= MACHINE_GET_CLASS(obj
);
604 SMPTestData data
= {};
605 unsigned int num_dies
= 2;
608 for (i
= 0; i
< ARRAY_SIZE(data_generic_valid
); i
++) {
609 data
= data_generic_valid
[i
];
610 unsupported_params_init(mc
, &data
);
612 /* when dies parameter is omitted, it will be set as 1 */
613 data
.expect_prefer_sockets
.dies
= 1;
614 data
.expect_prefer_cores
.dies
= 1;
616 smp_parse_test(ms
, &data
, true);
618 /* when dies parameter is specified */
619 data
.config
.has_dies
= true;
620 data
.config
.dies
= num_dies
;
621 if (data
.config
.has_cpus
) {
622 data
.config
.cpus
*= num_dies
;
624 if (data
.config
.has_maxcpus
) {
625 data
.config
.maxcpus
*= num_dies
;
628 data
.expect_prefer_sockets
.dies
= num_dies
;
629 data
.expect_prefer_sockets
.cpus
*= num_dies
;
630 data
.expect_prefer_sockets
.max_cpus
*= num_dies
;
631 data
.expect_prefer_cores
.dies
= num_dies
;
632 data
.expect_prefer_cores
.cpus
*= num_dies
;
633 data
.expect_prefer_cores
.max_cpus
*= num_dies
;
635 smp_parse_test(ms
, &data
, true);
638 for (i
= 0; i
< ARRAY_SIZE(data_with_dies_invalid
); i
++) {
639 data
= data_with_dies_invalid
[i
];
640 unsupported_params_init(mc
, &data
);
642 smp_parse_test(ms
, &data
, false);
648 static void test_with_clusters(const void *opaque
)
650 const char *machine_type
= opaque
;
651 Object
*obj
= object_new(machine_type
);
652 MachineState
*ms
= MACHINE(obj
);
653 MachineClass
*mc
= MACHINE_GET_CLASS(obj
);
654 SMPTestData data
= {};
655 unsigned int num_clusters
= 2;
658 for (i
= 0; i
< ARRAY_SIZE(data_generic_valid
); i
++) {
659 data
= data_generic_valid
[i
];
660 unsupported_params_init(mc
, &data
);
662 /* when clusters parameter is omitted, it will be set as 1 */
663 data
.expect_prefer_sockets
.clusters
= 1;
664 data
.expect_prefer_cores
.clusters
= 1;
666 smp_parse_test(ms
, &data
, true);
668 /* when clusters parameter is specified */
669 data
.config
.has_clusters
= true;
670 data
.config
.clusters
= num_clusters
;
671 if (data
.config
.has_cpus
) {
672 data
.config
.cpus
*= num_clusters
;
674 if (data
.config
.has_maxcpus
) {
675 data
.config
.maxcpus
*= num_clusters
;
678 data
.expect_prefer_sockets
.clusters
= num_clusters
;
679 data
.expect_prefer_sockets
.cpus
*= num_clusters
;
680 data
.expect_prefer_sockets
.max_cpus
*= num_clusters
;
681 data
.expect_prefer_cores
.clusters
= num_clusters
;
682 data
.expect_prefer_cores
.cpus
*= num_clusters
;
683 data
.expect_prefer_cores
.max_cpus
*= num_clusters
;
685 smp_parse_test(ms
, &data
, true);
688 for (i
= 0; i
< ARRAY_SIZE(data_with_clusters_invalid
); i
++) {
689 data
= data_with_clusters_invalid
[i
];
690 unsupported_params_init(mc
, &data
);
692 smp_parse_test(ms
, &data
, false);
698 /* Type info of the tested machine */
699 static const TypeInfo smp_machine_types
[] = {
701 .name
= TYPE_MACHINE
,
702 .parent
= TYPE_OBJECT
,
704 .class_init
= machine_base_class_init
,
705 .class_size
= sizeof(MachineClass
),
706 .instance_size
= sizeof(MachineState
),
708 .name
= MACHINE_TYPE_NAME("smp-generic-valid"),
709 .parent
= TYPE_MACHINE
,
711 .name
= MACHINE_TYPE_NAME("smp-generic-invalid"),
712 .parent
= TYPE_MACHINE
,
713 .class_init
= machine_generic_invalid_class_init
,
715 .name
= MACHINE_TYPE_NAME("smp-with-dies"),
716 .parent
= TYPE_MACHINE
,
717 .class_init
= machine_with_dies_class_init
,
719 .name
= MACHINE_TYPE_NAME("smp-with-clusters"),
720 .parent
= TYPE_MACHINE
,
721 .class_init
= machine_with_clusters_class_init
,
725 DEFINE_TYPES(smp_machine_types
)
727 int main(int argc
, char *argv
[])
729 module_call_init(MODULE_INIT_QOM
);
731 g_test_init(&argc
, &argv
, NULL
);
733 g_test_add_data_func("/test-smp-parse/generic/valid",
734 MACHINE_TYPE_NAME("smp-generic-valid"),
736 g_test_add_data_func("/test-smp-parse/generic/invalid",
737 MACHINE_TYPE_NAME("smp-generic-invalid"),
738 test_generic_invalid
);
739 g_test_add_data_func("/test-smp-parse/with_dies",
740 MACHINE_TYPE_NAME("smp-with-dies"),
742 g_test_add_data_func("/test-smp-parse/with_clusters",
743 MACHINE_TYPE_NAME("smp-with-clusters"),