qemu/tests/cpu-plug-test.c
<<
>>
Prefs
   1/*
   2 * QTest testcase for CPU plugging
   3 *
   4 * Copyright (c) 2015 SUSE Linux GmbH
   5 *
   6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   7 * See the COPYING file in the top-level directory.
   8 */
   9
  10#include "qemu/osdep.h"
  11
  12#include "qemu-common.h"
  13#include "libqtest-single.h"
  14#include "qapi/qmp/qdict.h"
  15#include "qapi/qmp/qlist.h"
  16
  17struct PlugTestData {
  18    char *machine;
  19    const char *cpu_model;
  20    char *device_model;
  21    unsigned sockets;
  22    unsigned cores;
  23    unsigned threads;
  24    unsigned maxcpus;
  25};
  26typedef struct PlugTestData PlugTestData;
  27
  28static void test_plug_with_cpu_add(gconstpointer data)
  29{
  30    const PlugTestData *s = data;
  31    char *args;
  32    QDict *response;
  33    unsigned int i;
  34
  35    args = g_strdup_printf("-machine %s -cpu %s "
  36                           "-smp 1,sockets=%u,cores=%u,threads=%u,maxcpus=%u",
  37                           s->machine, s->cpu_model,
  38                           s->sockets, s->cores, s->threads, s->maxcpus);
  39    qtest_start(args);
  40
  41    for (i = 1; i < s->maxcpus; i++) {
  42        response = qmp("{ 'execute': 'cpu-add',"
  43                       "  'arguments': { 'id': %d } }", i);
  44        g_assert(response);
  45        g_assert(!qdict_haskey(response, "error"));
  46        qobject_unref(response);
  47    }
  48
  49    qtest_end();
  50    g_free(args);
  51}
  52
  53static void test_plug_without_cpu_add(gconstpointer data)
  54{
  55    const PlugTestData *s = data;
  56    char *args;
  57    QDict *response;
  58
  59    args = g_strdup_printf("-machine %s -cpu %s "
  60                           "-smp 1,sockets=%u,cores=%u,threads=%u,maxcpus=%u",
  61                           s->machine, s->cpu_model,
  62                           s->sockets, s->cores, s->threads, s->maxcpus);
  63    qtest_start(args);
  64
  65    response = qmp("{ 'execute': 'cpu-add',"
  66                   "  'arguments': { 'id': %d } }",
  67                   s->sockets * s->cores * s->threads);
  68    g_assert(response);
  69    g_assert(qdict_haskey(response, "error"));
  70    qobject_unref(response);
  71
  72    qtest_end();
  73    g_free(args);
  74}
  75
  76static void test_plug_with_device_add(gconstpointer data)
  77{
  78    const PlugTestData *td = data;
  79    char *args;
  80    QTestState *qts;
  81    QDict *resp;
  82    QList *cpus;
  83    QObject *e;
  84    int hotplugged = 0;
  85
  86    args = g_strdup_printf("-machine %s -cpu %s "
  87                           "-smp 1,sockets=%u,cores=%u,threads=%u,maxcpus=%u",
  88                           td->machine, td->cpu_model,
  89                           td->sockets, td->cores, td->threads, td->maxcpus);
  90    qts = qtest_init(args);
  91
  92    resp = qtest_qmp(qts, "{ 'execute': 'query-hotpluggable-cpus'}");
  93    g_assert(qdict_haskey(resp, "return"));
  94    cpus = qdict_get_qlist(resp, "return");
  95    g_assert(cpus);
  96
  97    while ((e = qlist_pop(cpus))) {
  98        const QDict *cpu, *props;
  99
 100        cpu = qobject_to(QDict, e);
 101        if (qdict_haskey(cpu, "qom-path")) {
 102            qobject_unref(e);
 103            continue;
 104        }
 105
 106        g_assert(qdict_haskey(cpu, "props"));
 107        props = qdict_get_qdict(cpu, "props");
 108
 109        qtest_qmp_device_add_qdict(qts, td->device_model, props);
 110        hotplugged++;
 111        qobject_unref(e);
 112    }
 113
 114    /* make sure that there were hotplugged CPUs */
 115    g_assert(hotplugged);
 116    qobject_unref(resp);
 117    qtest_quit(qts);
 118    g_free(args);
 119}
 120
 121static void test_data_free(gpointer data)
 122{
 123    PlugTestData *pc = data;
 124
 125    g_free(pc->machine);
 126    g_free(pc->device_model);
 127    g_free(pc);
 128}
 129
 130static void add_pc_test_case(const char *mname)
 131{
 132    char *path;
 133    PlugTestData *data;
 134
 135    if (!g_str_has_prefix(mname, "pc-")) {
 136        return;
 137    }
 138    data = g_new(PlugTestData, 1);
 139    data->machine = g_strdup(mname);
 140    data->cpu_model = "Haswell"; /* 1.3+ theoretically */
 141    data->device_model = g_strdup_printf("%s-%s-cpu", data->cpu_model,
 142                                         qtest_get_arch());
 143    data->sockets = 1;
 144    data->cores = 3;
 145    data->threads = 2;
 146    data->maxcpus = data->sockets * data->cores * data->threads;
 147    if (g_str_has_suffix(mname, "-1.4") ||
 148        (strcmp(mname, "pc-1.3") == 0) ||
 149        (strcmp(mname, "pc-1.2") == 0) ||
 150        (strcmp(mname, "pc-1.1") == 0) ||
 151        (strcmp(mname, "pc-1.0") == 0) ||
 152        (strcmp(mname, "pc-0.15") == 0) ||
 153        (strcmp(mname, "pc-0.14") == 0) ||
 154        (strcmp(mname, "pc-0.13") == 0) ||
 155        (strcmp(mname, "pc-0.12") == 0)) {
 156        path = g_strdup_printf("cpu-plug/%s/init/%ux%ux%u&maxcpus=%u",
 157                               mname, data->sockets, data->cores,
 158                               data->threads, data->maxcpus);
 159        qtest_add_data_func_full(path, data, test_plug_without_cpu_add,
 160                                 test_data_free);
 161        g_free(path);
 162    } else {
 163        PlugTestData *data2 = g_memdup(data, sizeof(PlugTestData));
 164
 165        data2->machine = g_strdup(data->machine);
 166        data2->device_model = g_strdup(data->device_model);
 167
 168        path = g_strdup_printf("cpu-plug/%s/cpu-add/%ux%ux%u&maxcpus=%u",
 169                               mname, data->sockets, data->cores,
 170                               data->threads, data->maxcpus);
 171        qtest_add_data_func_full(path, data, test_plug_with_cpu_add,
 172                                 test_data_free);
 173        g_free(path);
 174        path = g_strdup_printf("cpu-plug/%s/device-add/%ux%ux%u&maxcpus=%u",
 175                               mname, data2->sockets, data2->cores,
 176                               data2->threads, data2->maxcpus);
 177        qtest_add_data_func_full(path, data2, test_plug_with_device_add,
 178                                 test_data_free);
 179        g_free(path);
 180    }
 181}
 182
 183static void add_pseries_test_case(const char *mname)
 184{
 185    char *path;
 186    PlugTestData *data;
 187
 188    if (!g_str_has_prefix(mname, "pseries-") ||
 189        (g_str_has_prefix(mname, "pseries-2.") && atoi(&mname[10]) < 7)) {
 190        return;
 191    }
 192    data = g_new(PlugTestData, 1);
 193    data->machine = g_strdup(mname);
 194    data->cpu_model = "power8_v2.0";
 195    data->device_model = g_strdup("power8_v2.0-spapr-cpu-core");
 196    data->sockets = 2;
 197    data->cores = 3;
 198    data->threads = 1;
 199    data->maxcpus = data->sockets * data->cores * data->threads;
 200
 201    path = g_strdup_printf("cpu-plug/%s/device-add/%ux%ux%u&maxcpus=%u",
 202                           mname, data->sockets, data->cores,
 203                           data->threads, data->maxcpus);
 204    qtest_add_data_func_full(path, data, test_plug_with_device_add,
 205                             test_data_free);
 206    g_free(path);
 207}
 208
 209static void add_s390x_test_case(const char *mname)
 210{
 211    char *path;
 212    PlugTestData *data, *data2;
 213
 214    if (!g_str_has_prefix(mname, "s390-ccw-virtio-")) {
 215        return;
 216    }
 217
 218    data = g_new(PlugTestData, 1);
 219    data->machine = g_strdup(mname);
 220    data->cpu_model = "qemu";
 221    data->device_model = g_strdup("qemu-s390x-cpu");
 222    data->sockets = 1;
 223    data->cores = 3;
 224    data->threads = 1;
 225    data->maxcpus = data->sockets * data->cores * data->threads;
 226
 227    data2 = g_memdup(data, sizeof(PlugTestData));
 228    data2->machine = g_strdup(data->machine);
 229    data2->device_model = g_strdup(data->device_model);
 230
 231    path = g_strdup_printf("cpu-plug/%s/cpu-add/%ux%ux%u&maxcpus=%u",
 232                           mname, data->sockets, data->cores,
 233                           data->threads, data->maxcpus);
 234    qtest_add_data_func_full(path, data, test_plug_with_cpu_add,
 235                             test_data_free);
 236    g_free(path);
 237
 238    path = g_strdup_printf("cpu-plug/%s/device-add/%ux%ux%u&maxcpus=%u",
 239                           mname, data2->sockets, data2->cores,
 240                           data2->threads, data2->maxcpus);
 241    qtest_add_data_func_full(path, data2, test_plug_with_device_add,
 242                             test_data_free);
 243    g_free(path);
 244}
 245
 246int main(int argc, char **argv)
 247{
 248    const char *arch = qtest_get_arch();
 249
 250    g_test_init(&argc, &argv, NULL);
 251
 252    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
 253        qtest_cb_for_every_machine(add_pc_test_case, g_test_quick());
 254    } else if (g_str_equal(arch, "ppc64")) {
 255        qtest_cb_for_every_machine(add_pseries_test_case, g_test_quick());
 256    } else if (g_str_equal(arch, "s390x")) {
 257        qtest_cb_for_every_machine(add_s390x_test_case, g_test_quick());
 258    }
 259
 260    return g_test_run();
 261}
 262