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:
parent
2093714314
commit
8d4e9146b3
73
cpus.c
73
cpus.c
@ -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)
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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
49
vl.c
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user