qemu指令计数
来源:互联网 发布:怎么样删除淘宝评价 编辑:程序博客网 时间:2024/06/07 17:38
使用全局变量use_icount标记qemu如何进行指令计数。
use_icout=0:表示不统计执行的指令数;
use_icout=1:表示精确同时执行的指令数;
use_icout=2:表示对执行的指令数进行适应性估计。
在configure_icount函数中对use_icount进行设置
void configure_icount(const char *option);
输入参数option为NULL时,use_icount=0;为"auto"时,use_icount=1;否则use_icount=1.
use_icount为1时,option中还包含着icount_time_shift的信息: icount_time_shift = strtol(option, NULL, 0);
use_icount为2时,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;
//所以,加上count后qemu_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_extra与env->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_start与gen_icount_end。但在use_icount为0时,它们不起任何作用。下面我们来看看这两个函数的内容,并分析它们所起的作用是什么。
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中的临时参数0xdeadbeef为num_insns,即所翻译TB中的目标指令数。
综合gen_icount_start和gen_icount_end函数,它们的作用就是让TCG引擎生成完成下面操作的代码:
比较env->icount_decr.u32与num_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();}}
- qemu指令计数
- Qemu中间代码微指令类型总结
- qemu指令翻译过程(1)-- ADD指令
- QEMU
- QEMU
- QEMU
- qemu
- qemu
- qemu
- QEMU
- QEMU
- QEMU
- qemu
- QEMU
- QEMU
- 操作系统:用二值信号量和一些机器指令实现计数信号量
- 计数
- 计数
- jkd7、tomcat7安装详解。Neither the JAVA_HOME nor the JRE_HOME environment variable is defined 错误解决
- Linux 多线程编程( POSIX )( 二 )----->代码区 ( pthread_attr_t 线程属性实例 )
- Linux 多线程编程( POSIX )( 二 )----->pthread_attr_t 线程属性
- memcached简单的使用教程
- 自学嵌入式 linux C好迷茫
- qemu指令计数
- CGImageRef 的 参数解释
- 私人云服务Jolicloud Me:收录用户在Web上的所有分享内容
- one question about type casting
- ☆【线性规划】【容斥原理】【NOI2010】能量采集
- C#实现检查指定端口被哪个进程占用
- Object Pascal语言基础
- Python 中不常见builtinfunction
- ADD FACEBOOK CONNECT TO A UNITY IPHONE GAME