tcg: add options for enabling MTTCG

We know there will be cases where MTTCG won't work until additional work
is done in the front/back ends to support. It will however be useful to
be able to turn it on.

As a result MTTCG will default to off unless the combination is
supported. However the user can turn it on for the sake of testing.

Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
[AJB: move to -accel tcg,thread=multi|single, defaults]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
KONRAD Frederic 2017-02-23 18:29:08 +00:00 committed by Alex Bennée
parent 2093714314
commit 8d4e9146b3
6 changed files with 161 additions and 1 deletions

73
cpus.c
View File

@ -25,6 +25,7 @@
/* Needed early for CONFIG_BSD etc. */
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/config-file.h"
#include "cpu.h"
#include "monitor/monitor.h"
#include "qapi/qmp/qerror.h"
@ -45,6 +46,7 @@
#include "qemu/main-loop.h"
#include "qemu/bitmap.h"
#include "qemu/seqlock.h"
#include "tcg.h"
#include "qapi-event.h"
#include "hw/nmi.h"
#include "sysemu/replay.h"
@ -150,6 +152,77 @@ typedef struct TimersState {
} TimersState;
static TimersState timers_state;
bool mttcg_enabled;
/*
* We default to false if we know other options have been enabled
* which are currently incompatible with MTTCG. Otherwise when each
* guest (target) has been updated to support:
* - atomic instructions
* - memory ordering primitives (barriers)
* they can set the appropriate CONFIG flags in ${target}-softmmu.mak
*
* Once a guest architecture has been converted to the new primitives
* there are two remaining limitations to check.
*
* - The guest can't be oversized (e.g. 64 bit guest on 32 bit host)
* - The host must have a stronger memory order than the guest
*
* It may be possible in future to support strong guests on weak hosts
* but that will require tagging all load/stores in a guest with their
* implicit memory order requirements which would likely slow things
* down a lot.
*/
static bool check_tcg_memory_orders_compatible(void)
{
#if defined(TCG_GUEST_DEFAULT_MO) && defined(TCG_TARGET_DEFAULT_MO)
return (TCG_GUEST_DEFAULT_MO & ~TCG_TARGET_DEFAULT_MO) == 0;
#else
return false;
#endif
}
static bool default_mttcg_enabled(void)
{
QemuOpts *icount_opts = qemu_find_opts_singleton("icount");
const char *rr = qemu_opt_get(icount_opts, "rr");
if (rr || TCG_OVERSIZED_GUEST) {
return false;
} else {
#ifdef TARGET_SUPPORTS_MTTCG
return check_tcg_memory_orders_compatible();
#else
return false;
#endif
}
}
void qemu_tcg_configure(QemuOpts *opts, Error **errp)
{
const char *t = qemu_opt_get(opts, "thread");
if (t) {
if (strcmp(t, "multi") == 0) {
if (TCG_OVERSIZED_GUEST) {
error_setg(errp, "No MTTCG when guest word size > hosts");
} else {
if (!check_tcg_memory_orders_compatible()) {
error_report("Guest expects a stronger memory ordering "
"than the host provides");
error_printf("This may cause strange/hard to debug errors");
}
mttcg_enabled = true;
}
} else if (strcmp(t, "single") == 0) {
mttcg_enabled = false;
} else {
error_setg(errp, "Invalid 'thread' setting %s", t);
}
} else {
mttcg_enabled = default_mttcg_enabled();
}
}
int64_t cpu_get_icount_raw(void)
{

View File

@ -415,6 +415,15 @@ extern struct CPUTailQ cpus;
extern __thread CPUState *current_cpu;
/**
* qemu_tcg_mttcg_enabled:
* Check whether we are running MultiThread TCG or not.
*
* Returns: %true if we are in MTTCG mode %false otherwise.
*/
extern bool mttcg_enabled;
#define qemu_tcg_mttcg_enabled() (mttcg_enabled)
/**
* cpu_paging_enabled:
* @cpu: The CPU whose state is to be inspected.

View File

@ -36,4 +36,6 @@ extern int smp_threads;
void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg);
void qemu_tcg_configure(QemuOpts *opts, Error **errp);
#endif

View File

@ -95,6 +95,26 @@ STEXI
Select CPU model (@code{-cpu help} for list and additional feature selection)
ETEXI
DEF("accel", HAS_ARG, QEMU_OPTION_accel,
"-accel [accel=]accelerator[,thread=single|multi]\n"
" select accelerator ('-accel help for list')\n"
" thread=single|multi (enable multi-threaded TCG)", QEMU_ARCH_ALL)
STEXI
@item -accel @var{name}[,prop=@var{value}[,...]]
@findex -accel
This is used to enable an accelerator. Depending on the target architecture,
kvm, xen, or tcg can be available. By default, tcg is used. If there is more
than one accelerator specified, the next one is used if the previous one fails
to initialize.
@table @option
@item thread=single|multi
Controls number of TCG threads. When the TCG is multi-threaded there will be one
thread per vCPU therefor taking advantage of additional host cores. The default
is to enable multi-threading where both the back-end and front-ends support it and
no incompatible TCG features have been enabled (e.g. icount/replay).
@end table
ETEXI
DEF("smp", HAS_ARG, QEMU_OPTION_smp,
"-smp [cpus=]n[,maxcpus=cpus][,cores=cores][,threads=threads][,sockets=sockets]\n"
" set the number of CPUs to 'n' [default=1]\n"

View File

@ -80,6 +80,15 @@ typedef uint64_t tcg_target_ulong;
#error unsupported
#endif
/* Oversized TCG guests make things like MTTCG hard
* as we can't use atomics for cputlb updates.
*/
#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
#define TCG_OVERSIZED_GUEST 1
#else
#define TCG_OVERSIZED_GUEST 0
#endif
#if TCG_TARGET_NB_REGS <= 32
typedef uint32_t TCGRegSet;
#elif TCG_TARGET_NB_REGS <= 64

49
vl.c
View File

@ -300,6 +300,26 @@ static QemuOptsList qemu_machine_opts = {
},
};
static QemuOptsList qemu_accel_opts = {
.name = "accel",
.implied_opt_name = "accel",
.head = QTAILQ_HEAD_INITIALIZER(qemu_accel_opts.head),
.merge_lists = true,
.desc = {
{
.name = "accel",
.type = QEMU_OPT_STRING,
.help = "Select the type of accelerator",
},
{
.name = "thread",
.type = QEMU_OPT_STRING,
.help = "Enable/disable multi-threaded TCG",
},
{ /* end of list */ }
},
};
static QemuOptsList qemu_boot_opts = {
.name = "boot-opts",
.implied_opt_name = "order",
@ -2928,7 +2948,8 @@ int main(int argc, char **argv, char **envp)
const char *boot_once = NULL;
DisplayState *ds;
int cyls, heads, secs, translation;
QemuOpts *hda_opts = NULL, *opts, *machine_opts, *icount_opts = NULL;
QemuOpts *opts, *machine_opts;
QemuOpts *hda_opts = NULL, *icount_opts = NULL, *accel_opts = NULL;
QemuOptsList *olist;
int optind;
const char *optarg;
@ -2983,6 +3004,7 @@ int main(int argc, char **argv, char **envp)
qemu_add_opts(&qemu_trace_opts);
qemu_add_opts(&qemu_option_rom_opts);
qemu_add_opts(&qemu_machine_opts);
qemu_add_opts(&qemu_accel_opts);
qemu_add_opts(&qemu_mem_opts);
qemu_add_opts(&qemu_smp_opts);
qemu_add_opts(&qemu_boot_opts);
@ -3675,6 +3697,26 @@ int main(int argc, char **argv, char **envp)
qdev_prop_register_global(&kvm_pit_lost_tick_policy);
break;
}
case QEMU_OPTION_accel:
accel_opts = qemu_opts_parse_noisily(qemu_find_opts("accel"),
optarg, true);
optarg = qemu_opt_get(accel_opts, "accel");
olist = qemu_find_opts("machine");
if (strcmp("kvm", optarg) == 0) {
qemu_opts_parse_noisily(olist, "accel=kvm", false);
} else if (strcmp("xen", optarg) == 0) {
qemu_opts_parse_noisily(olist, "accel=xen", false);
} else if (strcmp("tcg", optarg) == 0) {
qemu_opts_parse_noisily(olist, "accel=tcg", false);
} else {
if (!is_help_option(optarg)) {
error_printf("Unknown accelerator: %s", optarg);
}
error_printf("Supported accelerators: kvm, xen, tcg\n");
exit(1);
}
break;
case QEMU_OPTION_usb:
olist = qemu_find_opts("machine");
qemu_opts_parse_noisily(olist, "usb=on", false);
@ -3983,6 +4025,8 @@ int main(int argc, char **argv, char **envp)
replay_configure(icount_opts);
qemu_tcg_configure(accel_opts, &error_fatal);
machine_class = select_machine();
set_memory_options(&ram_slots, &maxram_size, machine_class);
@ -4349,6 +4393,9 @@ int main(int argc, char **argv, char **envp)
if (!tcg_enabled()) {
error_report("-icount is not allowed with hardware virtualization");
exit(1);
} else if (qemu_tcg_mttcg_enabled()) {
error_report("-icount does not currently work with MTTCG");
exit(1);
}
configure_icount(icount_opts, &error_abort);
qemu_opts_del(icount_opts);