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
336 static const struct SMPTestData data_generic_invalid[] = {
337 {
338 /* config: -smp 2,dies=2 */
339 .config = SMP_CONFIG_WITH_DIES(T, 2, F, 0, T, 2, F, 0, F, 0, F, 0),
340 .expect_error = "dies not supported by this machine's CPU topology",
341 }, {
342 /* config: -smp 2,clusters=2 */
343 .config = SMP_CONFIG_WITH_CLUSTERS(T, 2, F, 0, T, 2, F, 0, F, 0, F, 0),
344 .expect_error = "clusters not supported by this machine's CPU topology",
345 }, {
346 /* config: -smp 2,books=2 */
347 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 2, F, 0, T, 2, F,
348 0, F, 0, F, 0, F, 0),
349 .expect_error = "books not supported by this machine's CPU topology",
350 }, {
351 /* config: -smp 2,drawers=2 */
352 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 2, T, 2, F, 0, F,
353 0, F, 0, F, 0, F, 0),
354 .expect_error = "drawers not supported by this machine's CPU topology",
355 }, {
356 /* config: -smp 8,sockets=2,cores=4,threads=2,maxcpus=8 */
357 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 2, T, 8),
358 .expect_error = "Invalid CPU topology: "
359 "product of the hierarchy must match maxcpus: "
360 "sockets (2) * cores (4) * threads (2) "
361 "!= maxcpus (8)",
362 }, {
363 /* config: -smp 18,sockets=2,cores=4,threads=2,maxcpus=16 */
364 .config = SMP_CONFIG_GENERIC(T, 18, T, 2, T, 4, T, 2, T, 16),
365 .expect_error = "Invalid CPU topology: "
366 "maxcpus must be equal to or greater than smp: "
367 "sockets (2) * cores (4) * threads (2) "
368 "== maxcpus (16) < smp_cpus (18)",
369 }, {
370 /*
371 * config: -smp 1
372 * The test machine should tweak the supported min CPUs to
373 * 2 (MIN_CPUS + 1) for testing.
374 */
375 .config = SMP_CONFIG_GENERIC(T, MIN_CPUS, F, 0, F, 0, F, 0, F, 0),
376 .expect_error = "Invalid SMP CPUs 1. The min CPUs supported "
377 "by machine '" SMP_MACHINE_NAME "' is 2",
378 }, {
379 /*
380 * config: -smp 4096
381 * The test machine should tweak the supported max CPUs to
382 * 4095 (MAX_CPUS - 1) for testing.
383 */
384 .config = SMP_CONFIG_GENERIC(T, 4096, F, 0, F, 0, F, 0, F, 0),
385 .expect_error = "Invalid SMP CPUs 4096. The max CPUs supported "
386 "by machine '" SMP_MACHINE_NAME "' is 4095",
387 },
388 };
389
390 static const struct SMPTestData data_with_dies_invalid[] = {
391 {
392 /* config: -smp 16,sockets=2,dies=2,cores=4,threads=2,maxcpus=16 */
393 .config = SMP_CONFIG_WITH_DIES(T, 16, T, 2, T, 2, T, 4, T, 2, T, 16),
394 .expect_error = "Invalid CPU topology: "
395 "product of the hierarchy must match maxcpus: "
396 "sockets (2) * dies (2) * cores (4) * threads (2) "
397 "!= maxcpus (16)",
398 }, {
399 /* config: -smp 34,sockets=2,dies=2,cores=4,threads=2,maxcpus=32 */
400 .config = SMP_CONFIG_WITH_DIES(T, 34, T, 2, T, 2, T, 4, T, 2, T, 32),
401 .expect_error = "Invalid CPU topology: "
402 "maxcpus must be equal to or greater than smp: "
403 "sockets (2) * dies (2) * cores (4) * threads (2) "
404 "== maxcpus (32) < smp_cpus (34)",
405 },
406 };
407
408 static const struct SMPTestData data_with_clusters_invalid[] = {
409 {
410 /* config: -smp 16,sockets=2,clusters=2,cores=4,threads=2,maxcpus=16 */
411 .config = SMP_CONFIG_WITH_CLUSTERS(T, 16, T, 2, T, 2, T, 4, T, 2, T, 16),
412 .expect_error = "Invalid CPU topology: "
413 "product of the hierarchy must match maxcpus: "
414 "sockets (2) * clusters (2) * cores (4) * threads (2) "
415 "!= maxcpus (16)",
416 }, {
417 /* config: -smp 34,sockets=2,clusters=2,cores=4,threads=2,maxcpus=32 */
418 .config = SMP_CONFIG_WITH_CLUSTERS(T, 34, T, 2, T, 2, T, 4, T, 2, T, 32),
419 .expect_error = "Invalid CPU topology: "
420 "maxcpus must be equal to or greater than smp: "
421 "sockets (2) * clusters (2) * cores (4) * threads (2) "
422 "== maxcpus (32) < smp_cpus (34)",
423 },
424 };
425
426 static const struct SMPTestData data_with_books_invalid[] = {
427 {
428 /* config: -smp 16,books=2,sockets=2,cores=4,threads=2,maxcpus=16 */
429 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 16, F, 1, T, 2, T,
430 2, T, 4, T, 2, T, 16),
431 .expect_error = "Invalid CPU topology: "
432 "product of the hierarchy must match maxcpus: "
433 "books (2) * sockets (2) * cores (4) * threads (2) "
434 "!= maxcpus (16)",
435 }, {
436 /* config: -smp 34,books=2,sockets=2,cores=4,threads=2,maxcpus=32 */
437 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 34, F, 1, T, 2, T,
438 2, T, 4, T, 2, T, 32),
439 .expect_error = "Invalid CPU topology: "
440 "maxcpus must be equal to or greater than smp: "
441 "books (2) * sockets (2) * cores (4) * threads (2) "
442 "== maxcpus (32) < smp_cpus (34)",
443 },
444 };
445
446 static const struct SMPTestData data_with_drawers_invalid[] = {
447 {
448 /* config: -smp 16,drawers=2,sockets=2,cores=4,threads=2,maxcpus=16 */
449 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 16, T, 2, F, 1, T,
450 2, T, 4, T, 2, T, 16),
451 .expect_error = "Invalid CPU topology: "
452 "product of the hierarchy must match maxcpus: "
453 "drawers (2) * sockets (2) * cores (4) * threads (2) "
454 "!= maxcpus (16)",
455 }, {
456 /* config: -smp 34,drawers=2,sockets=2,cores=4,threads=2,maxcpus=32 */
457 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 34, T, 2, F, 1, T,
458 2, T, 4, T, 2, T, 32),
459 .expect_error = "Invalid CPU topology: "
460 "maxcpus must be equal to or greater than smp: "
461 "drawers (2) * sockets (2) * cores (4) * threads (2) "
462 "== maxcpus (32) < smp_cpus (34)",
463 },
464 };
465
466 static const struct SMPTestData data_with_drawers_books_invalid[] = {
467 {
468 /*
469 * config: -smp 200,drawers=2,books=2,sockets=2,cores=4,\
470 * threads=2,maxcpus=200
471 */
472 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 200, T, 3, T, 5, T,
473 2, T, 4, T, 2, T, 200),
474 .expect_error = "Invalid CPU topology: "
475 "product of the hierarchy must match maxcpus: "
476 "drawers (3) * books (5) * sockets (2) * "
477 "cores (4) * threads (2) != maxcpus (200)",
478 }, {
479 /*
480 * config: -smp 242,drawers=2,books=2,sockets=2,cores=4,\
481 * threads=2,maxcpus=240
482 */
483 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 242, T, 3, T, 5, T,
484 2, T, 4, T, 2, T, 240),
485 .expect_error = "Invalid CPU topology: "
486 "maxcpus must be equal to or greater than smp: "
487 "drawers (3) * books (5) * sockets (2) * "
488 "cores (4) * threads (2) "
489 "== maxcpus (240) < smp_cpus (242)",
490 },
491 };
492
493 static const struct SMPTestData data_full_topo_invalid[] = {
494 {
495 /*
496 * config: -smp 200,drawers=3,books=5,sockets=2,dies=4,\
497 * clusters=2,cores=7,threads=2,maxcpus=200
498 */
499 .config = SMP_CONFIG_WITH_FULL_TOPO(200, 3, 5, 2, 4, 2, 7, 2, 200),
500 .expect_error = "Invalid CPU topology: "
501 "product of the hierarchy must match maxcpus: "
502 "drawers (3) * books (5) * sockets (2) * dies (4) * "
503 "clusters (2) * cores (7) * threads (2) "
504 "!= maxcpus (200)",
505 }, {
506 /*
507 * config: -smp 3361,drawers=3,books=5,sockets=2,dies=4,\
508 * clusters=2,cores=7,threads=2,maxcpus=3360
509 */
510 .config = SMP_CONFIG_WITH_FULL_TOPO(3361, 3, 5, 2, 4, 2, 7, 2, 3360),
511 .expect_error = "Invalid CPU topology: "
512 "maxcpus must be equal to or greater than smp: "
513 "drawers (3) * books (5) * sockets (2) * dies (4) * "
514 "clusters (2) * cores (7) * threads (2) "
515 "== maxcpus (3360) < smp_cpus (3361)",
516 }, {
517 /*
518 * config: -smp 1,drawers=3,books=5,sockets=2,dies=4,\
519 * clusters=2,cores=7,threads=3,maxcpus=5040
520 */
521 .config = SMP_CONFIG_WITH_FULL_TOPO(3361, 3, 5, 2, 4, 2, 7, 3, 5040),
522 .expect_error = "Invalid SMP CPUs 5040. The max CPUs supported "
523 "by machine '" SMP_MACHINE_NAME "' is 4096",
524 },
525 };
526
527 static const struct SMPTestData data_zero_topo_invalid[] = {
528 {
529 /*
530 * Test "cpus=0".
531 * config: -smp 0,drawers=1,books=1,sockets=1,dies=1,\
532 * clusters=1,cores=1,threads=1,maxcpus=1
533 */
534 .config = SMP_CONFIG_WITH_FULL_TOPO(0, 1, 1, 1, 1, 1, 1, 1, 1),
535 .expect_error = "Invalid CPU topology: CPU topology parameters must "
536 "be greater than zero",
537 }, {
538 /*
539 * Test "drawers=0".
540 * config: -smp 1,drawers=0,books=1,sockets=1,dies=1,\
541 * clusters=1,cores=1,threads=1,maxcpus=1
542 */
543 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 0, 1, 1, 1, 1, 1, 1, 1),
544 .expect_error = "Invalid CPU topology: CPU topology parameters must "
545 "be greater than zero",
546 }, {
547 /*
548 * Test "books=0".
549 * config: -smp 1,drawers=1,books=0,sockets=1,dies=1,\
550 * clusters=1,cores=1,threads=1,maxcpus=1
551 */
552 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 0, 1, 1, 1, 1, 1, 1),
553 .expect_error = "Invalid CPU topology: CPU topology parameters must "
554 "be greater than zero",
555 }, {
556 /*
557 * Test "sockets=0".
558 * config: -smp 1,drawers=1,books=1,sockets=0,dies=1,\
559 * clusters=1,cores=1,threads=1,maxcpus=1
560 */
561 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 0, 1, 1, 1, 1, 1),
562 .expect_error = "Invalid CPU topology: CPU topology parameters must "
563 "be greater than zero",
564 }, {
565 /*
566 * Test "dies=0".
567 * config: -smp 1,drawers=1,books=1,sockets=1,dies=0,\
568 * clusters=1,cores=1,threads=1,maxcpus=1
569 */
570 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 1, 0, 1, 1, 1, 1),
571 .expect_error = "Invalid CPU topology: CPU topology parameters must "
572 "be greater than zero",
573 }, {
574 /*
575 * Test "clusters=0".
576 * config: -smp 1,drawers=1,books=1,sockets=1,dies=1,\
577 * clusters=0,cores=1,threads=1,maxcpus=1
578 */
579 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 1, 1, 0, 1, 1, 1),
580 .expect_error = "Invalid CPU topology: CPU topology parameters must "
581 "be greater than zero",
582 }, {
583 /*
584 * Test "cores=0".
585 * config: -smp 1,drawers=1,books=1,sockets=1,dies=1,\
586 * clusters=1,cores=0,threads=1,maxcpus=1
587 */
588 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 1, 1, 1, 0, 1, 1),
589 .expect_error = "Invalid CPU topology: CPU topology parameters must "
590 "be greater than zero",
591 }, {
592 /*
593 * Test "threads=0".
594 * config: -smp 1,drawers=1,books=1,sockets=1,dies=1,\
595 * clusters=1,cores=1,threads=0,maxcpus=1
596 */
597 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 1, 1, 1, 1, 0, 1),
598 .expect_error = "Invalid CPU topology: CPU topology parameters must "
599 "be greater than zero",
600 }, {
601 /*
602 * Test "maxcpus=0".
603 * config: -smp 1,drawers=1,books=1,sockets=1,dies=1,\
604 * clusters=1,cores=1,threads=1,maxcpus=0
605 */
606 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 1, 1, 1, 1, 1, 0),
607 .expect_error = "Invalid CPU topology: CPU topology parameters must "
608 "be greater than zero",
609 },
610 };
611
smp_config_to_string(const SMPConfiguration * config)612 static char *smp_config_to_string(const SMPConfiguration *config)
613 {
614 return g_strdup_printf(
615 "(SMPConfiguration) {\n"
616 " .has_cpus = %5s, cpus = %" PRId64 ",\n"
617 " .has_drawers = %5s, drawers = %" PRId64 ",\n"
618 " .has_books = %5s, books = %" PRId64 ",\n"
619 " .has_sockets = %5s, sockets = %" PRId64 ",\n"
620 " .has_dies = %5s, dies = %" PRId64 ",\n"
621 " .has_clusters = %5s, clusters = %" PRId64 ",\n"
622 " .has_cores = %5s, cores = %" PRId64 ",\n"
623 " .has_threads = %5s, threads = %" PRId64 ",\n"
624 " .has_maxcpus = %5s, maxcpus = %" PRId64 ",\n"
625 "}",
626 config->has_cpus ? "true" : "false", config->cpus,
627 config->has_drawers ? "true" : "false", config->drawers,
628 config->has_books ? "true" : "false", config->books,
629 config->has_sockets ? "true" : "false", config->sockets,
630 config->has_dies ? "true" : "false", config->dies,
631 config->has_clusters ? "true" : "false", config->clusters,
632 config->has_cores ? "true" : "false", config->cores,
633 config->has_threads ? "true" : "false", config->threads,
634 config->has_maxcpus ? "true" : "false", config->maxcpus);
635 }
636
637 /* Use the different calculation than machine_topo_get_threads_per_socket(). */
cpu_topology_get_threads_per_socket(const CpuTopology * topo)638 static unsigned int cpu_topology_get_threads_per_socket(const CpuTopology *topo)
639 {
640 /* Check the divisor to avoid invalid topology examples causing SIGFPE. */
641 if (!topo->drawers || !topo->books || !topo->sockets) {
642 return 0;
643 } else {
644 return topo->max_cpus / topo->drawers / topo->books / topo->sockets;
645 }
646 }
647
648 /* Use the different calculation than machine_topo_get_cores_per_socket(). */
cpu_topology_get_cores_per_socket(const CpuTopology * topo)649 static unsigned int cpu_topology_get_cores_per_socket(const CpuTopology *topo)
650 {
651 /* Check the divisor to avoid invalid topology examples causing SIGFPE. */
652 if (!topo->threads) {
653 return 0;
654 } else {
655 return cpu_topology_get_threads_per_socket(topo) / topo->threads;
656 }
657 }
658
cpu_topology_to_string(const CpuTopology * topo,unsigned int threads_per_socket,unsigned int cores_per_socket,bool has_clusters)659 static char *cpu_topology_to_string(const CpuTopology *topo,
660 unsigned int threads_per_socket,
661 unsigned int cores_per_socket,
662 bool has_clusters)
663 {
664 return g_strdup_printf(
665 "(CpuTopology) {\n"
666 " .cpus = %u,\n"
667 " .drawers = %u,\n"
668 " .books = %u,\n"
669 " .sockets = %u,\n"
670 " .dies = %u,\n"
671 " .clusters = %u,\n"
672 " .cores = %u,\n"
673 " .threads = %u,\n"
674 " .max_cpus = %u,\n"
675 " .threads_per_socket = %u,\n"
676 " .cores_per_socket = %u,\n"
677 " .has_clusters = %s,\n"
678 "}",
679 topo->cpus, topo->drawers, topo->books,
680 topo->sockets, topo->dies, topo->clusters,
681 topo->cores, topo->threads, topo->max_cpus,
682 threads_per_socket, cores_per_socket,
683 has_clusters ? "true" : "false");
684 }
685
check_parse(MachineState * ms,const SMPConfiguration * config,const CpuTopology * expect_topo,const char * expect_err,bool is_valid)686 static void check_parse(MachineState *ms, const SMPConfiguration *config,
687 const CpuTopology *expect_topo, const char *expect_err,
688 bool is_valid)
689 {
690 MachineClass *mc = MACHINE_GET_CLASS(ms);
691 g_autofree char *config_str = smp_config_to_string(config);
692 g_autofree char *expect_topo_str = NULL, *output_topo_str = NULL;
693 unsigned int expect_threads_per_socket, expect_cores_per_socket;
694 unsigned int ms_threads_per_socket, ms_cores_per_socket;
695 Error *err = NULL;
696
697 expect_threads_per_socket =
698 cpu_topology_get_threads_per_socket(expect_topo);
699 expect_cores_per_socket =
700 cpu_topology_get_cores_per_socket(expect_topo);
701 expect_topo_str = cpu_topology_to_string(expect_topo,
702 expect_threads_per_socket,
703 expect_cores_per_socket,
704 config->has_clusters);
705
706 /* call the generic parser */
707 machine_parse_smp_config(ms, config, &err);
708
709 ms_threads_per_socket = machine_topo_get_threads_per_socket(ms);
710 ms_cores_per_socket = machine_topo_get_cores_per_socket(ms);
711 output_topo_str = cpu_topology_to_string(&ms->smp,
712 ms_threads_per_socket,
713 ms_cores_per_socket,
714 mc->smp_props.has_clusters);
715
716 /* when the configuration is supposed to be valid */
717 if (is_valid) {
718 if ((err == NULL) &&
719 (ms->smp.cpus == expect_topo->cpus) &&
720 (ms->smp.drawers == expect_topo->drawers) &&
721 (ms->smp.books == expect_topo->books) &&
722 (ms->smp.sockets == expect_topo->sockets) &&
723 (ms->smp.dies == expect_topo->dies) &&
724 (ms->smp.clusters == expect_topo->clusters) &&
725 (ms->smp.cores == expect_topo->cores) &&
726 (ms->smp.threads == expect_topo->threads) &&
727 (ms->smp.max_cpus == expect_topo->max_cpus) &&
728 (ms_threads_per_socket == expect_threads_per_socket) &&
729 (ms_cores_per_socket == expect_cores_per_socket) &&
730 (mc->smp_props.has_clusters == config->has_clusters)) {
731 return;
732 }
733
734 if (err != NULL) {
735 g_printerr("Test smp_parse failed!\n"
736 "Input configuration: %s\n"
737 "Should be valid: yes\n"
738 "Expected topology: %s\n\n"
739 "Result is valid: no\n"
740 "Output error report: %s\n",
741 config_str, expect_topo_str, error_get_pretty(err));
742 goto end;
743 }
744
745 g_printerr("Test smp_parse failed!\n"
746 "Input configuration: %s\n"
747 "Should be valid: yes\n"
748 "Expected topology: %s\n\n"
749 "Result is valid: yes\n"
750 "Output topology: %s\n",
751 config_str, expect_topo_str, output_topo_str);
752 goto end;
753 }
754
755 /* when the configuration is supposed to be invalid */
756 if (err != NULL) {
757 if (expect_err == NULL ||
758 g_str_equal(expect_err, error_get_pretty(err))) {
759 error_free(err);
760 return;
761 }
762
763 g_printerr("Test smp_parse failed!\n"
764 "Input configuration: %s\n"
765 "Should be valid: no\n"
766 "Expected error report: %s\n\n"
767 "Result is valid: no\n"
768 "Output error report: %s\n",
769 config_str, expect_err, error_get_pretty(err));
770 goto end;
771 }
772
773 g_printerr("Test smp_parse failed!\n"
774 "Input configuration: %s\n"
775 "Should be valid: no\n"
776 "Expected error report: %s\n\n"
777 "Result is valid: yes\n"
778 "Output topology: %s\n",
779 config_str, expect_err, output_topo_str);
780
781 end:
782 if (err != NULL) {
783 error_free(err);
784 }
785
786 abort();
787 }
788
smp_parse_test(MachineState * ms,SMPTestData * data,bool is_valid)789 static void smp_parse_test(MachineState *ms, SMPTestData *data, bool is_valid)
790 {
791 MachineClass *mc = MACHINE_GET_CLASS(ms);
792
793 mc->smp_props.prefer_sockets = true;
794 check_parse(ms, &data->config, &data->expect_prefer_sockets,
795 data->expect_error, is_valid);
796
797 mc->smp_props.prefer_sockets = false;
798 check_parse(ms, &data->config, &data->expect_prefer_cores,
799 data->expect_error, is_valid);
800 }
801
802 /* The parsed results of the unsupported parameters should be 1 */
unsupported_params_init(const MachineClass * mc,SMPTestData * data)803 static void unsupported_params_init(const MachineClass *mc, SMPTestData *data)
804 {
805 if (!mc->smp_props.dies_supported) {
806 data->expect_prefer_sockets.dies = 1;
807 data->expect_prefer_cores.dies = 1;
808 }
809
810 if (!mc->smp_props.clusters_supported) {
811 data->expect_prefer_sockets.clusters = 1;
812 data->expect_prefer_cores.clusters = 1;
813 }
814
815 if (!mc->smp_props.books_supported) {
816 data->expect_prefer_sockets.books = 1;
817 data->expect_prefer_cores.books = 1;
818 }
819
820 if (!mc->smp_props.drawers_supported) {
821 data->expect_prefer_sockets.drawers = 1;
822 data->expect_prefer_cores.drawers = 1;
823 }
824 }
825
machine_base_class_init(ObjectClass * oc,void * data)826 static void machine_base_class_init(ObjectClass *oc, void *data)
827 {
828 MachineClass *mc = MACHINE_CLASS(oc);
829
830 mc->min_cpus = MIN_CPUS;
831 mc->max_cpus = MAX_CPUS;
832
833 mc->name = g_strdup(SMP_MACHINE_NAME);
834 }
835
machine_generic_invalid_class_init(ObjectClass * oc,void * data)836 static void machine_generic_invalid_class_init(ObjectClass *oc, void *data)
837 {
838 MachineClass *mc = MACHINE_CLASS(oc);
839
840 /* Force invalid min CPUs and max CPUs */
841 mc->min_cpus = MIN_CPUS + 1;
842 mc->max_cpus = MAX_CPUS - 1;
843 }
844
machine_with_dies_class_init(ObjectClass * oc,void * data)845 static void machine_with_dies_class_init(ObjectClass *oc, void *data)
846 {
847 MachineClass *mc = MACHINE_CLASS(oc);
848
849 mc->smp_props.dies_supported = true;
850 }
851
machine_with_clusters_class_init(ObjectClass * oc,void * data)852 static void machine_with_clusters_class_init(ObjectClass *oc, void *data)
853 {
854 MachineClass *mc = MACHINE_CLASS(oc);
855
856 mc->smp_props.clusters_supported = true;
857 }
858
machine_with_books_class_init(ObjectClass * oc,void * data)859 static void machine_with_books_class_init(ObjectClass *oc, void *data)
860 {
861 MachineClass *mc = MACHINE_CLASS(oc);
862
863 mc->smp_props.books_supported = true;
864 }
865
machine_with_drawers_class_init(ObjectClass * oc,void * data)866 static void machine_with_drawers_class_init(ObjectClass *oc, void *data)
867 {
868 MachineClass *mc = MACHINE_CLASS(oc);
869
870 mc->smp_props.drawers_supported = true;
871 }
872
machine_with_drawers_books_class_init(ObjectClass * oc,void * data)873 static void machine_with_drawers_books_class_init(ObjectClass *oc, void *data)
874 {
875 MachineClass *mc = MACHINE_CLASS(oc);
876
877 mc->smp_props.drawers_supported = true;
878 mc->smp_props.books_supported = true;
879 }
880
machine_full_topo_class_init(ObjectClass * oc,void * data)881 static void machine_full_topo_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 mc->smp_props.dies_supported = true;
888 mc->smp_props.clusters_supported = true;
889 }
890
test_generic_valid(const void * opaque)891 static void test_generic_valid(const void *opaque)
892 {
893 const char *machine_type = opaque;
894 Object *obj = object_new(machine_type);
895 MachineState *ms = MACHINE(obj);
896 MachineClass *mc = MACHINE_GET_CLASS(obj);
897 SMPTestData data = {};
898 int i;
899
900 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
901 data = data_generic_valid[i];
902 unsupported_params_init(mc, &data);
903
904 smp_parse_test(ms, &data, true);
905 }
906
907 object_unref(obj);
908 }
909
test_generic_invalid(const void * opaque)910 static void test_generic_invalid(const void *opaque)
911 {
912 const char *machine_type = opaque;
913 Object *obj = object_new(machine_type);
914 MachineState *ms = MACHINE(obj);
915 MachineClass *mc = MACHINE_GET_CLASS(obj);
916 SMPTestData data = {};
917 int i;
918
919 for (i = 0; i < ARRAY_SIZE(data_generic_invalid); i++) {
920 data = data_generic_invalid[i];
921 unsupported_params_init(mc, &data);
922
923 smp_parse_test(ms, &data, false);
924 }
925
926 object_unref(obj);
927 }
928
test_with_dies(const void * opaque)929 static void test_with_dies(const void *opaque)
930 {
931 const char *machine_type = opaque;
932 Object *obj = object_new(machine_type);
933 MachineState *ms = MACHINE(obj);
934 MachineClass *mc = MACHINE_GET_CLASS(obj);
935 SMPTestData data = {};
936 unsigned int num_dies = 2;
937 int i;
938
939 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
940 data = data_generic_valid[i];
941 unsupported_params_init(mc, &data);
942
943 /* when dies parameter is omitted, it will be set as 1 */
944 data.expect_prefer_sockets.dies = 1;
945 data.expect_prefer_cores.dies = 1;
946
947 smp_parse_test(ms, &data, true);
948
949 /* when dies parameter is specified */
950 data.config.has_dies = true;
951 data.config.dies = num_dies;
952 if (data.config.has_cpus) {
953 data.config.cpus *= num_dies;
954 }
955 if (data.config.has_maxcpus) {
956 data.config.maxcpus *= num_dies;
957 }
958
959 data.expect_prefer_sockets.dies = num_dies;
960 data.expect_prefer_sockets.cpus *= num_dies;
961 data.expect_prefer_sockets.max_cpus *= num_dies;
962 data.expect_prefer_cores.dies = num_dies;
963 data.expect_prefer_cores.cpus *= num_dies;
964 data.expect_prefer_cores.max_cpus *= num_dies;
965
966 smp_parse_test(ms, &data, true);
967 }
968
969 for (i = 0; i < ARRAY_SIZE(data_with_dies_invalid); i++) {
970 data = data_with_dies_invalid[i];
971 unsupported_params_init(mc, &data);
972
973 smp_parse_test(ms, &data, false);
974 }
975
976 object_unref(obj);
977 }
978
test_with_clusters(const void * opaque)979 static void test_with_clusters(const void *opaque)
980 {
981 const char *machine_type = opaque;
982 Object *obj = object_new(machine_type);
983 MachineState *ms = MACHINE(obj);
984 MachineClass *mc = MACHINE_GET_CLASS(obj);
985 SMPTestData data = {};
986 unsigned int num_clusters = 2;
987 int i;
988
989 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
990 data = data_generic_valid[i];
991 unsupported_params_init(mc, &data);
992
993 /* when clusters parameter is omitted, it will be set as 1 */
994 data.expect_prefer_sockets.clusters = 1;
995 data.expect_prefer_cores.clusters = 1;
996
997 smp_parse_test(ms, &data, true);
998
999 /* when clusters parameter is specified */
1000 data.config.has_clusters = true;
1001 data.config.clusters = num_clusters;
1002 if (data.config.has_cpus) {
1003 data.config.cpus *= num_clusters;
1004 }
1005 if (data.config.has_maxcpus) {
1006 data.config.maxcpus *= num_clusters;
1007 }
1008
1009 data.expect_prefer_sockets.clusters = num_clusters;
1010 data.expect_prefer_sockets.cpus *= num_clusters;
1011 data.expect_prefer_sockets.max_cpus *= num_clusters;
1012 data.expect_prefer_cores.clusters = num_clusters;
1013 data.expect_prefer_cores.cpus *= num_clusters;
1014 data.expect_prefer_cores.max_cpus *= num_clusters;
1015
1016 smp_parse_test(ms, &data, true);
1017 }
1018
1019 for (i = 0; i < ARRAY_SIZE(data_with_clusters_invalid); i++) {
1020 data = data_with_clusters_invalid[i];
1021 unsupported_params_init(mc, &data);
1022
1023 smp_parse_test(ms, &data, false);
1024 }
1025
1026 object_unref(obj);
1027 }
1028
test_with_books(const void * opaque)1029 static void test_with_books(const void *opaque)
1030 {
1031 const char *machine_type = opaque;
1032 Object *obj = object_new(machine_type);
1033 MachineState *ms = MACHINE(obj);
1034 MachineClass *mc = MACHINE_GET_CLASS(obj);
1035 SMPTestData data = {};
1036 unsigned int num_books = 2;
1037 int i;
1038
1039 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
1040 data = data_generic_valid[i];
1041 unsupported_params_init(mc, &data);
1042
1043 /* when books parameter is omitted, it will be set as 1 */
1044 data.expect_prefer_sockets.books = 1;
1045 data.expect_prefer_cores.books = 1;
1046
1047 smp_parse_test(ms, &data, true);
1048
1049 /* when books parameter is specified */
1050 data.config.has_books = true;
1051 data.config.books = num_books;
1052 if (data.config.has_cpus) {
1053 data.config.cpus *= num_books;
1054 }
1055 if (data.config.has_maxcpus) {
1056 data.config.maxcpus *= num_books;
1057 }
1058
1059 data.expect_prefer_sockets.books = num_books;
1060 data.expect_prefer_sockets.cpus *= num_books;
1061 data.expect_prefer_sockets.max_cpus *= num_books;
1062 data.expect_prefer_cores.books = num_books;
1063 data.expect_prefer_cores.cpus *= num_books;
1064 data.expect_prefer_cores.max_cpus *= num_books;
1065
1066 smp_parse_test(ms, &data, true);
1067 }
1068
1069 for (i = 0; i < ARRAY_SIZE(data_with_books_invalid); i++) {
1070 data = data_with_books_invalid[i];
1071 unsupported_params_init(mc, &data);
1072
1073 smp_parse_test(ms, &data, false);
1074 }
1075
1076 object_unref(obj);
1077 }
1078
test_with_drawers(const void * opaque)1079 static void test_with_drawers(const void *opaque)
1080 {
1081 const char *machine_type = opaque;
1082 Object *obj = object_new(machine_type);
1083 MachineState *ms = MACHINE(obj);
1084 MachineClass *mc = MACHINE_GET_CLASS(obj);
1085 SMPTestData data = {};
1086 unsigned int num_drawers = 2;
1087 int i;
1088
1089 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
1090 data = data_generic_valid[i];
1091 unsupported_params_init(mc, &data);
1092
1093 /* when drawers parameter is omitted, it will be set as 1 */
1094 data.expect_prefer_sockets.drawers = 1;
1095 data.expect_prefer_cores.drawers = 1;
1096
1097 smp_parse_test(ms, &data, true);
1098
1099 /* when drawers parameter is specified */
1100 data.config.has_drawers = true;
1101 data.config.drawers = num_drawers;
1102 if (data.config.has_cpus) {
1103 data.config.cpus *= num_drawers;
1104 }
1105 if (data.config.has_maxcpus) {
1106 data.config.maxcpus *= num_drawers;
1107 }
1108
1109 data.expect_prefer_sockets.drawers = num_drawers;
1110 data.expect_prefer_sockets.cpus *= num_drawers;
1111 data.expect_prefer_sockets.max_cpus *= num_drawers;
1112 data.expect_prefer_cores.drawers = num_drawers;
1113 data.expect_prefer_cores.cpus *= num_drawers;
1114 data.expect_prefer_cores.max_cpus *= num_drawers;
1115
1116 smp_parse_test(ms, &data, true);
1117 }
1118
1119 for (i = 0; i < ARRAY_SIZE(data_with_drawers_invalid); i++) {
1120 data = data_with_drawers_invalid[i];
1121 unsupported_params_init(mc, &data);
1122
1123 smp_parse_test(ms, &data, false);
1124 }
1125
1126 object_unref(obj);
1127 }
1128
test_with_drawers_books(const void * opaque)1129 static void test_with_drawers_books(const void *opaque)
1130 {
1131 const char *machine_type = opaque;
1132 Object *obj = object_new(machine_type);
1133 MachineState *ms = MACHINE(obj);
1134 MachineClass *mc = MACHINE_GET_CLASS(obj);
1135 SMPTestData data = {};
1136 unsigned int num_drawers = 5, num_books = 3;
1137 int i;
1138
1139 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
1140 data = data_generic_valid[i];
1141 unsupported_params_init(mc, &data);
1142
1143 /*
1144 * when drawers and books parameters are omitted, they will
1145 * be both set as 1.
1146 */
1147 data.expect_prefer_sockets.drawers = 1;
1148 data.expect_prefer_sockets.books = 1;
1149 data.expect_prefer_cores.drawers = 1;
1150 data.expect_prefer_cores.books = 1;
1151
1152 smp_parse_test(ms, &data, true);
1153
1154 /* when drawers and books parameters are both specified */
1155 data.config.has_drawers = true;
1156 data.config.drawers = num_drawers;
1157 data.config.has_books = true;
1158 data.config.books = num_books;
1159
1160 if (data.config.has_cpus) {
1161 data.config.cpus *= num_drawers * num_books;
1162 }
1163 if (data.config.has_maxcpus) {
1164 data.config.maxcpus *= num_drawers * num_books;
1165 }
1166
1167 data.expect_prefer_sockets.drawers = num_drawers;
1168 data.expect_prefer_sockets.books = num_books;
1169 data.expect_prefer_sockets.cpus *= num_drawers * num_books;
1170 data.expect_prefer_sockets.max_cpus *= num_drawers * num_books;
1171
1172 data.expect_prefer_cores.drawers = num_drawers;
1173 data.expect_prefer_cores.books = num_books;
1174 data.expect_prefer_cores.cpus *= num_drawers * num_books;
1175 data.expect_prefer_cores.max_cpus *= num_drawers * num_books;
1176
1177 smp_parse_test(ms, &data, true);
1178 }
1179
1180 for (i = 0; i < ARRAY_SIZE(data_with_drawers_books_invalid); i++) {
1181 data = data_with_drawers_books_invalid[i];
1182 unsupported_params_init(mc, &data);
1183
1184 smp_parse_test(ms, &data, false);
1185 }
1186
1187 object_unref(obj);
1188 }
1189
test_full_topo(const void * opaque)1190 static void test_full_topo(const void *opaque)
1191 {
1192 const char *machine_type = opaque;
1193 Object *obj = object_new(machine_type);
1194 MachineState *ms = MACHINE(obj);
1195 MachineClass *mc = MACHINE_GET_CLASS(obj);
1196 SMPTestData data = {};
1197 unsigned int drawers = 5, books = 3, dies = 2, clusters = 7, multiplier;
1198 int i;
1199
1200 multiplier = drawers * books * dies * clusters;
1201 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
1202 data = data_generic_valid[i];
1203 unsupported_params_init(mc, &data);
1204
1205 /*
1206 * when drawers, books, dies and clusters parameters are omitted,
1207 * they will be set as 1.
1208 */
1209 data.expect_prefer_sockets.drawers = 1;
1210 data.expect_prefer_sockets.books = 1;
1211 data.expect_prefer_sockets.dies = 1;
1212 data.expect_prefer_sockets.clusters = 1;
1213 data.expect_prefer_cores.drawers = 1;
1214 data.expect_prefer_cores.books = 1;
1215 data.expect_prefer_cores.dies = 1;
1216 data.expect_prefer_cores.clusters = 1;
1217
1218 smp_parse_test(ms, &data, true);
1219
1220 /* when drawers, books, dies and clusters parameters are specified. */
1221 data.config.has_drawers = true;
1222 data.config.drawers = drawers;
1223 data.config.has_books = true;
1224 data.config.books = books;
1225 data.config.has_dies = true;
1226 data.config.dies = dies;
1227 data.config.has_clusters = true;
1228 data.config.clusters = clusters;
1229
1230 if (data.config.has_cpus) {
1231 data.config.cpus *= multiplier;
1232 }
1233 if (data.config.has_maxcpus) {
1234 data.config.maxcpus *= multiplier;
1235 }
1236
1237 data.expect_prefer_sockets.drawers = drawers;
1238 data.expect_prefer_sockets.books = books;
1239 data.expect_prefer_sockets.dies = dies;
1240 data.expect_prefer_sockets.clusters = clusters;
1241 data.expect_prefer_sockets.cpus *= multiplier;
1242 data.expect_prefer_sockets.max_cpus *= multiplier;
1243
1244 data.expect_prefer_cores.drawers = drawers;
1245 data.expect_prefer_cores.books = books;
1246 data.expect_prefer_cores.dies = dies;
1247 data.expect_prefer_cores.clusters = clusters;
1248 data.expect_prefer_cores.cpus *= multiplier;
1249 data.expect_prefer_cores.max_cpus *= multiplier;
1250
1251 smp_parse_test(ms, &data, true);
1252 }
1253
1254 for (i = 0; i < ARRAY_SIZE(data_full_topo_invalid); i++) {
1255 data = data_full_topo_invalid[i];
1256 unsupported_params_init(mc, &data);
1257
1258 smp_parse_test(ms, &data, false);
1259 }
1260
1261 for (i = 0; i < ARRAY_SIZE(data_zero_topo_invalid); i++) {
1262 data = data_zero_topo_invalid[i];
1263 unsupported_params_init(mc, &data);
1264
1265 smp_parse_test(ms, &data, false);
1266 }
1267
1268 object_unref(obj);
1269 }
1270
1271 /* Type info of the tested machine */
1272 static const TypeInfo smp_machine_types[] = {
1273 {
1274 .name = TYPE_MACHINE,
1275 .parent = TYPE_OBJECT,
1276 .abstract = true,
1277 .class_init = machine_base_class_init,
1278 .class_size = sizeof(MachineClass),
1279 .instance_size = sizeof(MachineState),
1280 }, {
1281 .name = MACHINE_TYPE_NAME("smp-generic-valid"),
1282 .parent = TYPE_MACHINE,
1283 }, {
1284 .name = MACHINE_TYPE_NAME("smp-generic-invalid"),
1285 .parent = TYPE_MACHINE,
1286 .class_init = machine_generic_invalid_class_init,
1287 }, {
1288 .name = MACHINE_TYPE_NAME("smp-with-dies"),
1289 .parent = TYPE_MACHINE,
1290 .class_init = machine_with_dies_class_init,
1291 }, {
1292 .name = MACHINE_TYPE_NAME("smp-with-clusters"),
1293 .parent = TYPE_MACHINE,
1294 .class_init = machine_with_clusters_class_init,
1295 }, {
1296 .name = MACHINE_TYPE_NAME("smp-with-books"),
1297 .parent = TYPE_MACHINE,
1298 .class_init = machine_with_books_class_init,
1299 }, {
1300 .name = MACHINE_TYPE_NAME("smp-with-drawers"),
1301 .parent = TYPE_MACHINE,
1302 .class_init = machine_with_drawers_class_init,
1303 }, {
1304 .name = MACHINE_TYPE_NAME("smp-with-drawers-books"),
1305 .parent = TYPE_MACHINE,
1306 .class_init = machine_with_drawers_books_class_init,
1307 }, {
1308 .name = MACHINE_TYPE_NAME("smp-full-topo"),
1309 .parent = TYPE_MACHINE,
1310 .class_init = machine_full_topo_class_init,
1311 }
1312 };
1313
DEFINE_TYPES(smp_machine_types)1314 DEFINE_TYPES(smp_machine_types)
1315
1316 int main(int argc, char *argv[])
1317 {
1318 module_call_init(MODULE_INIT_QOM);
1319
1320 g_test_init(&argc, &argv, NULL);
1321
1322 g_test_add_data_func("/test-smp-parse/generic/valid",
1323 MACHINE_TYPE_NAME("smp-generic-valid"),
1324 test_generic_valid);
1325 g_test_add_data_func("/test-smp-parse/generic/invalid",
1326 MACHINE_TYPE_NAME("smp-generic-invalid"),
1327 test_generic_invalid);
1328 g_test_add_data_func("/test-smp-parse/with_dies",
1329 MACHINE_TYPE_NAME("smp-with-dies"),
1330 test_with_dies);
1331 g_test_add_data_func("/test-smp-parse/with_clusters",
1332 MACHINE_TYPE_NAME("smp-with-clusters"),
1333 test_with_clusters);
1334 g_test_add_data_func("/test-smp-parse/with_books",
1335 MACHINE_TYPE_NAME("smp-with-books"),
1336 test_with_books);
1337 g_test_add_data_func("/test-smp-parse/with_drawers",
1338 MACHINE_TYPE_NAME("smp-with-drawers"),
1339 test_with_drawers);
1340 g_test_add_data_func("/test-smp-parse/with_drawers_books",
1341 MACHINE_TYPE_NAME("smp-with-drawers-books"),
1342 test_with_drawers_books);
1343 g_test_add_data_func("/test-smp-parse/full",
1344 MACHINE_TYPE_NAME("smp-full-topo"),
1345 test_full_topo);
1346
1347 g_test_run();
1348
1349 return 0;
1350 }
1351