qemu/tests/numa-test.c
<<
>>
Prefs
   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
  12#include "qemu/osdep.h"
  13#include "libqtest.h"
  14#include "qapi/qmp/qdict.h"
  15#include "qapi/qmp/qlist.h"
  16
  17static 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
  22static 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
  32    s = hmp("info numa");
  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
  41static 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
  49    s = hmp("info numa");
  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
  58static 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
  68    s = hmp("info numa");
  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
  77static QList *get_cpus(QDict **resp)
  78{
  79    *resp = qmp("{ 'execute': 'query-cpus' }");
  80    g_assert(*resp);
  81    g_assert(qdict_haskey(*resp, "return"));
  82    return qdict_get_qlist(*resp, "return");
  83}
  84
  85static void test_query_cpus(const void *data)
  86{
  87    char *cli;
  88    QDict *resp;
  89    QList *cpus;
  90    QObject *e;
  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
 101        cpu = qobject_to(QDict, e);
 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        }
 114        qobject_unref(e);
 115    }
 116
 117    qobject_unref(resp);
 118    qtest_end();
 119    g_free(cli);
 120}
 121
 122static void pc_numa_cpu(const void *data)
 123{
 124    char *cli;
 125    QDict *resp;
 126    QList *cpus;
 127    QObject *e;
 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
 143        cpu = qobject_to(QDict, e);
 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        }
 167        qobject_unref(e);
 168    }
 169
 170    qobject_unref(resp);
 171    qtest_end();
 172    g_free(cli);
 173}
 174
 175static void spapr_numa_cpu(const void *data)
 176{
 177    char *cli;
 178    QDict *resp;
 179    QList *cpus;
 180    QObject *e;
 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
 196        cpu = qobject_to(QDict, e);
 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        }
 212        qobject_unref(e);
 213    }
 214
 215    qobject_unref(resp);
 216    qtest_end();
 217    g_free(cli);
 218}
 219
 220static void aarch64_numa_cpu(const void *data)
 221{
 222    char *cli;
 223    QDict *resp;
 224    QList *cpus;
 225    QObject *e;
 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
 239        cpu = qobject_to(QDict, e);
 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        }
 255        qobject_unref(e);
 256    }
 257
 258    qobject_unref(resp);
 259    qtest_end();
 260    g_free(cli);
 261}
 262
 263static 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_initf("%s -nodefaults --preconfig -smp 2",
 271                     data ? (char *)data : "");
 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 */
 288    g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'x-exit-preconfig' }")));
 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
 323int 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);
 337    qtest_add_data_func("/numa/qmp/cpus/query-cpus", args, test_query_cpus);
 338
 339    if (!strcmp(arch, "i386") || !strcmp(arch, "x86_64")) {
 340        qtest_add_data_func("/numa/pc/cpu/explicit", args, pc_numa_cpu);
 341        qtest_add_data_func("/numa/pc/dynamic/cpu", args, pc_dynamic_cpu_cfg);
 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
 353    return g_test_run();
 354}
 355