QEMU 自带的简易计时器 — profiler 的简介及代码分析

我们应该怎么分析QEMU代码中某段代码的性能呢?除了比较复杂的trace-event功能(我的博客中翻译过qemu tracing的文档),其实在QEMU自带有一个简单的profiler实现,它是一个简单的计时器封装。这篇博客主要介绍怎么在编译时开启、使用QEMU profiler,并说明怎么利用这个功能添加一个自己的计时器来分析QEMU中某段代码的性能。

1. 编译

我的代码是QEMU 2.12.0。要开启profiler功能,在编译前进行运行configure的时候,只要加入--enable-profiler选项就可以了,它会加入CONFIG_PROFILER这个宏定义。比如我用如下选项进行编译:

将其编译到QEMU后,无须改动启动参数,它是默认启用的,但是我们一般需要用QMP shell来查看它帮我们计时的信息。

2. 使用

在启动QEMU虚拟机的命令中,我们需要加入一个QMP socket,用于一会接入我们的QMP shell:

在虚拟机启动后,用QEMU源码中自带的QMP shell脚本连接QMP socket:

之后出现以下欢迎界面:

我们在(QEMU)后面输入info profile就可以看到QEMU自带的两个计时器的数值,每次查看完这个数值,数值会清零。

3. 实现

QEMU源码中,计时器功能的实现,主要与monitor.cinclude/qemu/timer.h这两个文件有关文件实现。而使用这个profiler进行计时的只有两个变量:一个是vl.cdev_time(即上面的async time);一个是cpus.ctcg_time(即上面的qemu time),由于我们使用的是KVM,没有用TCG,所以这个值应该一直为0。

首先,计时器变量都定义在monitor.c,就是和QMP实现相关的代码文件中:

查询计时器的代码也在这附近,可以看到,的确和我们刚才用info profile查询时打印的信息一致,而且打印后进行了清零操作:

include/qemu/timer.h中实现了计时器相关的函数,所以实际进行计时的代码段会包含它,其中也有计时器变量的外部声明:

我们可以以dev_time这个计时器为例看一下,开始和结束计时之间的代码就是被计时的代码,很自然的方式:

4. 扩展应用

根据这种思路,我们也很容易添加自己的计时器,只要以下几步:

  1. include/qemu/timer.h进行计时器变量声明;
  2. monitor.c进行计时器变量定义,并在hmp_info_profile函数加入自己喜欢的打印格式,在打印后也可以选择将计时器变量清零;
  3. 在要计时的代码段所在文件中包含qemu/timer.h头文件;
  4. 最后,在要计时的代码段前后加入profile_getclock()函数获取时间并累加到我们新定义的计时器变量上就可以了。

[1] 我的wiki–关于QMP, https://github.com/zhangjaycee/real_tech/wiki/virtual_018#接入qemu-monitor

[2] QEMU Docs, https://qemu.weilnetz.de/doc/qemu-doc.html

发表评论

电子邮件地址不会被公开。 必填项已用*标注