mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-27 19:11:16 +00:00
858 lines
30 KiB
C
858 lines
30 KiB
C
/*
|
|
* cputest.c: Test the libvirtd internal CPU APIs
|
|
*
|
|
* Copyright (C) 2010-2014 Red Hat, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library. If not, see
|
|
* <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Author: Jiri Denemark <jdenemar@redhat.com>
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <fcntl.h>
|
|
|
|
#include "internal.h"
|
|
#include "virxml.h"
|
|
#include "viralloc.h"
|
|
#include "virbuffer.h"
|
|
#include "testutils.h"
|
|
#include "cpu_conf.h"
|
|
#include "cpu/cpu.h"
|
|
#include "cpu/cpu_map.h"
|
|
#include "virstring.h"
|
|
|
|
#if WITH_QEMU && WITH_YAJL
|
|
# include "testutilsqemu.h"
|
|
# include "qemumonitortestutils.h"
|
|
# include "qemu/qemu_monitor_json.h"
|
|
#endif
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_CPU
|
|
|
|
enum cpuTestBoolWithError {
|
|
FAIL = -1,
|
|
NO = 0,
|
|
YES = 1
|
|
};
|
|
|
|
|
|
struct data {
|
|
const char *arch;
|
|
const char *host;
|
|
const char *name;
|
|
const char **models;
|
|
const char *modelsName;
|
|
unsigned int nmodels;
|
|
const char *preferred;
|
|
unsigned int flags;
|
|
int result;
|
|
};
|
|
|
|
#if WITH_QEMU && WITH_YAJL
|
|
static virQEMUDriver driver;
|
|
#endif
|
|
|
|
|
|
static virCPUDefPtr
|
|
cpuTestLoadXML(const char *arch, const char *name)
|
|
{
|
|
char *xml = NULL;
|
|
xmlDocPtr doc = NULL;
|
|
xmlXPathContextPtr ctxt = NULL;
|
|
virCPUDefPtr cpu = NULL;
|
|
|
|
if (virAsprintf(&xml, "%s/cputestdata/%s-%s.xml", abs_srcdir, arch, name) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(doc = virXMLParseFileCtxt(xml, &ctxt)))
|
|
goto cleanup;
|
|
|
|
cpu = virCPUDefParseXML(ctxt->node, ctxt, VIR_CPU_TYPE_AUTO);
|
|
|
|
cleanup:
|
|
xmlXPathFreeContext(ctxt);
|
|
xmlFreeDoc(doc);
|
|
VIR_FREE(xml);
|
|
return cpu;
|
|
}
|
|
|
|
|
|
static virCPUDefPtr *
|
|
cpuTestLoadMultiXML(const char *arch,
|
|
const char *name,
|
|
unsigned int *count)
|
|
{
|
|
char *xml = NULL;
|
|
xmlDocPtr doc = NULL;
|
|
xmlXPathContextPtr ctxt = NULL;
|
|
xmlNodePtr *nodes = NULL;
|
|
virCPUDefPtr *cpus = NULL;
|
|
int n;
|
|
size_t i;
|
|
|
|
if (virAsprintf(&xml, "%s/cputestdata/%s-%s.xml", abs_srcdir, arch, name) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(doc = virXMLParseFileCtxt(xml, &ctxt)))
|
|
goto cleanup;
|
|
|
|
n = virXPathNodeSet("/cpuTest/cpu", ctxt, &nodes);
|
|
if (n <= 0 || (VIR_ALLOC_N(cpus, n) < 0)) {
|
|
fprintf(stderr, "\nNo /cpuTest/cpu elements found in %s\n", xml);
|
|
goto cleanup;
|
|
}
|
|
|
|
for (i = 0; i < n; i++) {
|
|
ctxt->node = nodes[i];
|
|
cpus[i] = virCPUDefParseXML(nodes[i], ctxt, VIR_CPU_TYPE_HOST);
|
|
if (!cpus[i])
|
|
goto cleanup_cpus;
|
|
}
|
|
|
|
*count = n;
|
|
|
|
cleanup:
|
|
VIR_FREE(xml);
|
|
VIR_FREE(nodes);
|
|
xmlXPathFreeContext(ctxt);
|
|
xmlFreeDoc(doc);
|
|
return cpus;
|
|
|
|
cleanup_cpus:
|
|
for (i = 0; i < n; i++)
|
|
virCPUDefFree(cpus[i]);
|
|
VIR_FREE(cpus);
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
static int
|
|
cpuTestCompareXML(const char *arch,
|
|
virCPUDef *cpu,
|
|
const char *name,
|
|
bool updateCPU)
|
|
{
|
|
char *xml = NULL;
|
|
char *actual = NULL;
|
|
int ret = -1;
|
|
|
|
if (virAsprintf(&xml, "%s/cputestdata/%s-%s.xml",
|
|
abs_srcdir, arch, name) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(actual = virCPUDefFormat(cpu, NULL, updateCPU)))
|
|
goto cleanup;
|
|
|
|
if (virTestCompareToFile(actual, xml) < 0)
|
|
goto cleanup;
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
VIR_FREE(xml);
|
|
VIR_FREE(actual);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static const char *
|
|
cpuTestCompResStr(virCPUCompareResult result)
|
|
{
|
|
switch (result) {
|
|
case VIR_CPU_COMPARE_ERROR: return "ERROR";
|
|
case VIR_CPU_COMPARE_INCOMPATIBLE: return "INCOMPATIBLE";
|
|
case VIR_CPU_COMPARE_IDENTICAL: return "IDENTICAL";
|
|
case VIR_CPU_COMPARE_SUPERSET: return "SUPERSET";
|
|
case VIR_CPU_COMPARE_LAST: break;
|
|
}
|
|
|
|
return "unknown";
|
|
}
|
|
|
|
|
|
static const char *
|
|
cpuTestBoolWithErrorStr(enum cpuTestBoolWithError result)
|
|
{
|
|
switch (result) {
|
|
case FAIL: return "FAIL";
|
|
case NO: return "NO";
|
|
case YES: return "YES";
|
|
}
|
|
|
|
return "unknown";
|
|
}
|
|
|
|
|
|
static int
|
|
cpuTestCompare(const void *arg)
|
|
{
|
|
const struct data *data = arg;
|
|
int ret = -1;
|
|
virCPUDefPtr host = NULL;
|
|
virCPUDefPtr cpu = NULL;
|
|
virCPUCompareResult result;
|
|
|
|
if (!(host = cpuTestLoadXML(data->arch, data->host)) ||
|
|
!(cpu = cpuTestLoadXML(data->arch, data->name)))
|
|
goto cleanup;
|
|
|
|
result = cpuCompare(host, cpu, false);
|
|
if (data->result == VIR_CPU_COMPARE_ERROR)
|
|
virResetLastError();
|
|
|
|
if (data->result != result) {
|
|
VIR_TEST_VERBOSE("\nExpected result %s, got %s\n",
|
|
cpuTestCompResStr(data->result),
|
|
cpuTestCompResStr(result));
|
|
/* Pad to line up with test name ... in virTestRun */
|
|
VIR_TEST_VERBOSE("%74s", "... ");
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
virCPUDefFree(host);
|
|
virCPUDefFree(cpu);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int
|
|
cpuTestGuestData(const void *arg)
|
|
{
|
|
const struct data *data = arg;
|
|
int ret = -2;
|
|
virCPUDefPtr host = NULL;
|
|
virCPUDefPtr cpu = NULL;
|
|
virCPUDefPtr guest = NULL;
|
|
virCPUDataPtr guestData = NULL;
|
|
virCPUCompareResult cmpResult;
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
char *result = NULL;
|
|
|
|
if (!(host = cpuTestLoadXML(data->arch, data->host)) ||
|
|
!(cpu = cpuTestLoadXML(data->arch, data->name)))
|
|
goto cleanup;
|
|
|
|
cmpResult = cpuGuestData(host, cpu, &guestData, NULL);
|
|
if (cmpResult == VIR_CPU_COMPARE_ERROR ||
|
|
cmpResult == VIR_CPU_COMPARE_INCOMPATIBLE) {
|
|
ret = -1;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (VIR_ALLOC(guest) < 0)
|
|
goto cleanup;
|
|
|
|
guest->arch = host->arch;
|
|
guest->type = VIR_CPU_TYPE_GUEST;
|
|
guest->match = VIR_CPU_MATCH_EXACT;
|
|
guest->fallback = cpu->fallback;
|
|
if (cpuDecode(guest, guestData, data->models,
|
|
data->nmodels, data->preferred) < 0) {
|
|
ret = -1;
|
|
goto cleanup;
|
|
}
|
|
|
|
virBufferAsprintf(&buf, "%s+%s", data->host, data->name);
|
|
if (data->nmodels)
|
|
virBufferAsprintf(&buf, ",%s", data->modelsName);
|
|
if (data->preferred)
|
|
virBufferAsprintf(&buf, ",%s", data->preferred);
|
|
virBufferAddLit(&buf, "-result");
|
|
|
|
if (virBufferError(&buf)) {
|
|
virBufferFreeAndReset(&buf);
|
|
goto cleanup;
|
|
}
|
|
result = virBufferContentAndReset(&buf);
|
|
|
|
if (cpuTestCompareXML(data->arch, guest, result, false) < 0)
|
|
goto cleanup;
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
VIR_FREE(result);
|
|
cpuDataFree(guestData);
|
|
virCPUDefFree(host);
|
|
virCPUDefFree(cpu);
|
|
virCPUDefFree(guest);
|
|
|
|
if (ret == data->result) {
|
|
/* We got the result we expected, whether it was
|
|
* a success or a failure */
|
|
virResetLastError();
|
|
ret = 0;
|
|
} else {
|
|
VIR_TEST_VERBOSE("\nExpected result %d, got %d\n",
|
|
data->result, ret);
|
|
/* Pad to line up with test name ... in virTestRun */
|
|
VIR_TEST_VERBOSE("%74s", "... ");
|
|
ret = -1;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int
|
|
cpuTestBaseline(const void *arg)
|
|
{
|
|
const struct data *data = arg;
|
|
int ret = -1;
|
|
virCPUDefPtr *cpus = NULL;
|
|
virCPUDefPtr baseline = NULL;
|
|
unsigned int ncpus = 0;
|
|
char *result = NULL;
|
|
const char *suffix;
|
|
size_t i;
|
|
|
|
if (!(cpus = cpuTestLoadMultiXML(data->arch, data->name, &ncpus)))
|
|
goto cleanup;
|
|
|
|
baseline = cpuBaseline(cpus, ncpus, NULL, 0, data->flags);
|
|
if (data->result < 0) {
|
|
virResetLastError();
|
|
if (!baseline) {
|
|
ret = 0;
|
|
} else {
|
|
VIR_TEST_VERBOSE("\n%-70s... ",
|
|
"cpuBaseline was expected to fail but it succeeded");
|
|
}
|
|
goto cleanup;
|
|
}
|
|
if (!baseline)
|
|
goto cleanup;
|
|
|
|
if (data->flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES)
|
|
suffix = "expanded";
|
|
else if (data->flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE)
|
|
suffix = "migratable";
|
|
else
|
|
suffix = "result";
|
|
if (virAsprintf(&result, "%s-%s", data->name, suffix) < 0)
|
|
goto cleanup;
|
|
|
|
if (cpuTestCompareXML(data->arch, baseline, result, false) < 0)
|
|
goto cleanup;
|
|
|
|
for (i = 0; i < ncpus; i++) {
|
|
virCPUCompareResult cmp;
|
|
|
|
cmp = cpuCompare(cpus[i], baseline, false);
|
|
if (cmp != VIR_CPU_COMPARE_SUPERSET &&
|
|
cmp != VIR_CPU_COMPARE_IDENTICAL) {
|
|
VIR_TEST_VERBOSE("\nbaseline CPU is incompatible with CPU %zu\n",
|
|
i);
|
|
VIR_TEST_VERBOSE("%74s", "... ");
|
|
ret = -1;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
if (cpus) {
|
|
for (i = 0; i < ncpus; i++)
|
|
virCPUDefFree(cpus[i]);
|
|
VIR_FREE(cpus);
|
|
}
|
|
virCPUDefFree(baseline);
|
|
VIR_FREE(result);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int
|
|
cpuTestUpdate(const void *arg)
|
|
{
|
|
const struct data *data = arg;
|
|
int ret = -1;
|
|
virCPUDefPtr host = NULL;
|
|
virCPUDefPtr cpu = NULL;
|
|
char *result = NULL;
|
|
|
|
if (!(host = cpuTestLoadXML(data->arch, data->host)) ||
|
|
!(cpu = cpuTestLoadXML(data->arch, data->name)))
|
|
goto cleanup;
|
|
|
|
if (virCPUUpdate(host->arch, cpu, host) < 0)
|
|
goto cleanup;
|
|
|
|
if (virAsprintf(&result, "%s+%s", data->host, data->name) < 0)
|
|
goto cleanup;
|
|
|
|
ret = cpuTestCompareXML(data->arch, cpu, result, true);
|
|
|
|
cleanup:
|
|
virCPUDefFree(host);
|
|
virCPUDefFree(cpu);
|
|
VIR_FREE(result);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int
|
|
cpuTestHasFeature(const void *arg)
|
|
{
|
|
const struct data *data = arg;
|
|
int ret = -1;
|
|
virCPUDefPtr host = NULL;
|
|
virCPUDataPtr hostData = NULL;
|
|
int result;
|
|
|
|
if (!(host = cpuTestLoadXML(data->arch, data->host)))
|
|
goto cleanup;
|
|
|
|
if (cpuEncode(host->arch, host, NULL, &hostData,
|
|
NULL, NULL, NULL, NULL) < 0)
|
|
goto cleanup;
|
|
|
|
result = virCPUDataCheckFeature(hostData, data->name);
|
|
if (data->result == -1)
|
|
virResetLastError();
|
|
|
|
if (data->result != result) {
|
|
VIR_TEST_VERBOSE("\nExpected result %s, got %s\n",
|
|
cpuTestBoolWithErrorStr(data->result),
|
|
cpuTestBoolWithErrorStr(result));
|
|
/* Pad to line up with test name ... in virTestRun */
|
|
VIR_TEST_VERBOSE("%74s", "... ");
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
cpuDataFree(hostData);
|
|
virCPUDefFree(host);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int
|
|
cpuTestCPUID(bool guest, const void *arg)
|
|
{
|
|
const struct data *data = arg;
|
|
int ret = -1;
|
|
virCPUDataPtr hostData = NULL;
|
|
char *hostFile = NULL;
|
|
char *host = NULL;
|
|
virCPUDefPtr cpu = NULL;
|
|
char *result = NULL;
|
|
|
|
if (virAsprintf(&hostFile, "%s/cputestdata/%s-cpuid-%s.xml",
|
|
abs_srcdir, data->arch, data->host) < 0)
|
|
goto cleanup;
|
|
|
|
if (virTestLoadFile(hostFile, &host) < 0 ||
|
|
!(hostData = cpuDataParse(host)))
|
|
goto cleanup;
|
|
|
|
if (VIR_ALLOC(cpu) < 0)
|
|
goto cleanup;
|
|
|
|
cpu->arch = hostData->arch;
|
|
if (guest) {
|
|
cpu->type = VIR_CPU_TYPE_GUEST;
|
|
cpu->match = VIR_CPU_MATCH_EXACT;
|
|
cpu->fallback = VIR_CPU_FALLBACK_FORBID;
|
|
} else {
|
|
cpu->type = VIR_CPU_TYPE_HOST;
|
|
}
|
|
|
|
if (cpuDecode(cpu, hostData, NULL, 0, NULL) < 0)
|
|
goto cleanup;
|
|
|
|
if (virAsprintf(&result, "cpuid-%s-%s",
|
|
data->host,
|
|
guest ? "guest" : "host") < 0)
|
|
goto cleanup;
|
|
|
|
ret = cpuTestCompareXML(data->arch, cpu, result, false);
|
|
|
|
cleanup:
|
|
VIR_FREE(hostFile);
|
|
VIR_FREE(host);
|
|
cpuDataFree(hostData);
|
|
virCPUDefFree(cpu);
|
|
VIR_FREE(result);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int
|
|
cpuTestHostCPUID(const void *arg)
|
|
{
|
|
return cpuTestCPUID(false, arg);
|
|
}
|
|
|
|
|
|
static int
|
|
cpuTestGuestCPUID(const void *arg)
|
|
{
|
|
return cpuTestCPUID(true, arg);
|
|
}
|
|
|
|
|
|
#if WITH_QEMU && WITH_YAJL
|
|
static int
|
|
cpuTestJSONCPUID(const void *arg)
|
|
{
|
|
const struct data *data = arg;
|
|
virCPUDataPtr cpuData = NULL;
|
|
virCPUDefPtr cpu = NULL;
|
|
qemuMonitorTestPtr testMon = NULL;
|
|
char *json = NULL;
|
|
char *result = NULL;
|
|
int ret = -1;
|
|
|
|
if (virAsprintf(&json, "%s/cputestdata/%s-cpuid-%s.json",
|
|
abs_srcdir, data->arch, data->host) < 0 ||
|
|
virAsprintf(&result, "cpuid-%s-json", data->host) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(testMon = qemuMonitorTestNewFromFile(json, driver.xmlopt, true)))
|
|
goto cleanup;
|
|
|
|
if (qemuMonitorJSONGetCPUx86Data(qemuMonitorTestGetMonitor(testMon),
|
|
"feature-words", &cpuData) < 0)
|
|
goto cleanup;
|
|
|
|
if (VIR_ALLOC(cpu) < 0)
|
|
goto cleanup;
|
|
|
|
cpu->arch = cpuData->arch;
|
|
cpu->type = VIR_CPU_TYPE_GUEST;
|
|
cpu->match = VIR_CPU_MATCH_EXACT;
|
|
cpu->fallback = VIR_CPU_FALLBACK_FORBID;
|
|
|
|
if (cpuDecode(cpu, cpuData, NULL, 0, NULL) < 0)
|
|
goto cleanup;
|
|
|
|
ret = cpuTestCompareXML(data->arch, cpu, result, false);
|
|
|
|
cleanup:
|
|
qemuMonitorTestFree(testMon);
|
|
cpuDataFree(cpuData);
|
|
virCPUDefFree(cpu);
|
|
VIR_FREE(result);
|
|
VIR_FREE(json);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
|
|
static const char *model486[] = { "486" };
|
|
static const char *nomodel[] = { "nomodel" };
|
|
static const char *models[] = { "qemu64", "core2duo", "Nehalem" };
|
|
static const char *haswell[] = { "SandyBridge", "Haswell" };
|
|
static const char *ppc_models[] = { "POWER6", "POWER7", "POWER8" };
|
|
|
|
static int
|
|
mymain(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
#if WITH_QEMU && WITH_YAJL
|
|
if (qemuTestDriverInit(&driver) < 0)
|
|
return EXIT_FAILURE;
|
|
|
|
virEventRegisterDefaultImpl();
|
|
#endif
|
|
|
|
#define DO_TEST(arch, api, name, host, cpu, \
|
|
models, nmodels, preferred, flags, result) \
|
|
do { \
|
|
struct data data = { \
|
|
arch, host, cpu, models, \
|
|
models == NULL ? NULL : #models, \
|
|
nmodels, preferred, flags, result \
|
|
}; \
|
|
char *testLabel; \
|
|
char *tmp; \
|
|
\
|
|
tmp = virTestLogContentAndReset(); \
|
|
VIR_FREE(tmp); \
|
|
\
|
|
if (virAsprintf(&testLabel, "%s(%s): %s", \
|
|
#api, arch, name) < 0) { \
|
|
ret = -1; \
|
|
break; \
|
|
} \
|
|
\
|
|
if (virTestRun(testLabel, api, &data) < 0) { \
|
|
if (virTestGetDebug()) { \
|
|
char *log; \
|
|
if ((log = virTestLogContentAndReset()) && \
|
|
strlen(log) > 0) \
|
|
VIR_TEST_DEBUG("\n%s\n", log); \
|
|
VIR_FREE(log); \
|
|
} \
|
|
ret = -1; \
|
|
} \
|
|
\
|
|
VIR_FREE(testLabel); \
|
|
} while (0)
|
|
|
|
#define DO_TEST_COMPARE(arch, host, cpu, result) \
|
|
DO_TEST(arch, cpuTestCompare, \
|
|
host "/" cpu " (" #result ")", \
|
|
host, cpu, NULL, 0, NULL, 0, result)
|
|
|
|
#define DO_TEST_UPDATE_ONLY(arch, host, cpu) \
|
|
DO_TEST(arch, cpuTestUpdate, \
|
|
cpu " on " host, \
|
|
host, cpu, NULL, 0, NULL, 0, 0) \
|
|
|
|
#define DO_TEST_UPDATE(arch, host, cpu, result) \
|
|
do { \
|
|
DO_TEST_UPDATE_ONLY(arch, host, cpu); \
|
|
DO_TEST_COMPARE(arch, host, host "+" cpu, result); \
|
|
} while (0)
|
|
|
|
#define DO_TEST_BASELINE(arch, name, flags, result) \
|
|
do { \
|
|
const char *suffix = ""; \
|
|
char *label; \
|
|
if ((flags) & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) \
|
|
suffix = " (expanded)"; \
|
|
if ((flags) & VIR_CONNECT_BASELINE_CPU_MIGRATABLE) \
|
|
suffix = " (migratable)"; \
|
|
if (virAsprintf(&label, "%s%s", name, suffix) < 0) { \
|
|
ret = -1; \
|
|
} else { \
|
|
DO_TEST(arch, cpuTestBaseline, label, NULL, \
|
|
"baseline-" name, NULL, 0, NULL, flags, result); \
|
|
} \
|
|
VIR_FREE(label); \
|
|
} while (0)
|
|
|
|
#define DO_TEST_HASFEATURE(arch, host, feature, result) \
|
|
DO_TEST(arch, cpuTestHasFeature, \
|
|
host "/" feature " (" #result ")", \
|
|
host, feature, NULL, 0, NULL, 0, result)
|
|
|
|
#define DO_TEST_GUESTDATA(arch, host, cpu, models, preferred, result) \
|
|
DO_TEST(arch, cpuTestGuestData, \
|
|
host "/" cpu " (" #models ", pref=" #preferred ")", \
|
|
host, cpu, models, \
|
|
models == NULL ? 0 : sizeof(models) / sizeof(char *), \
|
|
preferred, 0, result)
|
|
|
|
#if WITH_QEMU && WITH_YAJL
|
|
# define DO_TEST_CPUID_JSON(arch, host, json) \
|
|
do { \
|
|
if (json) { \
|
|
DO_TEST(arch, cpuTestJSONCPUID, host, host, \
|
|
NULL, NULL, 0, NULL, 0, 0); \
|
|
} \
|
|
} while (0)
|
|
#else
|
|
# define DO_TEST_CPUID_JSON(arch, host, json)
|
|
#endif
|
|
|
|
#define DO_TEST_CPUID(arch, host, json) \
|
|
do { \
|
|
DO_TEST(arch, cpuTestHostCPUID, host, host, \
|
|
NULL, NULL, 0, NULL, 0, 0); \
|
|
DO_TEST(arch, cpuTestGuestCPUID, host, host, \
|
|
NULL, NULL, 0, NULL, 0, 0); \
|
|
DO_TEST_CPUID_JSON(arch, host, json); \
|
|
} while (0)
|
|
|
|
/* host to host comparison */
|
|
DO_TEST_COMPARE("x86", "host", "host", VIR_CPU_COMPARE_IDENTICAL);
|
|
DO_TEST_COMPARE("x86", "host", "host-better", VIR_CPU_COMPARE_INCOMPATIBLE);
|
|
DO_TEST_COMPARE("x86", "host", "host-worse", VIR_CPU_COMPARE_SUPERSET);
|
|
DO_TEST_COMPARE("x86", "host", "host-amd-fake", VIR_CPU_COMPARE_INCOMPATIBLE);
|
|
DO_TEST_COMPARE("x86", "host", "host-incomp-arch", VIR_CPU_COMPARE_INCOMPATIBLE);
|
|
DO_TEST_COMPARE("x86", "host", "host-no-vendor", VIR_CPU_COMPARE_IDENTICAL);
|
|
DO_TEST_COMPARE("x86", "host-no-vendor", "host", VIR_CPU_COMPARE_INCOMPATIBLE);
|
|
|
|
DO_TEST_COMPARE("ppc64", "host", "host", VIR_CPU_COMPARE_IDENTICAL);
|
|
DO_TEST_COMPARE("ppc64", "host", "host-better", VIR_CPU_COMPARE_INCOMPATIBLE);
|
|
DO_TEST_COMPARE("ppc64", "host", "host-worse", VIR_CPU_COMPARE_INCOMPATIBLE);
|
|
DO_TEST_COMPARE("ppc64", "host", "host-incomp-arch", VIR_CPU_COMPARE_INCOMPATIBLE);
|
|
DO_TEST_COMPARE("ppc64", "host", "host-no-vendor", VIR_CPU_COMPARE_IDENTICAL);
|
|
DO_TEST_COMPARE("ppc64", "host-no-vendor", "host", VIR_CPU_COMPARE_INCOMPATIBLE);
|
|
|
|
/* guest to host comparison */
|
|
DO_TEST_COMPARE("x86", "host", "bogus-model", VIR_CPU_COMPARE_ERROR);
|
|
DO_TEST_COMPARE("x86", "host", "bogus-feature", VIR_CPU_COMPARE_ERROR);
|
|
DO_TEST_COMPARE("x86", "host", "min", VIR_CPU_COMPARE_SUPERSET);
|
|
DO_TEST_COMPARE("x86", "host", "pentium3", VIR_CPU_COMPARE_SUPERSET);
|
|
DO_TEST_COMPARE("x86", "host", "exact", VIR_CPU_COMPARE_SUPERSET);
|
|
DO_TEST_COMPARE("x86", "host", "exact-forbid", VIR_CPU_COMPARE_INCOMPATIBLE);
|
|
DO_TEST_COMPARE("x86", "host", "exact-forbid-extra", VIR_CPU_COMPARE_SUPERSET);
|
|
DO_TEST_COMPARE("x86", "host", "exact-disable", VIR_CPU_COMPARE_SUPERSET);
|
|
DO_TEST_COMPARE("x86", "host", "exact-disable2", VIR_CPU_COMPARE_SUPERSET);
|
|
DO_TEST_COMPARE("x86", "host", "exact-disable-extra", VIR_CPU_COMPARE_SUPERSET);
|
|
DO_TEST_COMPARE("x86", "host", "exact-require", VIR_CPU_COMPARE_SUPERSET);
|
|
DO_TEST_COMPARE("x86", "host", "exact-require-extra", VIR_CPU_COMPARE_INCOMPATIBLE);
|
|
DO_TEST_COMPARE("x86", "host", "exact-force", VIR_CPU_COMPARE_SUPERSET);
|
|
DO_TEST_COMPARE("x86", "host", "strict", VIR_CPU_COMPARE_INCOMPATIBLE);
|
|
DO_TEST_COMPARE("x86", "host", "strict-full", VIR_CPU_COMPARE_IDENTICAL);
|
|
DO_TEST_COMPARE("x86", "host", "strict-disable", VIR_CPU_COMPARE_IDENTICAL);
|
|
DO_TEST_COMPARE("x86", "host", "strict-force-extra", VIR_CPU_COMPARE_IDENTICAL);
|
|
DO_TEST_COMPARE("x86", "host", "guest", VIR_CPU_COMPARE_SUPERSET);
|
|
DO_TEST_COMPARE("x86", "host", "pentium3-amd", VIR_CPU_COMPARE_INCOMPATIBLE);
|
|
DO_TEST_COMPARE("x86", "host-amd", "pentium3-amd", VIR_CPU_COMPARE_SUPERSET);
|
|
DO_TEST_COMPARE("x86", "host-worse", "penryn-force", VIR_CPU_COMPARE_IDENTICAL);
|
|
DO_TEST_COMPARE("x86", "host-SandyBridge", "exact-force-Haswell", VIR_CPU_COMPARE_IDENTICAL);
|
|
|
|
DO_TEST_COMPARE("ppc64", "host", "guest-strict", VIR_CPU_COMPARE_IDENTICAL);
|
|
DO_TEST_COMPARE("ppc64", "host", "guest-exact", VIR_CPU_COMPARE_INCOMPATIBLE);
|
|
DO_TEST_COMPARE("ppc64", "host", "guest-legacy", VIR_CPU_COMPARE_IDENTICAL);
|
|
DO_TEST_COMPARE("ppc64", "host", "guest-legacy-incompatible", VIR_CPU_COMPARE_INCOMPATIBLE);
|
|
DO_TEST_COMPARE("ppc64", "host", "guest-legacy-invalid", VIR_CPU_COMPARE_ERROR);
|
|
DO_TEST_COMPARE("ppc64", "host", "guest-compat-none", VIR_CPU_COMPARE_IDENTICAL);
|
|
DO_TEST_COMPARE("ppc64", "host", "guest-compat-valid", VIR_CPU_COMPARE_IDENTICAL);
|
|
DO_TEST_COMPARE("ppc64", "host", "guest-compat-invalid", VIR_CPU_COMPARE_ERROR);
|
|
DO_TEST_COMPARE("ppc64", "host", "guest-compat-incompatible", VIR_CPU_COMPARE_INCOMPATIBLE);
|
|
|
|
/* guest updates for migration
|
|
* automatically compares host CPU with the result */
|
|
DO_TEST_UPDATE("x86", "host", "min", VIR_CPU_COMPARE_IDENTICAL);
|
|
DO_TEST_UPDATE("x86", "host", "pentium3", VIR_CPU_COMPARE_IDENTICAL);
|
|
DO_TEST_UPDATE("x86", "host", "guest", VIR_CPU_COMPARE_SUPERSET);
|
|
DO_TEST_UPDATE("x86", "host", "host-model", VIR_CPU_COMPARE_IDENTICAL);
|
|
DO_TEST_UPDATE("x86", "host", "host-model-nofallback", VIR_CPU_COMPARE_IDENTICAL);
|
|
DO_TEST_UPDATE("x86", "host-invtsc", "host-model", VIR_CPU_COMPARE_SUPERSET);
|
|
DO_TEST_UPDATE_ONLY("x86", "host", "host-passthrough");
|
|
DO_TEST_UPDATE_ONLY("x86", "host", "host-passthrough-features");
|
|
|
|
DO_TEST_UPDATE("ppc64", "host", "guest", VIR_CPU_COMPARE_IDENTICAL);
|
|
DO_TEST_UPDATE("ppc64", "host", "guest-nofallback", VIR_CPU_COMPARE_INCOMPATIBLE);
|
|
DO_TEST_UPDATE("ppc64", "host", "guest-legacy", VIR_CPU_COMPARE_IDENTICAL);
|
|
DO_TEST_UPDATE("ppc64", "host", "guest-legacy-incompatible", VIR_CPU_COMPARE_INCOMPATIBLE);
|
|
DO_TEST_UPDATE("ppc64", "host", "guest-legacy-invalid", VIR_CPU_COMPARE_ERROR);
|
|
DO_TEST_UPDATE("ppc64", "host", "guest-compat-none", VIR_CPU_COMPARE_IDENTICAL);
|
|
DO_TEST_UPDATE("ppc64", "host", "guest-compat-valid", VIR_CPU_COMPARE_IDENTICAL);
|
|
DO_TEST_UPDATE("ppc64", "host", "guest-compat-invalid", VIR_CPU_COMPARE_ERROR);
|
|
DO_TEST_UPDATE("ppc64", "host", "guest-compat-incompatible", VIR_CPU_COMPARE_INCOMPATIBLE);
|
|
|
|
/* computing baseline CPUs */
|
|
DO_TEST_BASELINE("x86", "incompatible-vendors", 0, -1);
|
|
DO_TEST_BASELINE("x86", "no-vendor", 0, 0);
|
|
DO_TEST_BASELINE("x86", "some-vendors", 0, 0);
|
|
DO_TEST_BASELINE("x86", "1", 0, 0);
|
|
DO_TEST_BASELINE("x86", "2", 0, 0);
|
|
DO_TEST_BASELINE("x86", "3", 0, 0);
|
|
DO_TEST_BASELINE("x86", "3", VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, 0);
|
|
DO_TEST_BASELINE("x86", "4", 0, 0);
|
|
DO_TEST_BASELINE("x86", "4", VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, 0);
|
|
DO_TEST_BASELINE("x86", "5", 0, 0);
|
|
DO_TEST_BASELINE("x86", "5", VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, 0);
|
|
DO_TEST_BASELINE("x86", "6", 0, 0);
|
|
DO_TEST_BASELINE("x86", "6", VIR_CONNECT_BASELINE_CPU_MIGRATABLE, 0);
|
|
DO_TEST_BASELINE("x86", "7", 0, 0);
|
|
DO_TEST_BASELINE("x86", "8", 0, 0);
|
|
|
|
DO_TEST_BASELINE("ppc64", "incompatible-vendors", 0, -1);
|
|
DO_TEST_BASELINE("ppc64", "no-vendor", 0, 0);
|
|
DO_TEST_BASELINE("ppc64", "incompatible-models", 0, -1);
|
|
DO_TEST_BASELINE("ppc64", "same-model", 0, 0);
|
|
DO_TEST_BASELINE("ppc64", "legacy", 0, -1);
|
|
|
|
/* CPU features */
|
|
DO_TEST_HASFEATURE("x86", "host", "vmx", YES);
|
|
DO_TEST_HASFEATURE("x86", "host", "lm", YES);
|
|
DO_TEST_HASFEATURE("x86", "host", "sse4.1", YES);
|
|
DO_TEST_HASFEATURE("x86", "host", "3dnowext", NO);
|
|
DO_TEST_HASFEATURE("x86", "host", "skinit", NO);
|
|
DO_TEST_HASFEATURE("x86", "host", "foo", FAIL);
|
|
|
|
/* computing guest data and decoding the data into a guest CPU XML */
|
|
DO_TEST_GUESTDATA("x86", "host", "guest", NULL, NULL, 0);
|
|
DO_TEST_GUESTDATA("x86", "host-better", "pentium3", NULL, NULL, 0);
|
|
DO_TEST_GUESTDATA("x86", "host-better", "pentium3", NULL, "pentium3", 0);
|
|
DO_TEST_GUESTDATA("x86", "host-better", "pentium3", NULL, "core2duo", 0);
|
|
DO_TEST_GUESTDATA("x86", "host-worse", "guest", NULL, NULL, 0);
|
|
DO_TEST_GUESTDATA("x86", "host", "strict-force-extra", NULL, NULL, 0);
|
|
DO_TEST_GUESTDATA("x86", "host", "penryn-force", NULL, NULL, 0);
|
|
DO_TEST_GUESTDATA("x86", "host", "guest", model486, NULL, 0);
|
|
DO_TEST_GUESTDATA("x86", "host", "guest", models, NULL, 0);
|
|
DO_TEST_GUESTDATA("x86", "host", "guest", models, "Penryn", 0);
|
|
DO_TEST_GUESTDATA("x86", "host", "guest", models, "qemu64", 0);
|
|
DO_TEST_GUESTDATA("x86", "host", "guest", nomodel, NULL, -1);
|
|
DO_TEST_GUESTDATA("x86", "host", "guest-nofallback", models, "Penryn", -1);
|
|
DO_TEST_GUESTDATA("x86", "host", "host+host-model", models, "Penryn", 0);
|
|
DO_TEST_GUESTDATA("x86", "host", "host+host-model-nofallback",
|
|
models, "Penryn", -1);
|
|
DO_TEST_GUESTDATA("x86", "host-Haswell-noTSX", "Haswell",
|
|
haswell, "Haswell", 0);
|
|
DO_TEST_GUESTDATA("x86", "host-Haswell-noTSX", "Haswell-noTSX",
|
|
haswell, "Haswell-noTSX", 0);
|
|
DO_TEST_GUESTDATA("x86", "host-Haswell-noTSX", "Haswell-noTSX-nofallback",
|
|
haswell, "Haswell-noTSX", -1);
|
|
DO_TEST_GUESTDATA("x86", "host-Haswell-noTSX", "Haswell-noTSX",
|
|
NULL, "Haswell-noTSX", 0);
|
|
|
|
DO_TEST_GUESTDATA("ppc64", "host", "guest", ppc_models, NULL, 0);
|
|
DO_TEST_GUESTDATA("ppc64", "host", "guest-nofallback", ppc_models, "POWER8", -1);
|
|
DO_TEST_GUESTDATA("ppc64", "host", "guest-legacy", ppc_models, NULL, 0);
|
|
DO_TEST_GUESTDATA("ppc64", "host", "guest-legacy-incompatible", ppc_models, NULL, -1);
|
|
DO_TEST_GUESTDATA("ppc64", "host", "guest-legacy-invalid", ppc_models, NULL, -1);
|
|
|
|
DO_TEST_CPUID("x86", "A10-5800K", true);
|
|
DO_TEST_CPUID("x86", "Atom-D510", false);
|
|
DO_TEST_CPUID("x86", "Atom-N450", false);
|
|
DO_TEST_CPUID("x86", "Core-i5-2500", true);
|
|
DO_TEST_CPUID("x86", "Core-i5-2540M", true);
|
|
DO_TEST_CPUID("x86", "Core-i5-4670T", true);
|
|
DO_TEST_CPUID("x86", "Core-i5-6600", true);
|
|
DO_TEST_CPUID("x86", "Core-i7-2600", true);
|
|
DO_TEST_CPUID("x86", "Core-i7-3520M", false);
|
|
DO_TEST_CPUID("x86", "Core-i7-3740QM", true);
|
|
DO_TEST_CPUID("x86", "Core-i7-3770", true);
|
|
DO_TEST_CPUID("x86", "Core-i7-4600U", true);
|
|
DO_TEST_CPUID("x86", "Core-i7-5600U", true);
|
|
DO_TEST_CPUID("x86", "Core2-E6850", true);
|
|
DO_TEST_CPUID("x86", "Core2-Q9500", false);
|
|
DO_TEST_CPUID("x86", "FX-8150", false);
|
|
DO_TEST_CPUID("x86", "Opteron-1352", false);
|
|
DO_TEST_CPUID("x86", "Opteron-2350", true);
|
|
DO_TEST_CPUID("x86", "Opteron-6234", true);
|
|
DO_TEST_CPUID("x86", "Opteron-6282", false);
|
|
DO_TEST_CPUID("x86", "Pentium-P6100", false);
|
|
DO_TEST_CPUID("x86", "Phenom-B95", true);
|
|
DO_TEST_CPUID("x86", "Xeon-5110", false);
|
|
DO_TEST_CPUID("x86", "Xeon-E3-1245", true);
|
|
DO_TEST_CPUID("x86", "Xeon-E5-2630", true);
|
|
DO_TEST_CPUID("x86", "Xeon-E5-2650", true);
|
|
DO_TEST_CPUID("x86", "Xeon-E7-4820", true);
|
|
DO_TEST_CPUID("x86", "Xeon-W3520", true);
|
|
DO_TEST_CPUID("x86", "Xeon-X5460", false);
|
|
|
|
#if WITH_QEMU && WITH_YAJL
|
|
qemuTestDriverFree(&driver);
|
|
#endif
|
|
|
|
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
|
}
|
|
|
|
VIRT_TEST_MAIN(mymain)
|