]>
Commit | Line | Data |
---|---|---|
63baf8bf IM |
1 | /* |
2 | * NUMA configuration test cases | |
3 | * | |
4 | * Copyright (c) 2017 Red Hat Inc. | |
5 | * Authors: | |
6 | * Igor Mammedov <[email protected]> | |
7 | * | |
8 | * This work is licensed under the terms of the GNU GPL, version 2 or later. | |
9 | * See the COPYING file in the top-level directory. | |
10 | */ | |
11 | ||
12 | #include "qemu/osdep.h" | |
13 | #include "libqtest.h" | |
452fcdbc | 14 | #include "qapi/qmp/qdict.h" |
47e6b297 | 15 | #include "qapi/qmp/qlist.h" |
63baf8bf IM |
16 | |
17 | static char *make_cli(const char *generic_cli, const char *test_cli) | |
18 | { | |
19 | return g_strdup_printf("%s %s", generic_cli ? generic_cli : "", test_cli); | |
20 | } | |
21 | ||
63baf8bf IM |
22 | static void test_mon_explicit(const void *data) |
23 | { | |
24 | char *s; | |
25 | char *cli; | |
26 | ||
27 | cli = make_cli(data, "-smp 8 " | |
28 | "-numa node,nodeid=0,cpus=0-3 " | |
29 | "-numa node,nodeid=1,cpus=4-7 "); | |
30 | qtest_start(cli); | |
31 | ||
e8fc894b | 32 | s = hmp("info numa"); |
63baf8bf IM |
33 | g_assert(strstr(s, "node 0 cpus: 0 1 2 3")); |
34 | g_assert(strstr(s, "node 1 cpus: 4 5 6 7")); | |
35 | g_free(s); | |
36 | ||
37 | qtest_end(); | |
38 | g_free(cli); | |
39 | } | |
40 | ||
41 | static void test_mon_default(const void *data) | |
42 | { | |
43 | char *s; | |
44 | char *cli; | |
45 | ||
46 | cli = make_cli(data, "-smp 8 -numa node -numa node"); | |
47 | qtest_start(cli); | |
48 | ||
e8fc894b | 49 | s = hmp("info numa"); |
63baf8bf IM |
50 | g_assert(strstr(s, "node 0 cpus: 0 2 4 6")); |
51 | g_assert(strstr(s, "node 1 cpus: 1 3 5 7")); | |
52 | g_free(s); | |
53 | ||
54 | qtest_end(); | |
55 | g_free(cli); | |
56 | } | |
57 | ||
58 | static void test_mon_partial(const void *data) | |
59 | { | |
60 | char *s; | |
61 | char *cli; | |
62 | ||
63 | cli = make_cli(data, "-smp 8 " | |
64 | "-numa node,nodeid=0,cpus=0-1 " | |
65 | "-numa node,nodeid=1,cpus=4-5 "); | |
66 | qtest_start(cli); | |
67 | ||
e8fc894b | 68 | s = hmp("info numa"); |
63baf8bf IM |
69 | g_assert(strstr(s, "node 0 cpus: 0 1 2 3 6 7")); |
70 | g_assert(strstr(s, "node 1 cpus: 4 5")); | |
71 | g_free(s); | |
72 | ||
73 | qtest_end(); | |
74 | g_free(cli); | |
75 | } | |
76 | ||
6accfb78 IM |
77 | static QList *get_cpus(QDict **resp) |
78 | { | |
79 | *resp = qmp("{ 'execute': 'query-cpus' }"); | |
80 | g_assert(*resp); | |
81 | g_assert(qdict_haskey(*resp, "return")); | |
5e39d89d | 82 | return qdict_get_qlist(*resp, "return"); |
6accfb78 IM |
83 | } |
84 | ||
85 | static void test_query_cpus(const void *data) | |
86 | { | |
87 | char *cli; | |
88 | QDict *resp; | |
89 | QList *cpus; | |
5e39d89d | 90 | QObject *e; |
6accfb78 IM |
91 | |
92 | cli = make_cli(data, "-smp 8 -numa node,cpus=0-3 -numa node,cpus=4-7"); | |
93 | qtest_start(cli); | |
94 | cpus = get_cpus(&resp); | |
95 | g_assert(cpus); | |
96 | ||
97 | while ((e = qlist_pop(cpus))) { | |
98 | QDict *cpu, *props; | |
99 | int64_t cpu_idx, node; | |
100 | ||
7dc847eb | 101 | cpu = qobject_to(QDict, e); |
6accfb78 IM |
102 | g_assert(qdict_haskey(cpu, "CPU")); |
103 | g_assert(qdict_haskey(cpu, "props")); | |
104 | ||
105 | cpu_idx = qdict_get_int(cpu, "CPU"); | |
106 | props = qdict_get_qdict(cpu, "props"); | |
107 | g_assert(qdict_haskey(props, "node-id")); | |
108 | node = qdict_get_int(props, "node-id"); | |
109 | if (cpu_idx >= 0 && cpu_idx < 4) { | |
110 | g_assert_cmpint(node, ==, 0); | |
111 | } else { | |
112 | g_assert_cmpint(node, ==, 1); | |
113 | } | |
cb3e7f08 | 114 | qobject_unref(e); |
6accfb78 IM |
115 | } |
116 | ||
cb3e7f08 | 117 | qobject_unref(resp); |
6accfb78 IM |
118 | qtest_end(); |
119 | g_free(cli); | |
120 | } | |
121 | ||
2941020a IM |
122 | static void pc_numa_cpu(const void *data) |
123 | { | |
124 | char *cli; | |
125 | QDict *resp; | |
126 | QList *cpus; | |
5e39d89d | 127 | QObject *e; |
2941020a IM |
128 | |
129 | cli = make_cli(data, "-cpu pentium -smp 8,sockets=2,cores=2,threads=2 " | |
130 | "-numa node,nodeid=0 -numa node,nodeid=1 " | |
131 | "-numa cpu,node-id=1,socket-id=0 " | |
132 | "-numa cpu,node-id=0,socket-id=1,core-id=0 " | |
133 | "-numa cpu,node-id=0,socket-id=1,core-id=1,thread-id=0 " | |
134 | "-numa cpu,node-id=1,socket-id=1,core-id=1,thread-id=1"); | |
135 | qtest_start(cli); | |
136 | cpus = get_cpus(&resp); | |
137 | g_assert(cpus); | |
138 | ||
139 | while ((e = qlist_pop(cpus))) { | |
140 | QDict *cpu, *props; | |
141 | int64_t socket, core, thread, node; | |
142 | ||
7dc847eb | 143 | cpu = qobject_to(QDict, e); |
2941020a IM |
144 | g_assert(qdict_haskey(cpu, "props")); |
145 | props = qdict_get_qdict(cpu, "props"); | |
146 | ||
147 | g_assert(qdict_haskey(props, "node-id")); | |
148 | node = qdict_get_int(props, "node-id"); | |
149 | g_assert(qdict_haskey(props, "socket-id")); | |
150 | socket = qdict_get_int(props, "socket-id"); | |
151 | g_assert(qdict_haskey(props, "core-id")); | |
152 | core = qdict_get_int(props, "core-id"); | |
153 | g_assert(qdict_haskey(props, "thread-id")); | |
154 | thread = qdict_get_int(props, "thread-id"); | |
155 | ||
156 | if (socket == 0) { | |
157 | g_assert_cmpint(node, ==, 1); | |
158 | } else if (socket == 1 && core == 0) { | |
159 | g_assert_cmpint(node, ==, 0); | |
160 | } else if (socket == 1 && core == 1 && thread == 0) { | |
161 | g_assert_cmpint(node, ==, 0); | |
162 | } else if (socket == 1 && core == 1 && thread == 1) { | |
163 | g_assert_cmpint(node, ==, 1); | |
164 | } else { | |
165 | g_assert(false); | |
166 | } | |
cb3e7f08 | 167 | qobject_unref(e); |
2941020a IM |
168 | } |
169 | ||
cb3e7f08 | 170 | qobject_unref(resp); |
2941020a IM |
171 | qtest_end(); |
172 | g_free(cli); | |
173 | } | |
174 | ||
175 | static void spapr_numa_cpu(const void *data) | |
176 | { | |
177 | char *cli; | |
178 | QDict *resp; | |
179 | QList *cpus; | |
5e39d89d | 180 | QObject *e; |
2941020a IM |
181 | |
182 | cli = make_cli(data, "-smp 4,cores=4 " | |
183 | "-numa node,nodeid=0 -numa node,nodeid=1 " | |
184 | "-numa cpu,node-id=0,core-id=0 " | |
185 | "-numa cpu,node-id=0,core-id=1 " | |
186 | "-numa cpu,node-id=0,core-id=2 " | |
187 | "-numa cpu,node-id=1,core-id=3"); | |
188 | qtest_start(cli); | |
189 | cpus = get_cpus(&resp); | |
190 | g_assert(cpus); | |
191 | ||
192 | while ((e = qlist_pop(cpus))) { | |
193 | QDict *cpu, *props; | |
194 | int64_t core, node; | |
195 | ||
7dc847eb | 196 | cpu = qobject_to(QDict, e); |
2941020a IM |
197 | g_assert(qdict_haskey(cpu, "props")); |
198 | props = qdict_get_qdict(cpu, "props"); | |
199 | ||
200 | g_assert(qdict_haskey(props, "node-id")); | |
201 | node = qdict_get_int(props, "node-id"); | |
202 | g_assert(qdict_haskey(props, "core-id")); | |
203 | core = qdict_get_int(props, "core-id"); | |
204 | ||
205 | if (core >= 0 && core < 3) { | |
206 | g_assert_cmpint(node, ==, 0); | |
207 | } else if (core == 3) { | |
208 | g_assert_cmpint(node, ==, 1); | |
209 | } else { | |
210 | g_assert(false); | |
211 | } | |
cb3e7f08 | 212 | qobject_unref(e); |
2941020a IM |
213 | } |
214 | ||
cb3e7f08 | 215 | qobject_unref(resp); |
2941020a IM |
216 | qtest_end(); |
217 | g_free(cli); | |
218 | } | |
219 | ||
220 | static void aarch64_numa_cpu(const void *data) | |
221 | { | |
222 | char *cli; | |
223 | QDict *resp; | |
224 | QList *cpus; | |
5e39d89d | 225 | QObject *e; |
2941020a IM |
226 | |
227 | cli = make_cli(data, "-smp 2 " | |
228 | "-numa node,nodeid=0 -numa node,nodeid=1 " | |
229 | "-numa cpu,node-id=1,thread-id=0 " | |
230 | "-numa cpu,node-id=0,thread-id=1"); | |
231 | qtest_start(cli); | |
232 | cpus = get_cpus(&resp); | |
233 | g_assert(cpus); | |
234 | ||
235 | while ((e = qlist_pop(cpus))) { | |
236 | QDict *cpu, *props; | |
237 | int64_t thread, node; | |
238 | ||
7dc847eb | 239 | cpu = qobject_to(QDict, e); |
2941020a IM |
240 | g_assert(qdict_haskey(cpu, "props")); |
241 | props = qdict_get_qdict(cpu, "props"); | |
242 | ||
243 | g_assert(qdict_haskey(props, "node-id")); | |
244 | node = qdict_get_int(props, "node-id"); | |
245 | g_assert(qdict_haskey(props, "thread-id")); | |
246 | thread = qdict_get_int(props, "thread-id"); | |
247 | ||
248 | if (thread == 0) { | |
249 | g_assert_cmpint(node, ==, 1); | |
250 | } else if (thread == 1) { | |
251 | g_assert_cmpint(node, ==, 0); | |
252 | } else { | |
253 | g_assert(false); | |
254 | } | |
cb3e7f08 | 255 | qobject_unref(e); |
2941020a IM |
256 | } |
257 | ||
cb3e7f08 | 258 | qobject_unref(resp); |
2941020a IM |
259 | qtest_end(); |
260 | g_free(cli); | |
261 | } | |
262 | ||
c35665e1 IM |
263 | static void pc_dynamic_cpu_cfg(const void *data) |
264 | { | |
265 | QObject *e; | |
266 | QDict *resp; | |
267 | QList *cpus; | |
268 | QTestState *qs; | |
269 | ||
270 | qs = qtest_startf("%s %s", data ? (char *)data : "", | |
271 | "-nodefaults --preconfig -smp 2"); | |
272 | ||
273 | /* create 2 numa nodes */ | |
274 | g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node'," | |
275 | " 'arguments': { 'type': 'node', 'nodeid': 0 } }"))); | |
276 | g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node'," | |
277 | " 'arguments': { 'type': 'node', 'nodeid': 1 } }"))); | |
278 | ||
279 | /* map 2 cpus in non default reverse order | |
280 | * i.e socket1->node0, socket0->node1 | |
281 | */ | |
282 | g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node'," | |
283 | " 'arguments': { 'type': 'cpu', 'node-id': 0, 'socket-id': 1 } }"))); | |
284 | g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node'," | |
285 | " 'arguments': { 'type': 'cpu', 'node-id': 1, 'socket-id': 0 } }"))); | |
286 | ||
287 | /* let machine initialization to complete and run */ | |
361ac948 | 288 | g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'x-exit-preconfig' }"))); |
c35665e1 IM |
289 | qtest_qmp_eventwait(qs, "RESUME"); |
290 | ||
291 | /* check that CPUs are mapped as expected */ | |
292 | resp = qtest_qmp(qs, "{ 'execute': 'query-hotpluggable-cpus'}"); | |
293 | g_assert(qdict_haskey(resp, "return")); | |
294 | cpus = qdict_get_qlist(resp, "return"); | |
295 | g_assert(cpus); | |
296 | while ((e = qlist_pop(cpus))) { | |
297 | const QDict *cpu, *props; | |
298 | int64_t socket, node; | |
299 | ||
300 | cpu = qobject_to(QDict, e); | |
301 | g_assert(qdict_haskey(cpu, "props")); | |
302 | props = qdict_get_qdict(cpu, "props"); | |
303 | ||
304 | g_assert(qdict_haskey(props, "node-id")); | |
305 | node = qdict_get_int(props, "node-id"); | |
306 | g_assert(qdict_haskey(props, "socket-id")); | |
307 | socket = qdict_get_int(props, "socket-id"); | |
308 | ||
309 | if (socket == 0) { | |
310 | g_assert_cmpint(node, ==, 1); | |
311 | } else if (socket == 1) { | |
312 | g_assert_cmpint(node, ==, 0); | |
313 | } else { | |
314 | g_assert(false); | |
315 | } | |
316 | qobject_unref(e); | |
317 | } | |
318 | qobject_unref(resp); | |
319 | ||
320 | qtest_quit(qs); | |
321 | } | |
322 | ||
63baf8bf IM |
323 | int main(int argc, char **argv) |
324 | { | |
325 | const char *args = NULL; | |
326 | const char *arch = qtest_get_arch(); | |
327 | ||
328 | if (strcmp(arch, "aarch64") == 0) { | |
329 | args = "-machine virt"; | |
330 | } | |
331 | ||
332 | g_test_init(&argc, &argv, NULL); | |
333 | ||
334 | qtest_add_data_func("/numa/mon/default", args, test_mon_default); | |
335 | qtest_add_data_func("/numa/mon/cpus/explicit", args, test_mon_explicit); | |
336 | qtest_add_data_func("/numa/mon/cpus/partial", args, test_mon_partial); | |
6accfb78 | 337 | qtest_add_data_func("/numa/qmp/cpus/query-cpus", args, test_query_cpus); |
63baf8bf | 338 | |
2941020a IM |
339 | if (!strcmp(arch, "i386") || !strcmp(arch, "x86_64")) { |
340 | qtest_add_data_func("/numa/pc/cpu/explicit", args, pc_numa_cpu); | |
c35665e1 | 341 | qtest_add_data_func("/numa/pc/dynamic/cpu", args, pc_dynamic_cpu_cfg); |
2941020a IM |
342 | } |
343 | ||
344 | if (!strcmp(arch, "ppc64")) { | |
345 | qtest_add_data_func("/numa/spapr/cpu/explicit", args, spapr_numa_cpu); | |
346 | } | |
347 | ||
348 | if (!strcmp(arch, "aarch64")) { | |
349 | qtest_add_data_func("/numa/aarch64/cpu/explicit", args, | |
350 | aarch64_numa_cpu); | |
351 | } | |
352 | ||
63baf8bf IM |
353 | return g_test_run(); |
354 | } |