shitty spin loop detector

This commit is contained in:
Matt Borgerson 2021-11-03 18:35:50 -07:00
parent bbcd5763e6
commit 029bc377a1
6 changed files with 166 additions and 1 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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

View file

@ -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)

View file

@ -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) {

View file

@ -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)