mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-26 21:10:42 +00:00
shitty spin loop detector
This commit is contained in:
parent
bbcd5763e6
commit
029bc377a1
@ -879,6 +879,22 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
||||
|
||||
/* main execution loop */
|
||||
|
||||
|
||||
|
||||
/* Note: only supports millisecond resolution on Windows */
|
||||
static void sleep_ns(int64_t ns)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
struct timespec sleep_delay, rem_delay;
|
||||
sleep_delay.tv_sec = ns / 1000000000LL;
|
||||
sleep_delay.tv_nsec = ns % 1000000000LL;
|
||||
nanosleep(&sleep_delay, &rem_delay);
|
||||
#else
|
||||
Sleep(ns / SCALE_MS);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int cpu_exec(CPUState *cpu)
|
||||
{
|
||||
int ret;
|
||||
@ -935,6 +951,8 @@ int cpu_exec(CPUState *cpu)
|
||||
assert_no_pages_locked();
|
||||
}
|
||||
|
||||
int hotblocks = 0;
|
||||
|
||||
/* if an exception is pending, we execute it here */
|
||||
while (!cpu_handle_exception(cpu, &ret)) {
|
||||
TranslationBlock *last_tb = NULL;
|
||||
@ -989,12 +1007,43 @@ int cpu_exec(CPUState *cpu)
|
||||
}
|
||||
#endif
|
||||
/* See if we can patch the calling TB. */
|
||||
if (last_tb) {
|
||||
if (last_tb && !tb->hot) {
|
||||
tb_add_jump(last_tb, tb_exit, tb);
|
||||
}
|
||||
|
||||
cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit);
|
||||
|
||||
if (tb->hot) {
|
||||
hotblocks += 1;
|
||||
} else {
|
||||
hotblocks = 0;
|
||||
}
|
||||
|
||||
/* Chill */
|
||||
if (hotblocks > 100) {
|
||||
/* XXX: Eventually all regularly executed blocks will be
|
||||
* considired 'hot' with current dumb counter.
|
||||
*
|
||||
* - Decayed binning
|
||||
* - Temporal distance from vsync to estimate callback
|
||||
* probability
|
||||
* - See if cooling impacts cycles (if yes, then probably
|
||||
* interrupt bound; if no, then probably false positive)
|
||||
* - Regular sampling to measure which ones are most hot
|
||||
* - Global exec counter for delta
|
||||
*/
|
||||
|
||||
hotblocks = 0;
|
||||
/* XXX: Replace with schedule. Don't hold locks */
|
||||
#if 1
|
||||
sleep_ns(1000000);
|
||||
#else
|
||||
cpu->halted = 1;
|
||||
cpu->exception_index = EXCP_HALTED;
|
||||
qatomic_set(&cpu->exit_request, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Try to align the host and virtual clocks
|
||||
if the guest is in advance */
|
||||
align_clocks(&sc, cpu);
|
||||
|
@ -1445,8 +1445,24 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
}
|
||||
QEMU_BUILD_BUG_ON(CF_COUNT_MASK + 1 != TCG_MAX_INSNS);
|
||||
|
||||
bool tb_hot = false;
|
||||
|
||||
tb = inv_tb_htable_lookup(cpu, pc, cs_base, flags, cflags);
|
||||
if (tb) {
|
||||
#if 1
|
||||
if ((tb->xcount & (1ULL << 63)) && !tb->hot) {
|
||||
fprintf(stderr, "hotblock re-translate %x\n", tb->pc);
|
||||
|
||||
qemu_spin_lock(&tb->jmp_lock);
|
||||
qatomic_set(&tb->cflags, tb->cflags & ~CF_INVALID);
|
||||
qemu_spin_unlock(&tb->jmp_lock);
|
||||
uint32_t h = tb_hash_func(phys_pc, tb->pc, tb->flags, tb_cflags(tb),
|
||||
tb->trace_vcpu_dstate);
|
||||
qht_remove(&tb_ctx.inv_htable, tb, h);
|
||||
tb_hot = true;
|
||||
} else {
|
||||
#endif
|
||||
|
||||
qemu_spin_lock(&tb->jmp_lock);
|
||||
qatomic_set(&tb->cflags, tb->cflags & ~CF_INVALID);
|
||||
qemu_spin_unlock(&tb->jmp_lock);
|
||||
@ -1455,6 +1471,10 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
bool removed = qht_remove(&tb_ctx.inv_htable, tb, h);
|
||||
g_assert(removed);
|
||||
goto recycle_tb;
|
||||
|
||||
#if 1
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
buffer_overflow:
|
||||
@ -1469,6 +1489,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
}
|
||||
|
||||
gen_code_buf = tcg_ctx->code_gen_ptr;
|
||||
tb->hot = tb_hot;
|
||||
tb->tc.ptr = tcg_splitwx_to_rx(gen_code_buf);
|
||||
tb->pc = pc;
|
||||
tb->cs_base = cs_base;
|
||||
|
@ -492,6 +492,8 @@ struct TranslationBlock {
|
||||
target_ulong cs_base; /* CS base for this block */
|
||||
uint32_t flags; /* flags defining in which context the code was generated */
|
||||
uint32_t cflags; /* compile flags */
|
||||
uint64_t xcount;
|
||||
bool hot;
|
||||
|
||||
/* Note that TCG_MAX_INSNS is 512; we validate this match elsewhere. */
|
||||
#define CF_COUNT_MASK 0x000001ff
|
||||
|
@ -106,6 +106,7 @@ DEF_HELPER_FLAGS_2(flush_page, TCG_CALL_NO_RWG, void, env, tl)
|
||||
DEF_HELPER_FLAGS_2(hlt, TCG_CALL_NO_WG, noreturn, env, int)
|
||||
DEF_HELPER_FLAGS_2(monitor, TCG_CALL_NO_WG, void, env, tl)
|
||||
DEF_HELPER_FLAGS_2(mwait, TCG_CALL_NO_WG, noreturn, env, int)
|
||||
DEF_HELPER_FLAGS_2(hotblock, TCG_CALL_NO_WG, void, env, ptr)
|
||||
DEF_HELPER_1(rdmsr, void, env)
|
||||
DEF_HELPER_1(wrmsr, void, env)
|
||||
DEF_HELPER_FLAGS_2(read_crN, TCG_CALL_NO_RWG, tl, env, int)
|
||||
|
@ -481,6 +481,22 @@ void QEMU_NORETURN helper_hlt(CPUX86State *env, int next_eip_addend)
|
||||
do_hlt(env);
|
||||
}
|
||||
|
||||
#include "exec/translate-all.h"
|
||||
|
||||
void /*QEMU_NORETURN*/ helper_hotblock(CPUX86State *env, void *opaque)
|
||||
{
|
||||
TranslationBlock *tb = opaque;
|
||||
fprintf(stderr, "hotblock %x (%ld iterations)\n", tb->pc, tb->xcount & ~(1ULL << 63));
|
||||
|
||||
#if 1
|
||||
/* Re-translate */
|
||||
CPUState *cpu = env_cpu(env);
|
||||
tb_invalidate_phys_page_range(tb->page_addr[0], tb->page_addr[0]);
|
||||
#else
|
||||
tb->hot = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void helper_monitor(CPUX86State *env, target_ulong ptr)
|
||||
{
|
||||
if ((uint32_t)env->regs[R_ECX] != 0) {
|
||||
|
@ -7696,6 +7696,43 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
|
||||
gen_jmp_im(s, s->pc - s->cs_base);
|
||||
gen_eob_inhibit_irq(s, true);
|
||||
}
|
||||
|
||||
#if 1
|
||||
/*
|
||||
0x8001b02e: sti
|
||||
0x8001b02f: nop
|
||||
0x8001b030: nop
|
||||
0x8001b031: cli
|
||||
0x8001b032: cmp 0x0(%ebp),%ebp
|
||||
0x8001b035: je 0x8001b043
|
||||
0x8001b037: mov $0x2,%cl
|
||||
0x8001b039: call 0x8001415c
|
||||
0x8001b03e: call 0x8001b08f
|
||||
0x8001b043: cmpl $0x0,0x2c(%ebx)
|
||||
0x8001b047: je 0x8001b02e
|
||||
0x8001b049: sti
|
||||
0x8001b04a: mov 0x2c(%ebx),%esi
|
||||
0x8001b04d: mov 0x28(%ebx),%edi
|
||||
0x8001b050: movl $0x0,0x2c(%ebx)
|
||||
*/
|
||||
/* Shitty peek to see if this is the idle loop */
|
||||
if (translator_ldub(env, s->pc+0) == 0x90 &&
|
||||
translator_ldub(env, s->pc+1) == 0x90 &&
|
||||
translator_ldub(env, s->pc+2) == 0xfa
|
||||
) {
|
||||
fprintf(stderr, "idle loop at @ %x\n", s->pc);
|
||||
|
||||
#if 0
|
||||
/* Insert a HLT to exit CPU loop */
|
||||
if (check_cpl0(s)) {
|
||||
gen_update_cc_op(s);
|
||||
gen_jmp_im(s, pc_start - s->cs_base);
|
||||
gen_helper_hlt(cpu_env, tcg_const_i32(s->pc - pc_start));
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 0x62: /* bound */
|
||||
if (CODE64(s))
|
||||
@ -9124,6 +9161,45 @@ static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
|
||||
|
||||
static void i386_tr_tb_start(DisasContextBase *db, CPUState *cpu)
|
||||
{
|
||||
/* XXX: Don't need all this logic here..can periodically check instead */
|
||||
|
||||
// DisasContext *s = container_of(db, DisasContext, base);
|
||||
TranslationBlock *tb = db->tb;
|
||||
|
||||
if (tb->hot) {
|
||||
tb->xcount = 1ULL<<63;
|
||||
TCGv_i64 val = tcg_temp_local_new_i64();
|
||||
TCGv_ptr ptr = tcg_const_local_ptr(&tb->xcount);
|
||||
tcg_gen_ld_i64(val, ptr, 0);
|
||||
tcg_gen_addi_i64(val, val, 1);
|
||||
tcg_gen_st_i64(val, ptr, 0);
|
||||
tcg_temp_free_ptr(ptr);
|
||||
tcg_temp_free_i64(val);
|
||||
return;
|
||||
}
|
||||
|
||||
tb->xcount = 0;
|
||||
|
||||
TCGLabel *l_doblock = gen_new_label();
|
||||
TCGv_i64 val = tcg_temp_local_new_i64();
|
||||
TCGv_ptr ptr = tcg_const_local_ptr(&tb->xcount);
|
||||
|
||||
/* Increment exec counter */
|
||||
tcg_gen_ld_i64(val, ptr, 0);
|
||||
tcg_gen_addi_i64(val, val, 1);
|
||||
tcg_gen_st_i64(val, ptr, 0);
|
||||
|
||||
tcg_gen_brcondi_i64(TCG_COND_LTU, val, 100000000, l_doblock); /* Still cold */
|
||||
tcg_gen_brcondi_i64(TCG_COND_GTU, val, 1ULL << 63, l_doblock); /* Already flagged */
|
||||
|
||||
/* Flag it */
|
||||
tcg_gen_ori_i64(val, val, 1ULL << 63);
|
||||
tcg_gen_st_i64(val, ptr, 0);
|
||||
gen_helper_hotblock(cpu_env, tcg_const_ptr(tb));
|
||||
|
||||
gen_set_label(l_doblock);
|
||||
tcg_temp_free_ptr(ptr);
|
||||
tcg_temp_free_i64(val);
|
||||
}
|
||||
|
||||
static void i386_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
|
||||
|
Loading…
Reference in New Issue
Block a user