qemu指令计数

本文介绍QEMU中如何通过全局变量use_icount控制指令计数,包括不同取值的意义及配置函数configure_icount的工作原理。此外,详细解析了qemu_cpu_exec函数内部实现指令计数的过程,以及TB执行过程中gen_icount_start和gen_icount_end两个函数如何协同工作生成指令计数代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用全局变量use_icount标记qemu如何进行指令计数。

use_icout=0:表示不统计执行的指令数;

use_icout=1:表示精确同时执行的指令数;

use_icout=2:表示对执行的指令数进行适应性估计。


在configure_icount函数中对use_icount进行设置

void configure_icount(const char *option);

输入参数optionNULL时,use_icount=0;为"auto"时,use_icount=1;否则use_icount=1.

use_icount1时,option中还包含着icount_time_shift的信息:     icount_time_shift = strtol(option, NULL, 0);

use_icount2时,icount_time_shift = 3;


qemu中使用全局变量qemu_icount记录执行的指令数,但这个计数值会大于实际执行的指令数,因为其中包含了尚未执行的一些指令。利用这个全局变量计数的功能在qemu_cpu_exec函数中实现。

    if (use_icount) {

        int64_t count;

        int decr;

        qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);

        env->icount_decr.u16.low = 0;

        env->icount_extra = 0;

        count = qemu_icount_round (qemu_next_deadline());

//count是距离下次事件发生还需执行的指令数,这些指令尚未执行

        qemu_icount += count;

//所以,加上countqemu_icount表示的就不仅仅是已经执行的指令数

        decr = (count > 0xffff) ? 0xffff : count;

        count -= decr;

//count分成了两部分,一部分存放在icount_decr.u16.low中,这用来控制TB的执行,防止连续执行的指令过多,以至于超出限制。

        env->icount_decr.u16.low = decr;

        env->icount_extra = count;

    }

ret = cpu_exec(env);

//cpu_exec会连续执行,但执行指令数不会超过env->icount_extraenv->icount_decr.u16.low之和。

    if (use_icount) {

        qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);

//这时的qemu_icount是实际执行的指令数

        env->icount_decr.u32 = 0;

        env->icount_extra = 0;

    }

TB执行时是如何进行指令计数呢?

在生成中间码函数gen_intermediate_code_internal中,调用了两个函数来生成指令计数代码,它们可记录下来所翻译TB中包含的目标指令数目。这两个函数就是gen_icount_startgen_icount_end。但在use_icount0时,它们不起任何作用。下面我们来看看这两个函数的内容,并分析它们所起的作用是什么。

static inline void gen_icount_start(void)

{

    TCGv_i32 count;

    if (!use_icount)

        return;

    icount_label = gen_new_label();

    count = tcg_temp_local_new_i32();

    tcg_gen_ld_i32(count, cpu_env, offsetof(CPUState, icount_decr.u32));

    /* This is a horrid hack to allow fixing up the value later.  */

    icount_arg = gen_opparam_ptr + 1;

    tcg_gen_subi_i32(count, count, 0xdeadbeef);

    tcg_gen_brcondi_i32(TCG_COND_LT, count, 0, icount_label);

    tcg_gen_st16_i32(count, cpu_env, offsetof(CPUState, icount_decr.u16.low));

    tcg_temp_free_i32(count);

}

use_icount不为0时,gen_icount_start函数执行后产生一系列的中间码,根据这些中间码,TCG引擎将会生成关于指令计数的代码。

函数中的常量0xdeadbeef并无实际意义,它只是起辅助作用,因为用它生成的中间码在TCG之前还会被修改。icount_arg指向存放0xdeadbeef的中间码参数指针,在gen_icount_end函数中会对其修改。

static void gen_icount_end(TranslationBlock *tb, int num_insns)

{

    if (use_icount) {

        *icount_arg = num_insns;

        gen_set_label(icount_label);

        tcg_gen_exit_tb((long)tb + 2);

    }

}

可以看到,gen_icount_end中语句:

*icount_arg = num_insns;

作用是修改gen_icount_start中的临时参数0xdeadbeefnum_insns,即所翻译TB中的目标指令数。

综合gen_icount_startgen_icount_end函数,它们的作用就是让TCG引擎生成完成下面操作的代码:

比较env->icount_decr.u32num_insns,如果小于0,跳过TB代码,并返回(long)tb+2;否则,env->icount_decr.u32 -= num_insns

返回(long)tb+2后,在cpu_exec函数中执行下面语句:

	next_tb = tcg_qemu_tb_exec(tc_ptr);
	if ((next_tb & 3) == 2) {
		/* Instruction counter expired.  */
		int insns_left;
		tb = (TranslationBlock *)(long)(next_tb & ~3);
		/* Restore PC.  */
		cpu_pc_from_tb(env, tb);
		insns_left = env->icount_decr.u32;
		if (env->icount_extra && insns_left >= 0) {
			/* Refill decrementer and continue execution.  */
			env->icount_extra += insns_left;
			if (env->icount_extra > 0xffff) {
				insns_left = 0xffff;
			} else {
				insns_left = env->icount_extra;
			}
			env->icount_extra -= insns_left;
			env->icount_decr.u16.low = insns_left;
		} else {
			if (insns_left > 0) {
				/* Execute remaining instructions.  */
				cpu_exec_nocache(insns_left, tb);
			}
			env->exception_index = EXCP_INTERRUPT;
			next_tb = 0;
			cpu_loop_exit();
		}
	}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值