1 /*
2 * SMP parsing unit-tests
3 *
4 * Copyright (c) 2021 Huawei Technologies Co., Ltd
5 *
6 * Authors:
7 * Yanan Wang <wangyanan55@huawei.com>
8 *
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.
11 */
12
13 #include "qemu/osdep.h"
14 #include "qom/object.h"
15 #include "qemu/module.h"
16 #include "qapi/error.h"
17
18 #include "hw/boards.h"
19
20 #define T true
21 #define F false
22
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 */
25
26 #define SMP_MACHINE_NAME "TEST-SMP"
27
28 /*
29 * Used to define the generic 3-level CPU topology hierarchy
30 * -sockets/cores/threads
31 */
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, \
39 }
40
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, \
48 }
49
50 /*
51 * Currently a 4-level topology hierarchy is supported on PC machines
52 * -sockets/dies/cores/threads
53 */
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, \
62 }
63
64 /*
65 * Currently a 4-level topology hierarchy is supported on ARM virt machines
66 * -sockets/clusters/cores/threads
67 */
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, \
76 }
77
78 /*
79 * Currently a 5-level topology hierarchy is supported on s390 ccw machines
80 * -drawers/books/sockets/cores/threads
81 */
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, \
92 }
93
94 /*
95 * Currently QEMU supports up to a 7-level topology hierarchy, which is the
96 * QEMU's unified abstract representation of CPU topology.
97 * -drawers/books/sockets/dies/clusters/cores/threads
98 */
99 #define SMP_CONFIG_WITH_FULL_TOPO(a, b, c, d, e, f, g, h, i) \
100 { \
101 .has_cpus = true, .cpus = a, \
102 .has_drawers = true, .drawers = b, \
103 .has_books = true, .books = c, \
104 .has_sockets = true, .sockets = d, \
105 .has_dies = true, .dies = e, \
106 .has_clusters = true, .clusters = f, \
107 .has_cores = true, .cores = g, \
108 .has_threads = true, .threads = h, \
109 .has_maxcpus = true, .maxcpus = i, \
110 }
111
112 /**
113 * @config - the given SMP configuration
114 * @expect_prefer_sockets - the expected parsing result for the
115 * valid configuration, when sockets are preferred over cores
116 * @expect_prefer_cores - the expected parsing result for the
117 * valid configuration, when cores are preferred over sockets
118 * @expect_error - the expected error report when the given
119 * configuration is invalid
120 */
121 typedef struct SMPTestData {
122 SMPConfiguration config;
123 CpuTopology expect_prefer_sockets;
124 CpuTopology expect_prefer_cores;
125 const char *expect_error;
126 } SMPTestData;
127
128 /*
129 * List all the possible valid sub-collections of the generic 5
130 * topology parameters (i.e. cpus/maxcpus/sockets/cores/threads),
131 * then test the automatic calculation algorithm of the missing
132 * values in the parser.
133 */
134 static const struct SMPTestData data_generic_valid[] = {
135 {
136 /* config: no configuration provided
137 * expect: cpus=1,sockets=1,cores=1,threads=1,maxcpus=1 */
138 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, F, 0, F, 0),
139 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(1, 1, 1, 1, 1),
140 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(1, 1, 1, 1, 1),
141 }, {
142 /* config: -smp 8
143 * prefer_sockets: cpus=8,sockets=8,cores=1,threads=1,maxcpus=8
144 * prefer_cores: cpus=8,sockets=1,cores=8,threads=1,maxcpus=8 */
145 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, F, 0, F, 0),
146 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 8, 1, 1, 8),
147 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 8, 1, 8),
148 }, {
149 /* config: -smp sockets=2
150 * expect: cpus=2,sockets=2,cores=1,threads=1,maxcpus=2 */
151 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, F, 0, F, 0),
152 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(2, 2, 1, 1, 2),
153 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(2, 2, 1, 1, 2),
154 }, {
155 /* config: -smp cores=4
156 * expect: cpus=4,sockets=1,cores=4,threads=1,maxcpus=4 */
157 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, F, 0, F, 0),
158 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(4, 1, 4, 1, 4),
159 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(4, 1, 4, 1, 4),
160 }, {
161 /* config: -smp threads=2
162 * expect: cpus=2,sockets=1,cores=1,threads=2,maxcpus=2 */
163 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, T, 2, F, 0),
164 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(2, 1, 1, 2, 2),
165 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(2, 1, 1, 2, 2),
166 }, {
167 /* config: -smp maxcpus=16
168 * prefer_sockets: cpus=16,sockets=16,cores=1,threads=1,maxcpus=16
169 * prefer_cores: cpus=16,sockets=1,cores=16,threads=1,maxcpus=16 */
170 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, F, 0, T, 16),
171 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 16, 1, 1, 16),
172 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 1, 16, 1, 16),
173 }, {
174 /* config: -smp 8,sockets=2
175 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */
176 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, F, 0, F, 0),
177 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
178 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
179 }, {
180 /* config: -smp 8,cores=4
181 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */
182 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, F, 0, F, 0),
183 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
184 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
185 }, {
186 /* config: -smp 8,threads=2
187 * prefer_sockets: cpus=8,sockets=4,cores=1,threads=2,maxcpus=8
188 * prefer_cores: cpus=8,sockets=1,cores=4,threads=2,maxcpus=8 */
189 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, T, 2, F, 0),
190 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 4, 1, 2, 8),
191 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8),
192 }, {
193 /* config: -smp 8,maxcpus=16
194 * prefer_sockets: cpus=8,sockets=16,cores=1,threads=1,maxcpus=16
195 * prefer_cores: cpus=8,sockets=1,cores=16,threads=1,maxcpus=16 */
196 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, F, 0, T, 16),
197 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 16, 1, 1, 16),
198 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 16, 1, 16),
199 }, {
200 /* config: -smp sockets=2,cores=4
201 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */
202 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, F, 0, F, 0),
203 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
204 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
205 }, {
206 /* config: -smp sockets=2,threads=2
207 * expect: cpus=4,sockets=2,cores=1,threads=2,maxcpus=4 */
208 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, T, 2, F, 0),
209 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(4, 2, 1, 2, 4),
210 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(4, 2, 1, 2, 4),
211 }, {
212 /* config: -smp sockets=2,maxcpus=16
213 * expect: cpus=16,sockets=2,cores=8,threads=1,maxcpus=16 */
214 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, F, 0, T, 16),
215 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 8, 1, 16),
216 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 8, 1, 16),
217 }, {
218 /* config: -smp cores=4,threads=2
219 * expect: cpus=8,sockets=1,cores=4,threads=2,maxcpus=8 */
220 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, T, 2, F, 0),
221 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8),
222 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8),
223 }, {
224 /* config: -smp cores=4,maxcpus=16
225 * expect: cpus=16,sockets=4,cores=4,threads=1,maxcpus=16 */
226 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, F, 0, T, 16),
227 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 4, 4, 1, 16),
228 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 4, 4, 1, 16),
229 }, {
230 /* config: -smp threads=2,maxcpus=16
231 * prefer_sockets: cpus=16,sockets=8,cores=1,threads=2,maxcpus=16
232 * prefer_cores: cpus=16,sockets=1,cores=8,threads=2,maxcpus=16 */
233 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, T, 2, T, 16),
234 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 8, 1, 2, 16),
235 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 1, 8, 2, 16),
236 }, {
237 /* config: -smp 8,sockets=2,cores=4
238 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */
239 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, F, 0, F, 0),
240 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
241 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
242 }, {
243 /* config: -smp 8,sockets=2,threads=2
244 * expect: cpus=8,sockets=2,cores=2,threads=2,maxcpus=8 */
245 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, T, 2, F, 0),
246 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 2, 2, 8),
247 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 2, 2, 8),
248 }, {
249 /* config: -smp 8,sockets=2,maxcpus=16
250 * expect: cpus=8,sockets=2,cores=8,threads=1,maxcpus=16 */
251 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, F, 0, T, 16),
252 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 8, 1, 16),
253 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 8, 1, 16),
254 }, {
255 /* config: -smp 8,cores=4,threads=2
256 * expect: cpus=8,sockets=1,cores=4,threads=2,maxcpus=8 */
257 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, T, 2, F, 0),
258 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8),
259 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8),
260 }, {
261 /* config: -smp 8,cores=4,maxcpus=16
262 * expect: cpus=8,sockets=4,cores=4,threads=1,maxcpus=16 */
263 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, F, 0, T, 16),
264 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 4, 4, 1, 16),
265 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 4, 4, 1, 16),
266 }, {
267 /* config: -smp 8,threads=2,maxcpus=16
268 * prefer_sockets: cpus=8,sockets=8,cores=1,threads=2,maxcpus=16
269 * prefer_cores: cpus=8,sockets=1,cores=8,threads=2,maxcpus=16 */
270 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, T, 2, T, 16),
271 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 8, 1, 2, 16),
272 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 8, 2, 16),
273 }, {
274 /* config: -smp sockets=2,cores=4,threads=2
275 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */
276 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, T, 2, F, 0),
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 sockets=2,cores=4,maxcpus=16
281 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */
282 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, F, 0, T, 16),
283 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
284 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
285 }, {
286 /* config: -smp sockets=2,threads=2,maxcpus=16
287 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */
288 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, T, 2, T, 16),
289 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
290 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
291 }, {
292 /* config: -smp cores=4,threads=2,maxcpus=16
293 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */
294 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, T, 2, T, 16),
295 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
296 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
297 }, {
298 /* config: -smp 8,sockets=2,cores=4,threads=1
299 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */
300 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 1, F, 0),
301 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
302 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
303 }, {
304 /* config: -smp 8,sockets=2,cores=4,maxcpus=16
305 * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */
306 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, F, 0, T, 16),
307 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
308 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
309 }, {
310 /* config: -smp 8,sockets=2,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, F, 0, 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),
315 }, {
316 /* config: -smp 8,cores=4,threads=2,maxcpus=16
317 * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */
318 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, T, 2, T, 16),
319 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
320 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
321 }, {
322 /* config: -smp sockets=2,cores=4,threads=2,maxcpus=16
323 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */
324 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, T, 2, T, 16),
325 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
326 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
327 }, {
328 /* config: -smp 8,sockets=2,cores=4,threads=2,maxcpus=16
329 * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */
330 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 2, T, 16),
331 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
332 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
333 }, {
334 /*
335 * Unsupported parameters are always allowed to be set to '1'
336 * config: -smp 8,books=1,drawers=1,sockets=2,modules=1,dies=1,cores=2,threads=2,maxcpus=8
337 * expect: cpus=8,sockets=2,cores=2,threads=2,maxcpus=8 */
338 .config = SMP_CONFIG_WITH_FULL_TOPO(8, 1, 1, 2, 1, 1, 2, 2, 8),
339 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 2, 2, 8),
340 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 2, 2, 8),
341 },
342 };
343
344 static const struct SMPTestData data_generic_invalid[] = {
345 {
346 /* config: -smp 2,dies=2 */
347 .config = SMP_CONFIG_WITH_DIES(T, 2, F, 0, T, 2, F, 0, F, 0, F, 0),
348 .expect_error = "dies > 1 not supported by this machine's CPU topology",
349 }, {
350 /* config: -smp 2,clusters=2 */
351 .config = SMP_CONFIG_WITH_CLUSTERS(T, 2, F, 0, T, 2, F, 0, F, 0, F, 0),
352 .expect_error = "clusters > 1 not supported by this machine's CPU topology",
353 }, {
354 /* config: -smp 2,books=2 */
355 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 2, F, 0, T, 2, F,
356 0, F, 0, F, 0, F, 0),
357 .expect_error = "books > 1 not supported by this machine's CPU topology",
358 }, {
359 /* config: -smp 2,drawers=2 */
360 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 2, T, 2, F, 0, F,
361 0, F, 0, F, 0, F, 0),
362 .expect_error = "drawers > 1 not supported by this machine's CPU topology",
363 }, {
364 /* config: -smp 8,sockets=2,cores=4,threads=2,maxcpus=8 */
365 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 2, T, 8),
366 .expect_error = "Invalid CPU topology: "
367 "product of the hierarchy must match maxcpus: "
368 "sockets (2) * cores (4) * threads (2) "
369 "!= maxcpus (8)",
370 }, {
371 /* config: -smp 18,sockets=2,cores=4,threads=2,maxcpus=16 */
372 .config = SMP_CONFIG_GENERIC(T, 18, T, 2, T, 4, T, 2, T, 16),
373 .expect_error = "Invalid CPU topology: "
374 "maxcpus must be equal to or greater than smp: "
375 "sockets (2) * cores (4) * threads (2) "
376 "== maxcpus (16) < smp_cpus (18)",
377 }, {
378 /*
379 * config: -smp 1
380 * The test machine should tweak the supported min CPUs to
381 * 2 (MIN_CPUS + 1) for testing.
382 */
383 .config = SMP_CONFIG_GENERIC(T, MIN_CPUS, F, 0, F, 0, F, 0, F, 0),
384 .expect_error = "Invalid SMP CPUs 1. The min CPUs supported "
385 "by machine '" SMP_MACHINE_NAME "' is 2",
386 }, {
387 /*
388 * config: -smp 4096
389 * The test machine should tweak the supported max CPUs to
390 * 4095 (MAX_CPUS - 1) for testing.
391 */
392 .config = SMP_CONFIG_GENERIC(T, 4096, F, 0, F, 0, F, 0, F, 0),
393 .expect_error = "Invalid SMP CPUs 4096. The max CPUs supported "
394 "by machine '" SMP_MACHINE_NAME "' is 4095",
395 },
396 };
397
398 static const struct SMPTestData data_with_dies_invalid[] = {
399 {
400 /* config: -smp 16,sockets=2,dies=2,cores=4,threads=2,maxcpus=16 */
401 .config = SMP_CONFIG_WITH_DIES(T, 16, T, 2, T, 2, T, 4, T, 2, T, 16),
402 .expect_error = "Invalid CPU topology: "
403 "product of the hierarchy must match maxcpus: "
404 "sockets (2) * dies (2) * cores (4) * threads (2) "
405 "!= maxcpus (16)",
406 }, {
407 /* config: -smp 34,sockets=2,dies=2,cores=4,threads=2,maxcpus=32 */
408 .config = SMP_CONFIG_WITH_DIES(T, 34, T, 2, T, 2, T, 4, T, 2, T, 32),
409 .expect_error = "Invalid CPU topology: "
410 "maxcpus must be equal to or greater than smp: "
411 "sockets (2) * dies (2) * cores (4) * threads (2) "
412 "== maxcpus (32) < smp_cpus (34)",
413 },
414 };
415
416 static const struct SMPTestData data_with_clusters_invalid[] = {
417 {
418 /* config: -smp 16,sockets=2,clusters=2,cores=4,threads=2,maxcpus=16 */
419 .config = SMP_CONFIG_WITH_CLUSTERS(T, 16, T, 2, T, 2, T, 4, T, 2, T, 16),
420 .expect_error = "Invalid CPU topology: "
421 "product of the hierarchy must match maxcpus: "
422 "sockets (2) * clusters (2) * cores (4) * threads (2) "
423 "!= maxcpus (16)",
424 }, {
425 /* config: -smp 34,sockets=2,clusters=2,cores=4,threads=2,maxcpus=32 */
426 .config = SMP_CONFIG_WITH_CLUSTERS(T, 34, T, 2, T, 2, T, 4, T, 2, T, 32),
427 .expect_error = "Invalid CPU topology: "
428 "maxcpus must be equal to or greater than smp: "
429 "sockets (2) * clusters (2) * cores (4) * threads (2) "
430 "== maxcpus (32) < smp_cpus (34)",
431 },
432 };
433
434 static const struct SMPTestData data_with_books_invalid[] = {
435 {
436 /* config: -smp 16,books=2,sockets=2,cores=4,threads=2,maxcpus=16 */
437 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 16, F, 1, T, 2, T,
438 2, T, 4, T, 2, T, 16),
439 .expect_error = "Invalid CPU topology: "
440 "product of the hierarchy must match maxcpus: "
441 "books (2) * sockets (2) * cores (4) * threads (2) "
442 "!= maxcpus (16)",
443 }, {
444 /* config: -smp 34,books=2,sockets=2,cores=4,threads=2,maxcpus=32 */
445 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 34, F, 1, T, 2, T,
446 2, T, 4, T, 2, T, 32),
447 .expect_error = "Invalid CPU topology: "
448 "maxcpus must be equal to or greater than smp: "
449 "books (2) * sockets (2) * cores (4) * threads (2) "
450 "== maxcpus (32) < smp_cpus (34)",
451 },
452 };
453
454 static const struct SMPTestData data_with_drawers_invalid[] = {
455 {
456 /* config: -smp 16,drawers=2,sockets=2,cores=4,threads=2,maxcpus=16 */
457 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 16, T, 2, F, 1, T,
458 2, T, 4, T, 2, T, 16),
459 .expect_error = "Invalid CPU topology: "
460 "product of the hierarchy must match maxcpus: "
461 "drawers (2) * sockets (2) * cores (4) * threads (2) "
462 "!= maxcpus (16)",
463 }, {
464 /* config: -smp 34,drawers=2,sockets=2,cores=4,threads=2,maxcpus=32 */
465 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 34, T, 2, F, 1, T,
466 2, T, 4, T, 2, T, 32),
467 .expect_error = "Invalid CPU topology: "
468 "maxcpus must be equal to or greater than smp: "
469 "drawers (2) * sockets (2) * cores (4) * threads (2) "
470 "== maxcpus (32) < smp_cpus (34)",
471 },
472 };
473
474 static const struct SMPTestData data_with_drawers_books_invalid[] = {
475 {
476 /*
477 * config: -smp 200,drawers=2,books=2,sockets=2,cores=4,\
478 * threads=2,maxcpus=200
479 */
480 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 200, T, 3, T, 5, T,
481 2, T, 4, T, 2, T, 200),
482 .expect_error = "Invalid CPU topology: "
483 "product of the hierarchy must match maxcpus: "
484 "drawers (3) * books (5) * sockets (2) * "
485 "cores (4) * threads (2) != maxcpus (200)",
486 }, {
487 /*
488 * config: -smp 242,drawers=2,books=2,sockets=2,cores=4,\
489 * threads=2,maxcpus=240
490 */
491 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 242, T, 3, T, 5, T,
492 2, T, 4, T, 2, T, 240),
493 .expect_error = "Invalid CPU topology: "
494 "maxcpus must be equal to or greater than smp: "
495 "drawers (3) * books (5) * sockets (2) * "
496 "cores (4) * threads (2) "
497 "== maxcpus (240) < smp_cpus (242)",
498 },
499 };
500
501 static const struct SMPTestData data_full_topo_invalid[] = {
502 {
503 /*
504 * config: -smp 200,drawers=3,books=5,sockets=2,dies=4,\
505 * clusters=2,cores=7,threads=2,maxcpus=200
506 */
507 .config = SMP_CONFIG_WITH_FULL_TOPO(200, 3, 5, 2, 4, 2, 7, 2, 200),
508 .expect_error = "Invalid CPU topology: "
509 "product of the hierarchy must match maxcpus: "
510 "drawers (3) * books (5) * sockets (2) * dies (4) * "
511 "clusters (2) * cores (7) * threads (2) "
512 "!= maxcpus (200)",
513 }, {
514 /*
515 * config: -smp 3361,drawers=3,books=5,sockets=2,dies=4,\
516 * clusters=2,cores=7,threads=2,maxcpus=3360
517 */
518 .config = SMP_CONFIG_WITH_FULL_TOPO(3361, 3, 5, 2, 4, 2, 7, 2, 3360),
519 .expect_error = "Invalid CPU topology: "
520 "maxcpus must be equal to or greater than smp: "
521 "drawers (3) * books (5) * sockets (2) * dies (4) * "
522 "clusters (2) * cores (7) * threads (2) "
523 "== maxcpus (3360) < smp_cpus (3361)",
524 }, {
525 /*
526 * config: -smp 1,drawers=3,books=5,sockets=2,dies=4,\
527 * clusters=2,cores=7,threads=3,maxcpus=5040
528 */
529 .config = SMP_CONFIG_WITH_FULL_TOPO(3361, 3, 5, 2, 4, 2, 7, 3, 5040),
530 .expect_error = "Invalid SMP CPUs 5040. The max CPUs supported "
531 "by machine '" SMP_MACHINE_NAME "' is 4096",
532 },
533 };
534
535 static const struct SMPTestData data_zero_topo_invalid[] = {
536 {
537 /*
538 * Test "cpus=0".
539 * config: -smp 0,drawers=1,books=1,sockets=1,dies=1,\
540 * clusters=1,cores=1,threads=1,maxcpus=1
541 */
542 .config = SMP_CONFIG_WITH_FULL_TOPO(0, 1, 1, 1, 1, 1, 1, 1, 1),
543 .expect_error = "Invalid CPU topology: CPU topology parameters must "
544 "be greater than zero",
545 }, {
546 /*
547 * Test "drawers=0".
548 * config: -smp 1,drawers=0,books=1,sockets=1,dies=1,\
549 * clusters=1,cores=1,threads=1,maxcpus=1
550 */
551 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 0, 1, 1, 1, 1, 1, 1, 1),
552 .expect_error = "Invalid CPU topology: CPU topology parameters must "
553 "be greater than zero",
554 }, {
555 /*
556 * Test "books=0".
557 * config: -smp 1,drawers=1,books=0,sockets=1,dies=1,\
558 * clusters=1,cores=1,threads=1,maxcpus=1
559 */
560 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 0, 1, 1, 1, 1, 1, 1),
561 .expect_error = "Invalid CPU topology: CPU topology parameters must "
562 "be greater than zero",
563 }, {
564 /*
565 * Test "sockets=0".
566 * config: -smp 1,drawers=1,books=1,sockets=0,dies=1,\
567 * clusters=1,cores=1,threads=1,maxcpus=1
568 */
569 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 0, 1, 1, 1, 1, 1),
570 .expect_error = "Invalid CPU topology: CPU topology parameters must "
571 "be greater than zero",
572 }, {
573 /*
574 * Test "dies=0".
575 * config: -smp 1,drawers=1,books=1,sockets=1,dies=0,\
576 * clusters=1,cores=1,threads=1,maxcpus=1
577 */
578 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 1, 0, 1, 1, 1, 1),
579 .expect_error = "Invalid CPU topology: CPU topology parameters must "
580 "be greater than zero",
581 }, {
582 /*
583 * Test "clusters=0".
584 * config: -smp 1,drawers=1,books=1,sockets=1,dies=1,\
585 * clusters=0,cores=1,threads=1,maxcpus=1
586 */
587 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 1, 1, 0, 1, 1, 1),
588 .expect_error = "Invalid CPU topology: CPU topology parameters must "
589 "be greater than zero",
590 }, {
591 /*
592 * Test "cores=0".
593 * config: -smp 1,drawers=1,books=1,sockets=1,dies=1,\
594 * clusters=1,cores=0,threads=1,maxcpus=1
595 */
596 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 1, 1, 1, 0, 1, 1),
597 .expect_error = "Invalid CPU topology: CPU topology parameters must "
598 "be greater than zero",
599 }, {
600 /*
601 * Test "threads=0".
602 * config: -smp 1,drawers=1,books=1,sockets=1,dies=1,\
603 * clusters=1,cores=1,threads=0,maxcpus=1
604 */
605 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 1, 1, 1, 1, 0, 1),
606 .expect_error = "Invalid CPU topology: CPU topology parameters must "
607 "be greater than zero",
608 }, {
609 /*
610 * Test "maxcpus=0".
611 * config: -smp 1,drawers=1,books=1,sockets=1,dies=1,\
612 * clusters=1,cores=1,threads=1,maxcpus=0
613 */
614 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 1, 1, 1, 1, 1, 0),
615 .expect_error = "Invalid CPU topology: CPU topology parameters must "
616 "be greater than zero",
617 },
618 };
619
smp_config_to_string(const SMPConfiguration * config)620 static char *smp_config_to_string(const SMPConfiguration *config)
621 {
622 return g_strdup_printf(
623 "(SMPConfiguration) {\n"
624 " .has_cpus = %5s, cpus = %" PRId64 ",\n"
625 " .has_drawers = %5s, drawers = %" PRId64 ",\n"
626 " .has_books = %5s, books = %" PRId64 ",\n"
627 " .has_sockets = %5s, sockets = %" PRId64 ",\n"
628 " .has_dies = %5s, dies = %" PRId64 ",\n"
629 " .has_clusters = %5s, clusters = %" PRId64 ",\n"
630 " .has_cores = %5s, cores = %" PRId64 ",\n"
631 " .has_threads = %5s, threads = %" PRId64 ",\n"
632 " .has_maxcpus = %5s, maxcpus = %" PRId64 ",\n"
633 "}",
634 config->has_cpus ? "true" : "false", config->cpus,
635 config->has_drawers ? "true" : "false", config->drawers,
636 config->has_books ? "true" : "false", config->books,
637 config->has_sockets ? "true" : "false", config->sockets,
638 config->has_dies ? "true" : "false", config->dies,
639 config->has_clusters ? "true" : "false", config->clusters,
640 config->has_cores ? "true" : "false", config->cores,
641 config->has_threads ? "true" : "false", config->threads,
642 config->has_maxcpus ? "true" : "false", config->maxcpus);
643 }
644
645 /* Use the different calculation than machine_topo_get_threads_per_socket(). */
cpu_topology_get_threads_per_socket(const CpuTopology * topo)646 static unsigned int cpu_topology_get_threads_per_socket(const CpuTopology *topo)
647 {
648 /* Check the divisor to avoid invalid topology examples causing SIGFPE. */
649 if (!topo->drawers || !topo->books || !topo->sockets) {
650 return 0;
651 } else {
652 return topo->max_cpus / topo->drawers / topo->books / topo->sockets;
653 }
654 }
655
656 /* Use the different calculation than machine_topo_get_cores_per_socket(). */
cpu_topology_get_cores_per_socket(const CpuTopology * topo)657 static unsigned int cpu_topology_get_cores_per_socket(const CpuTopology *topo)
658 {
659 /* Check the divisor to avoid invalid topology examples causing SIGFPE. */
660 if (!topo->threads) {
661 return 0;
662 } else {
663 return cpu_topology_get_threads_per_socket(topo) / topo->threads;
664 }
665 }
666
cpu_topology_to_string(const CpuTopology * topo,unsigned int threads_per_socket,unsigned int cores_per_socket,bool has_clusters)667 static char *cpu_topology_to_string(const CpuTopology *topo,
668 unsigned int threads_per_socket,
669 unsigned int cores_per_socket,
670 bool has_clusters)
671 {
672 return g_strdup_printf(
673 "(CpuTopology) {\n"
674 " .cpus = %u,\n"
675 " .drawers = %u,\n"
676 " .books = %u,\n"
677 " .sockets = %u,\n"
678 " .dies = %u,\n"
679 " .clusters = %u,\n"
680 " .cores = %u,\n"
681 " .threads = %u,\n"
682 " .max_cpus = %u,\n"
683 " .threads_per_socket = %u,\n"
684 " .cores_per_socket = %u,\n"
685 " .has_clusters = %s,\n"
686 "}",
687 topo->cpus, topo->drawers, topo->books,
688 topo->sockets, topo->dies, topo->clusters,
689 topo->cores, topo->threads, topo->max_cpus,
690 threads_per_socket, cores_per_socket,
691 has_clusters ? "true" : "false");
692 }
693
check_parse(MachineState * ms,const SMPConfiguration * config,const CpuTopology * expect_topo,const char * expect_err,bool is_valid)694 static void check_parse(MachineState *ms, const SMPConfiguration *config,
695 const CpuTopology *expect_topo, const char *expect_err,
696 bool is_valid)
697 {
698 MachineClass *mc = MACHINE_GET_CLASS(ms);
699 g_autofree char *config_str = smp_config_to_string(config);
700 g_autofree char *expect_topo_str = NULL, *output_topo_str = NULL;
701 unsigned int expect_threads_per_socket, expect_cores_per_socket;
702 unsigned int ms_threads_per_socket, ms_cores_per_socket;
703 Error *err = NULL;
704
705 expect_threads_per_socket =
706 cpu_topology_get_threads_per_socket(expect_topo);
707 expect_cores_per_socket =
708 cpu_topology_get_cores_per_socket(expect_topo);
709 expect_topo_str = cpu_topology_to_string(expect_topo,
710 expect_threads_per_socket,
711 expect_cores_per_socket,
712 config->has_clusters);
713
714 /* call the generic parser */
715 machine_parse_smp_config(ms, config, &err);
716
717 ms_threads_per_socket = machine_topo_get_threads_per_socket(ms);
718 ms_cores_per_socket = machine_topo_get_cores_per_socket(ms);
719 output_topo_str = cpu_topology_to_string(&ms->smp,
720 ms_threads_per_socket,
721 ms_cores_per_socket,
722 mc->smp_props.has_clusters);
723
724 /* when the configuration is supposed to be valid */
725 if (is_valid) {
726 if ((err == NULL) &&
727 (ms->smp.cpus == expect_topo->cpus) &&
728 (ms->smp.drawers == expect_topo->drawers) &&
729 (ms->smp.books == expect_topo->books) &&
730 (ms->smp.sockets == expect_topo->sockets) &&
731 (ms->smp.dies == expect_topo->dies) &&
732 (ms->smp.clusters == expect_topo->clusters) &&
733 (ms->smp.cores == expect_topo->cores) &&
734 (ms->smp.threads == expect_topo->threads) &&
735 (ms->smp.max_cpus == expect_topo->max_cpus) &&
736 (ms_threads_per_socket == expect_threads_per_socket) &&
737 (ms_cores_per_socket == expect_cores_per_socket) &&
738 (mc->smp_props.has_clusters == config->has_clusters)) {
739 return;
740 }
741
742 if (err != NULL) {
743 g_printerr("Test smp_parse failed!\n"
744 "Input configuration: %s\n"
745 "Should be valid: yes\n"
746 "Expected topology: %s\n\n"
747 "Result is valid: no\n"
748 "Output error report: %s\n",
749 config_str, expect_topo_str, error_get_pretty(err));
750 goto end;
751 }
752
753 g_printerr("Test smp_parse failed!\n"
754 "Input configuration: %s\n"
755 "Should be valid: yes\n"
756 "Expected topology: %s\n\n"
757 "Result is valid: yes\n"
758 "Output topology: %s\n",
759 config_str, expect_topo_str, output_topo_str);
760 goto end;
761 }
762
763 /* when the configuration is supposed to be invalid */
764 if (err != NULL) {
765 if (expect_err == NULL ||
766 g_str_equal(expect_err, error_get_pretty(err))) {
767 error_free(err);
768 return;
769 }
770
771 g_printerr("Test smp_parse failed!\n"
772 "Input configuration: %s\n"
773 "Should be valid: no\n"
774 "Expected error report: %s\n\n"
775 "Result is valid: no\n"
776 "Output error report: %s\n",
777 config_str, expect_err, error_get_pretty(err));
778 goto end;
779 }
780
781 g_printerr("Test smp_parse failed!\n"
782 "Input configuration: %s\n"
783 "Should be valid: no\n"
784 "Expected error report: %s\n\n"
785 "Result is valid: yes\n"
786 "Output topology: %s\n",
787 config_str, expect_err, output_topo_str);
788
789 end:
790 if (err != NULL) {
791 error_free(err);
792 }
793
794 abort();
795 }
796
smp_parse_test(MachineState * ms,SMPTestData * data,bool is_valid)797 static void smp_parse_test(MachineState *ms, SMPTestData *data, bool is_valid)
798 {
799 MachineClass *mc = MACHINE_GET_CLASS(ms);
800
801 mc->smp_props.prefer_sockets = true;
802 check_parse(ms, &data->config, &data->expect_prefer_sockets,
803 data->expect_error, is_valid);
804
805 mc->smp_props.prefer_sockets = false;
806 check_parse(ms, &data->config, &data->expect_prefer_cores,
807 data->expect_error, is_valid);
808 }
809
810 /* The parsed results of the unsupported parameters should be 1 */
unsupported_params_init(const MachineClass * mc,SMPTestData * data)811 static void unsupported_params_init(const MachineClass *mc, SMPTestData *data)
812 {
813 if (!mc->smp_props.dies_supported) {
814 data->expect_prefer_sockets.dies = 1;
815 data->expect_prefer_cores.dies = 1;
816 }
817
818 if (!mc->smp_props.clusters_supported) {
819 data->expect_prefer_sockets.clusters = 1;
820 data->expect_prefer_cores.clusters = 1;
821 }
822
823 if (!mc->smp_props.books_supported) {
824 data->expect_prefer_sockets.books = 1;
825 data->expect_prefer_cores.books = 1;
826 }
827
828 if (!mc->smp_props.drawers_supported) {
829 data->expect_prefer_sockets.drawers = 1;
830 data->expect_prefer_cores.drawers = 1;
831 }
832 }
833
machine_base_class_init(ObjectClass * oc,void * data)834 static void machine_base_class_init(ObjectClass *oc, void *data)
835 {
836 MachineClass *mc = MACHINE_CLASS(oc);
837
838 mc->min_cpus = MIN_CPUS;
839 mc->max_cpus = MAX_CPUS;
840
841 mc->name = g_strdup(SMP_MACHINE_NAME);
842 }
843
machine_generic_invalid_class_init(ObjectClass * oc,void * data)844 static void machine_generic_invalid_class_init(ObjectClass *oc, void *data)
845 {
846 MachineClass *mc = MACHINE_CLASS(oc);
847
848 /* Force invalid min CPUs and max CPUs */
849 mc->min_cpus = MIN_CPUS + 1;
850 mc->max_cpus = MAX_CPUS - 1;
851 }
852
machine_with_dies_class_init(ObjectClass * oc,void * data)853 static void machine_with_dies_class_init(ObjectClass *oc, void *data)
854 {
855 MachineClass *mc = MACHINE_CLASS(oc);
856
857 mc->smp_props.dies_supported = true;
858 }
859
machine_with_clusters_class_init(ObjectClass * oc,void * data)860 static void machine_with_clusters_class_init(ObjectClass *oc, void *data)
861 {
862 MachineClass *mc = MACHINE_CLASS(oc);
863
864 mc->smp_props.clusters_supported = true;
865 }
866
machine_with_books_class_init(ObjectClass * oc,void * data)867 static void machine_with_books_class_init(ObjectClass *oc, void *data)
868 {
869 MachineClass *mc = MACHINE_CLASS(oc);
870
871 mc->smp_props.books_supported = true;
872 }
873
machine_with_drawers_class_init(ObjectClass * oc,void * data)874 static void machine_with_drawers_class_init(ObjectClass *oc, void *data)
875 {
876 MachineClass *mc = MACHINE_CLASS(oc);
877
878 mc->smp_props.drawers_supported = true;
879 }
880
machine_with_drawers_books_class_init(ObjectClass * oc,void * data)881 static void machine_with_drawers_books_class_init(ObjectClass *oc, void *data)
882 {
883 MachineClass *mc = MACHINE_CLASS(oc);
884
885 mc->smp_props.drawers_supported = true;
886 mc->smp_props.books_supported = true;
887 }
888
machine_full_topo_class_init(ObjectClass * oc,void * data)889 static void machine_full_topo_class_init(ObjectClass *oc, void *data)
890 {
891 MachineClass *mc = MACHINE_CLASS(oc);
892
893 mc->smp_props.drawers_supported = true;
894 mc->smp_props.books_supported = true;
895 mc->smp_props.dies_supported = true;
896 mc->smp_props.clusters_supported = true;
897 }
898
test_generic_valid(const void * opaque)899 static void test_generic_valid(const void *opaque)
900 {
901 const char *machine_type = opaque;
902 Object *obj = object_new(machine_type);
903 MachineState *ms = MACHINE(obj);
904 MachineClass *mc = MACHINE_GET_CLASS(obj);
905 SMPTestData data = {};
906 int i;
907
908 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
909 data = data_generic_valid[i];
910 unsupported_params_init(mc, &data);
911
912 smp_parse_test(ms, &data, true);
913 }
914
915 object_unref(obj);
916 }
917
test_generic_invalid(const void * opaque)918 static void test_generic_invalid(const void *opaque)
919 {
920 const char *machine_type = opaque;
921 Object *obj = object_new(machine_type);
922 MachineState *ms = MACHINE(obj);
923 MachineClass *mc = MACHINE_GET_CLASS(obj);
924 SMPTestData data = {};
925 int i;
926
927 for (i = 0; i < ARRAY_SIZE(data_generic_invalid); i++) {
928 data = data_generic_invalid[i];
929 unsupported_params_init(mc, &data);
930
931 smp_parse_test(ms, &data, false);
932 }
933
934 object_unref(obj);
935 }
936
test_with_dies(const void * opaque)937 static void test_with_dies(const void *opaque)
938 {
939 const char *machine_type = opaque;
940 Object *obj = object_new(machine_type);
941 MachineState *ms = MACHINE(obj);
942 MachineClass *mc = MACHINE_GET_CLASS(obj);
943 SMPTestData data = {};
944 unsigned int num_dies = 2;
945 int i;
946
947 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
948 data = data_generic_valid[i];
949 unsupported_params_init(mc, &data);
950
951 /* when dies parameter is omitted, it will be set as 1 */
952 data.expect_prefer_sockets.dies = 1;
953 data.expect_prefer_cores.dies = 1;
954
955 smp_parse_test(ms, &data, true);
956
957 /* when dies parameter is specified */
958 data.config.has_dies = true;
959 data.config.dies = num_dies;
960 if (data.config.has_cpus) {
961 data.config.cpus *= num_dies;
962 }
963 if (data.config.has_maxcpus) {
964 data.config.maxcpus *= num_dies;
965 }
966
967 data.expect_prefer_sockets.dies = num_dies;
968 data.expect_prefer_sockets.cpus *= num_dies;
969 data.expect_prefer_sockets.max_cpus *= num_dies;
970 data.expect_prefer_cores.dies = num_dies;
971 data.expect_prefer_cores.cpus *= num_dies;
972 data.expect_prefer_cores.max_cpus *= num_dies;
973
974 smp_parse_test(ms, &data, true);
975 }
976
977 for (i = 0; i < ARRAY_SIZE(data_with_dies_invalid); i++) {
978 data = data_with_dies_invalid[i];
979 unsupported_params_init(mc, &data);
980
981 smp_parse_test(ms, &data, false);
982 }
983
984 object_unref(obj);
985 }
986
test_with_clusters(const void * opaque)987 static void test_with_clusters(const void *opaque)
988 {
989 const char *machine_type = opaque;
990 Object *obj = object_new(machine_type);
991 MachineState *ms = MACHINE(obj);
992 MachineClass *mc = MACHINE_GET_CLASS(obj);
993 SMPTestData data = {};
994 unsigned int num_clusters = 2;
995 int i;
996
997 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
998 data = data_generic_valid[i];
999 unsupported_params_init(mc, &data);
1000
1001 /* when clusters parameter is omitted, it will be set as 1 */
1002 data.expect_prefer_sockets.clusters = 1;
1003 data.expect_prefer_cores.clusters = 1;
1004
1005 smp_parse_test(ms, &data, true);
1006
1007 /* when clusters parameter is specified */
1008 data.config.has_clusters = true;
1009 data.config.clusters = num_clusters;
1010 if (data.config.has_cpus) {
1011 data.config.cpus *= num_clusters;
1012 }
1013 if (data.config.has_maxcpus) {
1014 data.config.maxcpus *= num_clusters;
1015 }
1016
1017 data.expect_prefer_sockets.clusters = num_clusters;
1018 data.expect_prefer_sockets.cpus *= num_clusters;
1019 data.expect_prefer_sockets.max_cpus *= num_clusters;
1020 data.expect_prefer_cores.clusters = num_clusters;
1021 data.expect_prefer_cores.cpus *= num_clusters;
1022 data.expect_prefer_cores.max_cpus *= num_clusters;
1023
1024 smp_parse_test(ms, &data, true);
1025 }
1026
1027 for (i = 0; i < ARRAY_SIZE(data_with_clusters_invalid); i++) {
1028 data = data_with_clusters_invalid[i];
1029 unsupported_params_init(mc, &data);
1030
1031 smp_parse_test(ms, &data, false);
1032 }
1033
1034 object_unref(obj);
1035 }
1036
test_with_books(const void * opaque)1037 static void test_with_books(const void *opaque)
1038 {
1039 const char *machine_type = opaque;
1040 Object *obj = object_new(machine_type);
1041 MachineState *ms = MACHINE(obj);
1042 MachineClass *mc = MACHINE_GET_CLASS(obj);
1043 SMPTestData data = {};
1044 unsigned int num_books = 2;
1045 int i;
1046
1047 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
1048 data = data_generic_valid[i];
1049 unsupported_params_init(mc, &data);
1050
1051 /* when books parameter is omitted, it will be set as 1 */
1052 data.expect_prefer_sockets.books = 1;
1053 data.expect_prefer_cores.books = 1;
1054
1055 smp_parse_test(ms, &data, true);
1056
1057 /* when books parameter is specified */
1058 data.config.has_books = true;
1059 data.config.books = num_books;
1060 if (data.config.has_cpus) {
1061 data.config.cpus *= num_books;
1062 }
1063 if (data.config.has_maxcpus) {
1064 data.config.maxcpus *= num_books;
1065 }
1066
1067 data.expect_prefer_sockets.books = num_books;
1068 data.expect_prefer_sockets.cpus *= num_books;
1069 data.expect_prefer_sockets.max_cpus *= num_books;
1070 data.expect_prefer_cores.books = num_books;
1071 data.expect_prefer_cores.cpus *= num_books;
1072 data.expect_prefer_cores.max_cpus *= num_books;
1073
1074 smp_parse_test(ms, &data, true);
1075 }
1076
1077 for (i = 0; i < ARRAY_SIZE(data_with_books_invalid); i++) {
1078 data = data_with_books_invalid[i];
1079 unsupported_params_init(mc, &data);
1080
1081 smp_parse_test(ms, &data, false);
1082 }
1083
1084 object_unref(obj);
1085 }
1086
test_with_drawers(const void * opaque)1087 static void test_with_drawers(const void *opaque)
1088 {
1089 const char *machine_type = opaque;
1090 Object *obj = object_new(machine_type);
1091 MachineState *ms = MACHINE(obj);
1092 MachineClass *mc = MACHINE_GET_CLASS(obj);
1093 SMPTestData data = {};
1094 unsigned int num_drawers = 2;
1095 int i;
1096
1097 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
1098 data = data_generic_valid[i];
1099 unsupported_params_init(mc, &data);
1100
1101 /* when drawers parameter is omitted, it will be set as 1 */
1102 data.expect_prefer_sockets.drawers = 1;
1103 data.expect_prefer_cores.drawers = 1;
1104
1105 smp_parse_test(ms, &data, true);
1106
1107 /* when drawers parameter is specified */
1108 data.config.has_drawers = true;
1109 data.config.drawers = num_drawers;
1110 if (data.config.has_cpus) {
1111 data.config.cpus *= num_drawers;
1112 }
1113 if (data.config.has_maxcpus) {
1114 data.config.maxcpus *= num_drawers;
1115 }
1116
1117 data.expect_prefer_sockets.drawers = num_drawers;
1118 data.expect_prefer_sockets.cpus *= num_drawers;
1119 data.expect_prefer_sockets.max_cpus *= num_drawers;
1120 data.expect_prefer_cores.drawers = num_drawers;
1121 data.expect_prefer_cores.cpus *= num_drawers;
1122 data.expect_prefer_cores.max_cpus *= num_drawers;
1123
1124 smp_parse_test(ms, &data, true);
1125 }
1126
1127 for (i = 0; i < ARRAY_SIZE(data_with_drawers_invalid); i++) {
1128 data = data_with_drawers_invalid[i];
1129 unsupported_params_init(mc, &data);
1130
1131 smp_parse_test(ms, &data, false);
1132 }
1133
1134 object_unref(obj);
1135 }
1136
test_with_drawers_books(const void * opaque)1137 static void test_with_drawers_books(const void *opaque)
1138 {
1139 const char *machine_type = opaque;
1140 Object *obj = object_new(machine_type);
1141 MachineState *ms = MACHINE(obj);
1142 MachineClass *mc = MACHINE_GET_CLASS(obj);
1143 SMPTestData data = {};
1144 unsigned int num_drawers = 5, num_books = 3;
1145 int i;
1146
1147 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
1148 data = data_generic_valid[i];
1149 unsupported_params_init(mc, &data);
1150
1151 /*
1152 * when drawers and books parameters are omitted, they will
1153 * be both set as 1.
1154 */
1155 data.expect_prefer_sockets.drawers = 1;
1156 data.expect_prefer_sockets.books = 1;
1157 data.expect_prefer_cores.drawers = 1;
1158 data.expect_prefer_cores.books = 1;
1159
1160 smp_parse_test(ms, &data, true);
1161
1162 /* when drawers and books parameters are both specified */
1163 data.config.has_drawers = true;
1164 data.config.drawers = num_drawers;
1165 data.config.has_books = true;
1166 data.config.books = num_books;
1167
1168 if (data.config.has_cpus) {
1169 data.config.cpus *= num_drawers * num_books;
1170 }
1171 if (data.config.has_maxcpus) {
1172 data.config.maxcpus *= num_drawers * num_books;
1173 }
1174
1175 data.expect_prefer_sockets.drawers = num_drawers;
1176 data.expect_prefer_sockets.books = num_books;
1177 data.expect_prefer_sockets.cpus *= num_drawers * num_books;
1178 data.expect_prefer_sockets.max_cpus *= num_drawers * num_books;
1179
1180 data.expect_prefer_cores.drawers = num_drawers;
1181 data.expect_prefer_cores.books = num_books;
1182 data.expect_prefer_cores.cpus *= num_drawers * num_books;
1183 data.expect_prefer_cores.max_cpus *= num_drawers * num_books;
1184
1185 smp_parse_test(ms, &data, true);
1186 }
1187
1188 for (i = 0; i < ARRAY_SIZE(data_with_drawers_books_invalid); i++) {
1189 data = data_with_drawers_books_invalid[i];
1190 unsupported_params_init(mc, &data);
1191
1192 smp_parse_test(ms, &data, false);
1193 }
1194
1195 object_unref(obj);
1196 }
1197
test_full_topo(const void * opaque)1198 static void test_full_topo(const void *opaque)
1199 {
1200 const char *machine_type = opaque;
1201 Object *obj = object_new(machine_type);
1202 MachineState *ms = MACHINE(obj);
1203 MachineClass *mc = MACHINE_GET_CLASS(obj);
1204 SMPTestData data = {};
1205 unsigned int drawers = 5, books = 3, dies = 2, clusters = 7, multiplier;
1206 int i;
1207
1208 multiplier = drawers * books * dies * clusters;
1209 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
1210 data = data_generic_valid[i];
1211 unsupported_params_init(mc, &data);
1212
1213 /*
1214 * when drawers, books, dies and clusters parameters are omitted,
1215 * they will be set as 1.
1216 */
1217 data.expect_prefer_sockets.drawers = 1;
1218 data.expect_prefer_sockets.books = 1;
1219 data.expect_prefer_sockets.dies = 1;
1220 data.expect_prefer_sockets.clusters = 1;
1221 data.expect_prefer_cores.drawers = 1;
1222 data.expect_prefer_cores.books = 1;
1223 data.expect_prefer_cores.dies = 1;
1224 data.expect_prefer_cores.clusters = 1;
1225
1226 smp_parse_test(ms, &data, true);
1227
1228 /* when drawers, books, dies and clusters parameters are specified. */
1229 data.config.has_drawers = true;
1230 data.config.drawers = drawers;
1231 data.config.has_books = true;
1232 data.config.books = books;
1233 data.config.has_dies = true;
1234 data.config.dies = dies;
1235 data.config.has_clusters = true;
1236 data.config.clusters = clusters;
1237
1238 if (data.config.has_cpus) {
1239 data.config.cpus *= multiplier;
1240 }
1241 if (data.config.has_maxcpus) {
1242 data.config.maxcpus *= multiplier;
1243 }
1244
1245 data.expect_prefer_sockets.drawers = drawers;
1246 data.expect_prefer_sockets.books = books;
1247 data.expect_prefer_sockets.dies = dies;
1248 data.expect_prefer_sockets.clusters = clusters;
1249 data.expect_prefer_sockets.cpus *= multiplier;
1250 data.expect_prefer_sockets.max_cpus *= multiplier;
1251
1252 data.expect_prefer_cores.drawers = drawers;
1253 data.expect_prefer_cores.books = books;
1254 data.expect_prefer_cores.dies = dies;
1255 data.expect_prefer_cores.clusters = clusters;
1256 data.expect_prefer_cores.cpus *= multiplier;
1257 data.expect_prefer_cores.max_cpus *= multiplier;
1258
1259 smp_parse_test(ms, &data, true);
1260 }
1261
1262 for (i = 0; i < ARRAY_SIZE(data_full_topo_invalid); i++) {
1263 data = data_full_topo_invalid[i];
1264 unsupported_params_init(mc, &data);
1265
1266 smp_parse_test(ms, &data, false);
1267 }
1268
1269 for (i = 0; i < ARRAY_SIZE(data_zero_topo_invalid); i++) {
1270 data = data_zero_topo_invalid[i];
1271 unsupported_params_init(mc, &data);
1272
1273 smp_parse_test(ms, &data, false);
1274 }
1275
1276 object_unref(obj);
1277 }
1278
1279 /* Type info of the tested machine */
1280 static const TypeInfo smp_machine_types[] = {
1281 {
1282 .name = TYPE_MACHINE,
1283 .parent = TYPE_OBJECT,
1284 .abstract = true,
1285 .class_init = machine_base_class_init,
1286 .class_size = sizeof(MachineClass),
1287 .instance_size = sizeof(MachineState),
1288 }, {
1289 .name = MACHINE_TYPE_NAME("smp-generic-valid"),
1290 .parent = TYPE_MACHINE,
1291 }, {
1292 .name = MACHINE_TYPE_NAME("smp-generic-invalid"),
1293 .parent = TYPE_MACHINE,
1294 .class_init = machine_generic_invalid_class_init,
1295 }, {
1296 .name = MACHINE_TYPE_NAME("smp-with-dies"),
1297 .parent = TYPE_MACHINE,
1298 .class_init = machine_with_dies_class_init,
1299 }, {
1300 .name = MACHINE_TYPE_NAME("smp-with-clusters"),
1301 .parent = TYPE_MACHINE,
1302 .class_init = machine_with_clusters_class_init,
1303 }, {
1304 .name = MACHINE_TYPE_NAME("smp-with-books"),
1305 .parent = TYPE_MACHINE,
1306 .class_init = machine_with_books_class_init,
1307 }, {
1308 .name = MACHINE_TYPE_NAME("smp-with-drawers"),
1309 .parent = TYPE_MACHINE,
1310 .class_init = machine_with_drawers_class_init,
1311 }, {
1312 .name = MACHINE_TYPE_NAME("smp-with-drawers-books"),
1313 .parent = TYPE_MACHINE,
1314 .class_init = machine_with_drawers_books_class_init,
1315 }, {
1316 .name = MACHINE_TYPE_NAME("smp-full-topo"),
1317 .parent = TYPE_MACHINE,
1318 .class_init = machine_full_topo_class_init,
1319 }
1320 };
1321
DEFINE_TYPES(smp_machine_types)1322 DEFINE_TYPES(smp_machine_types)
1323
1324 int main(int argc, char *argv[])
1325 {
1326 module_call_init(MODULE_INIT_QOM);
1327
1328 g_test_init(&argc, &argv, NULL);
1329
1330 g_test_add_data_func("/test-smp-parse/generic/valid",
1331 MACHINE_TYPE_NAME("smp-generic-valid"),
1332 test_generic_valid);
1333 g_test_add_data_func("/test-smp-parse/generic/invalid",
1334 MACHINE_TYPE_NAME("smp-generic-invalid"),
1335 test_generic_invalid);
1336 g_test_add_data_func("/test-smp-parse/with_dies",
1337 MACHINE_TYPE_NAME("smp-with-dies"),
1338 test_with_dies);
1339 g_test_add_data_func("/test-smp-parse/with_clusters",
1340 MACHINE_TYPE_NAME("smp-with-clusters"),
1341 test_with_clusters);
1342 g_test_add_data_func("/test-smp-parse/with_books",
1343 MACHINE_TYPE_NAME("smp-with-books"),
1344 test_with_books);
1345 g_test_add_data_func("/test-smp-parse/with_drawers",
1346 MACHINE_TYPE_NAME("smp-with-drawers"),
1347 test_with_drawers);
1348 g_test_add_data_func("/test-smp-parse/with_drawers_books",
1349 MACHINE_TYPE_NAME("smp-with-drawers-books"),
1350 test_with_drawers_books);
1351 g_test_add_data_func("/test-smp-parse/full",
1352 MACHINE_TYPE_NAME("smp-full-topo"),
1353 test_full_topo);
1354
1355 g_test_run();
1356
1357 return 0;
1358 }
1359