如何查询Ubuntu下指定PID进程(如QEMU)的CPUID调用情况
Ubuntu下指定进程/QEMU实例CPUID调用统计实现方案
可按落地成本、场景需求从以下三个方案里选,全部适配原生Ubuntu系统,不需要额外第三方依赖:
方案1:bpftrace轻量动态追踪(生产环境首选,零侵入)
基于内核eBPF能力实现,不需要重启进程、不需要修改QEMU配置,性能损耗低于1%,可以实时统计运行中进程的CPUID调用行为,支持按需启停。
核心逻辑是通过uprobe匹配目标进程用户态的CPUID指令(二进制固定编码为0f a2),同时通过kprobe挂载KVM的CPUID处理函数,同时覆盖QEMU自身调用宿主机CPUID、QEMU处理虚拟机Guest内部CPUID请求两类场景。
- 先安装依赖:
sudo apt update && sudo apt install bpftrace linux-tools-common linux-tools-$(uname -r) - 找到目标QEMU实例的PID:执行
pidof qemu-system-x86_64,从返回的进程列表里匹配你要统计的虚拟机实例对应的PID即可 - 新建追踪脚本
cpuid_trace.bt,内容如下:#!/usr/bin/env bpftrace BEGIN { printf("追踪启动,目标PID: %d,按Ctrl+C终止并输出统计结果\n", $1); } // 统计QEMU用户态自身触发的CPUID调用 uprobe:./**/*: /pid == $1 && *u8(reg("ip")) == 0x0f && *u8(reg("ip")+1) == 0xa2/ { $leaf = reg("ax"); $subleaf = reg("cx"); @host_cpuid_count[$leaf, $subleaf] = count(); } // 统计Guest虚拟机触发的CPUID请求 kprobe:kvm_emulate_cpuid /pid == $1/ { $leaf = arg1; $subleaf = arg2; @guest_cpuid_count[$leaf, $subleaf] = count(); } END { printf("\n=== QEMU进程自身调用宿主机CPUID统计 ===\n"); printf("%-8s %-8s %-8s\n", "LEAF", "SUBLEAF", "CALL_CNT"); print(@host_cpuid_count); printf("\n=== 虚拟机Guest触发CPUID统计 ===\n"); printf("%-8s %-8s %-8s\n", "LEAF", "SUBLEAF", "CALL_CNT"); print(@guest_cpuid_count); clear(@host_cpuid_count); clear(@guest_cpuid_count); } - 加执行权限后运行:
sudo chmod +x cpuid_trace.bt && sudo ./cpuid_trace.bt <目标PID> - 等虚拟机跑过完整业务负载后按Ctrl+C,就能拿到所有实际触发过的CPUID功能号(leaf)、子功能号(subleaf)和调用次数,对应CPU架构的CPUID编程手册就能匹配到具体功能。
注意:该方案只能统计脚本运行期间的CPUID调用,如果需要覆盖进程从启动开始的全量调用,选下面两个方案。
方案2:perf/ptrace全生命周期追踪
如果需要无遗漏统计进程从启动到退出的所有CPUID调用,有两种落地方式:
- 快速实现:用perf的Intel PT(处理器追踪)能力,直接采集进程执行流里的所有CPUID指令事件,不需要写代码:
该方式要求CPU支持Intel PT(Intel 5代酷睿以上、AMD Zen2以上都支持),短时间采集性能损耗可接受,长时间采集会生成较大的trace文件。# 附加到运行中进程采集 sudo perf record -e intel_pt//u -p <目标PID> --filter 'filter op cpuid' # 采集完成后解析结果 sudo perf script | grep cpuid | awk '{print $9,$10}' | sort | uniq -c - 自定义实现:基于ptrace写轻量追踪器,启动QEMU时就附加,扫描进程所有可执行内存段找到CPUID指令位置,替换为断点指令
0xcc,每次触发断点时读取寄存器记录leaf/subleaf,还原指令单步执行后恢复断点;针对QEMU TCG模式动态生成的代码,定期扫描新映射的可执行内存段补断点即可,该方式灵活性最高,可按需定制统计维度。
方案3:QEMU原生埋点统计(虚拟化场景最精准)
如果可以重启QEMU实例,直接用QEMU自带的能力即可,不需要内核态追踪,准确率100%,性能无损耗:
- 无代码修改方式:启动QEMU时加自带的debug参数,把所有CPUID处理日志输出到指定文件:
运行一段时间后直接解析日志去重,就能拿到所有Guest触发的CPUID调用记录,完全没有误报。# 在原有QEMU启动参数末尾加这两个参数 -d cpuid -D /var/log/qemu_cpuid_trace.log - 定制化方式:如果是自行编译的QEMU版本,可以直接在CPUID处理入口(TCG模式对应
helper_cpuid函数、KVM模式对应kvm_handle_cpuid函数)加哈希表统计逻辑,还可以扩展QMP命令支持实时查询已调用的CPUID功能列表,适合长期运行的生产环境做常态化统计。
统计时注意区分两类CPUID调用:如果你的目标是明确虚拟机实际用到的虚拟CPUID特性,优先统计Guest触发的CPUID请求即可,QEMU进程自身调用宿主机CPUID一般是初始化硬件适配、特性检测用,和虚拟机业务实际用到的特性无关。
内容的提问来源于stack exchange,提问作者chegov
相关产品推荐
相关产品推荐

