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