numa-test.c 9.9 KB

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