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