vdpa: add vdpa-dev support
[qemu/kevin.git] / tests / unit / test-smp-parse.c
blobfdc39a846ca608d2207d029ecd6dd0a7fc6293c2
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 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) \
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, \
78 /**
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;
92 } SMPTestData;
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),
107 }, {
108 /* config: -smp 8
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),
114 }, {
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),
120 }, {
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),
126 }, {
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),
132 }, {
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),
139 }, {
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),
145 }, {
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),
151 }, {
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),
158 }, {
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),
165 }, {
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),
171 }, {
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),
177 }, {
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),
183 }, {
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),
189 }, {
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),
195 }, {
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),
202 }, {
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),
208 }, {
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),
214 }, {
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),
220 }, {
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),
226 }, {
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),
232 }, {
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),
239 }, {
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),
245 }, {
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),
251 }, {
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),
257 }, {
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),
263 }, {
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),
269 }, {
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),
275 }, {
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),
281 }, {
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),
287 }, {
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),
293 }, {
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",
307 }, {
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",
311 }, {
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) "
317 "!= maxcpus (8)",
318 }, {
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)",
325 }, {
326 /* config: -smp 1
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",
331 }, {
332 /* config: -smp 512
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) "
347 "!= maxcpus (16)",
348 }, {
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) "
365 "!= maxcpus (16)",
366 }, {
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"
387 "}",
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(
400 "(CpuTopology) {\n"
401 " .cpus = %u,\n"
402 " .sockets = %u,\n"
403 " .dies = %u,\n"
404 " .clusters = %u,\n"
405 " .cores = %u,\n"
406 " .threads = %u,\n"
407 " .max_cpus = %u,\n"
408 "}",
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,
415 bool is_valid)
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;
420 Error *err = 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 */
428 if (is_valid) {
429 if ((err == NULL) &&
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)) {
437 return;
440 if (err != NULL) {
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));
448 goto end;
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);
458 goto end;
461 /* when the configuration is supposed to be invalid */
462 if (err != NULL) {
463 if (expect_err == NULL ||
464 g_str_equal(expect_err, error_get_pretty(err))) {
465 error_free(err);
466 return;
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));
476 goto end;
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);
487 end:
488 if (err != NULL) {
489 error_free(err);
492 abort();
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 */
537 mc->min_cpus = 2;
538 mc->max_cpus = 511;
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 = {};
562 int i;
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);
576 object_unref(obj);
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 = {};
586 int i;
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);
595 object_unref(obj);
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;
606 int i;
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);
645 object_unref(obj);
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;
656 int i;
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);
695 object_unref(obj);
698 /* Type info of the tested machine */
699 static const TypeInfo smp_machine_types[] = {
701 .name = TYPE_MACHINE,
702 .parent = TYPE_OBJECT,
703 .abstract = true,
704 .class_init = machine_base_class_init,
705 .class_size = sizeof(MachineClass),
706 .instance_size = sizeof(MachineState),
707 }, {
708 .name = MACHINE_TYPE_NAME("smp-generic-valid"),
709 .parent = TYPE_MACHINE,
710 }, {
711 .name = MACHINE_TYPE_NAME("smp-generic-invalid"),
712 .parent = TYPE_MACHINE,
713 .class_init = machine_generic_invalid_class_init,
714 }, {
715 .name = MACHINE_TYPE_NAME("smp-with-dies"),
716 .parent = TYPE_MACHINE,
717 .class_init = machine_with_dies_class_init,
718 }, {
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"),
735 test_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"),
741 test_with_dies);
742 g_test_add_data_func("/test-smp-parse/with_clusters",
743 MACHINE_TYPE_NAME("smp-with-clusters"),
744 test_with_clusters);
746 g_test_run();
748 return 0;