Final icount and misc MTTCG fixes for 2.9
Minor differences from: Message-Id: <20170405132503.32125-1-alex.bennee@linaro.org> - dropped new feature patches - last minute typo fix from Nikunj A Dadhania <nikunj@linux.vnet.ibm.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJY62CSAAoJEPvQ2wlanipEu/wH/jNzNMus/zaM/+gS3GWpHer2 /aLkKS/zNHZoYzvDE4JZx3sX4q6HyeRZ0Hu46jWs3WAECgHhjV4Rfn3btK+x/5r8 wtmC0DM59ULbE2e6NjDRdJAocdjU6j9Zu+c09/sfssBLRHCJOGyAH8BEbyhHcmlq hUqTFvZAuLdko6CWfKjtFv+KQm+za9ypiLIncZZDhUi5vt2PIuUV6qSUyqs5EpwP JyDlgDD8Rzohq62dWIXYTg5dV7tU6/g9vou7tEUoqhMVTHF1usA++j6yfIpGq3Z5 MGN/63Q9tdSX/Kzot9yrHKdsjQEm7k7/03LKT6BIvM1tk0hjzumHFGJBDFYytVc= =/8U7 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/stsquad/tags/pull-mttcg-fixups-for-rc2-100417-1' into staging Final icount and misc MTTCG fixes for 2.9 Minor differences from: Message-Id: <20170405132503.32125-1-alex.bennee@linaro.org> - dropped new feature patches - last minute typo fix from Nikunj A Dadhania <nikunj@linux.vnet.ibm.com> # gpg: Signature made Mon 10 Apr 2017 11:38:10 BST # gpg: using RSA key 0xFBD0DB095A9E2A44 # gpg: Good signature from "Alex Bennée (Master Work Key) <alex.bennee@linaro.org>" # Primary key fingerprint: 6685 AE99 E751 67BC AFC8 DF35 FBD0 DB09 5A9E 2A44 * remotes/stsquad/tags/pull-mttcg-fixups-for-rc2-100417-1: replay: assert time only goes forward cpus: call cpu_update_icount on read cpu-exec: update icount after each TB_EXIT cpus: introduce cpu_update_icount helper cpus: don't credit executed instructions before they have run cpus: move icount preparation out of tcg_exec_cpu cpus: check cpu->running in cpu_get_icount_raw() cpus: remove icount handling from qemu_tcg_cpu_thread_fn target/i386/misc_helper: wrap BQL around another IRQ generator cpus: fix wrong define name scripts/qemugdb/mtree.py: fix up mtree dump Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
0a49bfa1ab
14
cpu-exec.c
14
cpu-exec.c
@ -600,13 +600,13 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
||||
/* Instruction counter expired. */
|
||||
assert(use_icount);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (cpu->icount_extra) {
|
||||
/* Refill decrementer and continue execution. */
|
||||
cpu->icount_extra += insns_left;
|
||||
insns_left = MIN(0xffff, cpu->icount_extra);
|
||||
cpu->icount_extra -= insns_left;
|
||||
cpu->icount_decr.u16.low = insns_left;
|
||||
} else {
|
||||
/* Ensure global icount has gone forward */
|
||||
cpu_update_icount(cpu);
|
||||
/* Refill decrementer and continue execution. */
|
||||
insns_left = MIN(0xffff, cpu->icount_budget);
|
||||
cpu->icount_decr.u16.low = insns_left;
|
||||
cpu->icount_extra = cpu->icount_budget - insns_left;
|
||||
if (!cpu->icount_extra) {
|
||||
/* Execute any remaining instructions, then let the main loop
|
||||
* handle the next event.
|
||||
*/
|
||||
|
111
cpus.c
111
cpus.c
@ -202,7 +202,7 @@ void qemu_tcg_configure(QemuOpts *opts, Error **errp)
|
||||
} else if (use_icount) {
|
||||
error_setg(errp, "No MTTCG when icount is enabled");
|
||||
} else {
|
||||
#ifndef TARGET_SUPPORT_MTTCG
|
||||
#ifndef TARGET_SUPPORTS_MTTCG
|
||||
error_report("Guest not yet converted to MTTCG - "
|
||||
"you may get unexpected results");
|
||||
#endif
|
||||
@ -223,20 +223,51 @@ void qemu_tcg_configure(QemuOpts *opts, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
/* The current number of executed instructions is based on what we
|
||||
* originally budgeted minus the current state of the decrementing
|
||||
* icount counters in extra/u16.low.
|
||||
*/
|
||||
static int64_t cpu_get_icount_executed(CPUState *cpu)
|
||||
{
|
||||
return cpu->icount_budget - (cpu->icount_decr.u16.low + cpu->icount_extra);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the global shared timer_state.qemu_icount to take into
|
||||
* account executed instructions. This is done by the TCG vCPU
|
||||
* thread so the main-loop can see time has moved forward.
|
||||
*/
|
||||
void cpu_update_icount(CPUState *cpu)
|
||||
{
|
||||
int64_t executed = cpu_get_icount_executed(cpu);
|
||||
cpu->icount_budget -= executed;
|
||||
|
||||
#ifdef CONFIG_ATOMIC64
|
||||
atomic_set__nocheck(&timers_state.qemu_icount,
|
||||
atomic_read__nocheck(&timers_state.qemu_icount) +
|
||||
executed);
|
||||
#else /* FIXME: we need 64bit atomics to do this safely */
|
||||
timers_state.qemu_icount += executed;
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t cpu_get_icount_raw(void)
|
||||
{
|
||||
int64_t icount;
|
||||
CPUState *cpu = current_cpu;
|
||||
|
||||
icount = timers_state.qemu_icount;
|
||||
if (cpu) {
|
||||
if (cpu && cpu->running) {
|
||||
if (!cpu->can_do_io) {
|
||||
fprintf(stderr, "Bad icount read\n");
|
||||
exit(1);
|
||||
}
|
||||
icount -= (cpu->icount_decr.u16.low + cpu->icount_extra);
|
||||
/* Take into account what has run */
|
||||
cpu_update_icount(cpu);
|
||||
}
|
||||
return icount;
|
||||
#ifdef CONFIG_ATOMIC64
|
||||
return atomic_read__nocheck(&timers_state.qemu_icount);
|
||||
#else /* FIXME: we need 64bit atomics to do this safely */
|
||||
return timers_state.qemu_icount;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return the virtual CPU time, based on the instruction counter. */
|
||||
@ -1179,6 +1210,41 @@ static void handle_icount_deadline(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void prepare_icount_for_run(CPUState *cpu)
|
||||
{
|
||||
if (use_icount) {
|
||||
int insns_left;
|
||||
|
||||
/* These should always be cleared by process_icount_data after
|
||||
* each vCPU execution. However u16.high can be raised
|
||||
* asynchronously by cpu_exit/cpu_interrupt/tcg_handle_interrupt
|
||||
*/
|
||||
g_assert(cpu->icount_decr.u16.low == 0);
|
||||
g_assert(cpu->icount_extra == 0);
|
||||
|
||||
cpu->icount_budget = tcg_get_icount_limit();
|
||||
insns_left = MIN(0xffff, cpu->icount_budget);
|
||||
cpu->icount_decr.u16.low = insns_left;
|
||||
cpu->icount_extra = cpu->icount_budget - insns_left;
|
||||
}
|
||||
}
|
||||
|
||||
static void process_icount_data(CPUState *cpu)
|
||||
{
|
||||
if (use_icount) {
|
||||
/* Account for executed instructions */
|
||||
cpu_update_icount(cpu);
|
||||
|
||||
/* Reset the counters */
|
||||
cpu->icount_decr.u16.low = 0;
|
||||
cpu->icount_extra = 0;
|
||||
cpu->icount_budget = 0;
|
||||
|
||||
replay_account_executed_instructions();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int tcg_cpu_exec(CPUState *cpu)
|
||||
{
|
||||
int ret;
|
||||
@ -1189,20 +1255,6 @@ static int tcg_cpu_exec(CPUState *cpu)
|
||||
#ifdef CONFIG_PROFILER
|
||||
ti = profile_getclock();
|
||||
#endif
|
||||
if (use_icount) {
|
||||
int64_t count;
|
||||
int decr;
|
||||
timers_state.qemu_icount -= (cpu->icount_decr.u16.low
|
||||
+ cpu->icount_extra);
|
||||
cpu->icount_decr.u16.low = 0;
|
||||
cpu->icount_extra = 0;
|
||||
count = tcg_get_icount_limit();
|
||||
timers_state.qemu_icount += count;
|
||||
decr = (count > 0xffff) ? 0xffff : count;
|
||||
count -= decr;
|
||||
cpu->icount_decr.u16.low = decr;
|
||||
cpu->icount_extra = count;
|
||||
}
|
||||
qemu_mutex_unlock_iothread();
|
||||
cpu_exec_start(cpu);
|
||||
ret = cpu_exec(cpu);
|
||||
@ -1211,15 +1263,6 @@ static int tcg_cpu_exec(CPUState *cpu)
|
||||
#ifdef CONFIG_PROFILER
|
||||
tcg_time += profile_getclock() - ti;
|
||||
#endif
|
||||
if (use_icount) {
|
||||
/* Fold pending instructions back into the
|
||||
instruction counter, and clear the interrupt flag. */
|
||||
timers_state.qemu_icount -= (cpu->icount_decr.u16.low
|
||||
+ cpu->icount_extra);
|
||||
cpu->icount_decr.u32 = 0;
|
||||
cpu->icount_extra = 0;
|
||||
replay_account_executed_instructions();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1306,7 +1349,13 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg)
|
||||
|
||||
if (cpu_can_run(cpu)) {
|
||||
int r;
|
||||
|
||||
prepare_icount_for_run(cpu);
|
||||
|
||||
r = tcg_cpu_exec(cpu);
|
||||
|
||||
process_icount_data(cpu);
|
||||
|
||||
if (r == EXCP_DEBUG) {
|
||||
cpu_handle_guest_debug(cpu);
|
||||
break;
|
||||
@ -1392,6 +1441,8 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
|
||||
{
|
||||
CPUState *cpu = arg;
|
||||
|
||||
g_assert(!use_icount);
|
||||
|
||||
rcu_register_thread();
|
||||
|
||||
qemu_mutex_lock_iothread();
|
||||
@ -1434,8 +1485,6 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
handle_icount_deadline();
|
||||
|
||||
atomic_mb_set(&cpu->exit_request, 0);
|
||||
qemu_tcg_wait_io_event(cpu);
|
||||
}
|
||||
|
@ -869,6 +869,7 @@ int64_t cpu_get_icount_raw(void);
|
||||
int64_t cpu_get_icount(void);
|
||||
int64_t cpu_get_clock(void);
|
||||
int64_t cpu_icount_to_ns(int64_t icount);
|
||||
void cpu_update_icount(CPUState *cpu);
|
||||
|
||||
/*******************************************/
|
||||
/* host CPU ticks (if available) */
|
||||
|
@ -332,6 +332,7 @@ struct CPUState {
|
||||
/* updates protected by BQL */
|
||||
uint32_t interrupt_request;
|
||||
int singlestep_enabled;
|
||||
int64_t icount_budget;
|
||||
int64_t icount_extra;
|
||||
sigjmp_buf jmp_env;
|
||||
|
||||
|
@ -195,6 +195,10 @@ void replay_save_instructions(void)
|
||||
if (replay_file && replay_mode == REPLAY_MODE_RECORD) {
|
||||
replay_mutex_lock();
|
||||
int diff = (int)(replay_get_current_step() - replay_state.current_step);
|
||||
|
||||
/* Time can only go forward */
|
||||
assert(diff >= 0);
|
||||
|
||||
if (diff > 0) {
|
||||
replay_put_event(EVENT_INSTRUCTION);
|
||||
replay_put_dword(diff);
|
||||
|
@ -84,6 +84,10 @@ void replay_account_executed_instructions(void)
|
||||
if (replay_state.instructions_count > 0) {
|
||||
int count = (int)(replay_get_current_step()
|
||||
- replay_state.current_step);
|
||||
|
||||
/* Time can only go forward */
|
||||
assert(count >= 0);
|
||||
|
||||
replay_state.instructions_count -= count;
|
||||
replay_state.current_step += count;
|
||||
if (replay_state.instructions_count == 0) {
|
||||
|
@ -21,7 +21,15 @@ def isnull(ptr):
|
||||
return ptr == gdb.Value(0).cast(ptr.type)
|
||||
|
||||
def int128(p):
|
||||
return int(p['lo']) + (int(p['hi']) << 64)
|
||||
'''Read an Int128 type to a python integer.
|
||||
|
||||
QEMU can be built with native Int128 support so we need to detect
|
||||
if the value is a structure or the native type.
|
||||
'''
|
||||
if p.type.code == gdb.TYPE_CODE_STRUCT:
|
||||
return int(p['lo']) + (int(p['hi']) << 64)
|
||||
else:
|
||||
return int(("%s" % p), 16)
|
||||
|
||||
class MtreeCommand(gdb.Command):
|
||||
'''Display the memory tree hierarchy'''
|
||||
@ -69,7 +77,7 @@ class MtreeCommand(gdb.Command):
|
||||
gdb.write('%s alias: %s@%016x (@ %s)\n' %
|
||||
(' ' * level,
|
||||
alias['name'].string(),
|
||||
ptr['alias_offset'],
|
||||
int(ptr['alias_offset']),
|
||||
alias,
|
||||
),
|
||||
gdb.STDOUT)
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/exec-all.h"
|
||||
@ -156,7 +157,9 @@ void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
|
||||
break;
|
||||
case 8:
|
||||
if (!(env->hflags2 & HF2_VINTR_MASK)) {
|
||||
qemu_mutex_lock_iothread();
|
||||
cpu_set_apic_tpr(x86_env_get_cpu(env)->apic_state, t0);
|
||||
qemu_mutex_unlock_iothread();
|
||||
}
|
||||
env->v_tpr = t0 & 0x0f;
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user