Unraid 虚拟机里 perf 计数为 0 排查
Unraid 虚拟机里 perf 计数为 0
在 Unraid 的 Ubuntu 虚拟机里跑 perf stat,task-clock 有数,cycles 和 instructions 却一直是 0。加了 sudo,换成持续计算的 Python 程序,结果也一样。
这次的环境是 i3-12100、Unraid 7.3.2,宿主内核 6.18.38-Unraid,Ubuntu 内核 7.0.0-34-generic。虚拟 CPU 用的是 host-passthrough,宿主的 enable_pmu 也是 Y。
先用计算任务确认问题,命令在 Ubuntu 内执行:
sudo taskset -c 0 perf stat \
-e task-clock,cpu_core/cycles/,cpu_core/instructions/ -- \
python3 -c 'sum(range(100000000))'
输出中的关键三行:
552.10 msec task-clock
0 cpu_core/cycles/
0 cpu_core/instructions/
程序确实消耗了 CPU 时间,硬件计数却没有增长。
先查环境和 PMU
在 Ubuntu 虚拟机内查看内核、perf 版本和虚拟化类型:
uname -r
perf --version
systemd-detect-virt
三条命令依次返回:
7.0.0-34-generic
perf version 7.0.14
kvm
这确认了来宾内核、工具版本以及 KVM 环境。也可以检查来宾暴露了哪些事件,以及普通用户的访问限制:
perf list
cat /proc/sys/kernel/perf_event_paranoid
这两条属于补充检查,本次没有保留返回结果。事件出现在列表里,不代表一定能计数。这次使用 sudo 后依然为 0,需要继续查虚拟 PMU。
在 Unraid 宿主机终端查看宿主版本、物理 CPU 和 KVM 的 PMU 开关:
cat /etc/unraid-version
uname -r
lscpu | grep -E 'Model name|型号名称'
cat /sys/module/kvm/parameters/enable_pmu
对应输出为:
version="7.3.2"
6.18.38-Unraid
Model name: 12th Gen Intel(R) Core(TM) i3-12100
Y
最后的 Y 是 enable_pmu 的结果,只说明宿主允许 PMU 虚拟化;还要检查这台虚拟机的配置:
virsh list --all
virsh dumpxml 'Ubuntu' |
sed -n '/<features>/,/<\/features>/p; /<cpu /,/<\/cpu>/p'
Ubuntu 是列表中的虚拟机名称,使用时换成自己的。运行中的虚拟机会显示当前生效的配置;查看下次启动使用的持久配置,可以给 dumpxml 加上 --inactive。
虚拟机列表只摘录目标行:
Id Name State
12 Ubuntu running
原 XML 的相关部分是:
<features>
<acpi/>
<apic/>
</features>
<cpu mode='host-passthrough' check='none' migratable='off'>
<topology sockets='1' dies='1' clusters='1' cores='4' threads='2'/>
<cache mode='passthrough'/>
</cpu>
这里确认了 CPU 直通和 4 核 8 线程拓扑。没有 <pmu> 项,只能说明没有显式设置,不能直接判定 PMU 已关闭。
回到 Ubuntu 虚拟机内,读取 PMU 初始化日志和寄存器异常:
sudo dmesg | grep -iE -A 12 'performance events|PMU|unsupported.*CPU'
sudo dmesg | grep -iE -B 3 -A 20 'unchecked MSR|WRMSR|check_exception'
两次 dmesg 查询的关键字段摘录如下,省略了时间戳和无关调用栈:
Performance Events: Alderlake Hybrid events, full-width counters, Intel PMU driver.
core: cpu_core PMU driver:
... version: 2
... generic counters: 8
... fixed-purpose counters: 3
... global_ctrl mask: 00010007000000ff
unchecked MSR access error: WRMSR to 0x38f
(tried to write 0x00010007000000ff)
调用栈落在 __intel_pmu_enable_all。来宾识别出了 Alder Lake,按对应驱动初始化 PMU,但写控制寄存器时失败了。Linux 开发者也报告过同类 KVM 问题。
如果 dmesg 中已经没有启动时的记录,可以改查 journal。本次没有使用这条命令的返回结果:
sudo journalctl -k -b --no-pager |
grep -iE -B 3 -A 20 'performance events|PMU|unchecked MSR|WRMSR'
host-passthrough 暴露了宿主的 CPU 身份和特性,性能计数器却仍由 KVM 虚拟化。来宾驱动想用的能力,虚拟 PMU 未必完整支持。
当输出中出现 cpu_core、cpu_atom 时,还可以在来宾查询它们对应的 CPU 列表:
cat /sys/bus/event_source/devices/cpu_core/cpus
cat /sys/bus/event_source/devices/cpu_atom/cpus
| 查询路径 | 本次输出 |
|---|---|
cpu_core/cpus |
0-7 |
cpu_atom/cpus |
空,无 CPU 编号 |
文件不存在时表示没有暴露对应名称的 PMU,不能单凭这一点认定故障;换成 Broadwell 后也不必再依赖这两个路径。
换模型,还要显式开 PMU
先在 Unraid 上确认可用模型:
virsh domcapabilities --virttype kvm | grep -E "model.*usable=.yes."
列表中选用的这一行是:
<model usable='yes' vendor='Intel' canonical='Broadwell-v4'>Broadwell-noTSX-IBRS</model>
usable='yes' 表示宿主支持这个模型,不代表已经验证过 PMU。正常关闭虚拟机、备份 XML 后,把原来的整个 <cpu> 段换成:
<cpu mode='custom' match='exact' check='partial'>
<model fallback='forbid'>Broadwell-noTSX-IBRS</model>
<topology sockets='1' dies='1' clusters='1' cores='4' threads='2'/>
</cpu>
这里的拓扑沿用原来的 4 核 8 线程。第一次只换模型,启动后查询 dmesg,并用通用的 cycles,instructions 重跑相同计算负载,得到:
Performance Events: unsupported CPU family 6 model 61 no PMU driver, software events only.
569.70 msec task-clock
<not supported> cycles
<not supported> instructions
此时连硬件事件都不可用了,来宾只启用了软件事件。
还差一步:在已有的 <features> 里加入 <pmu state='on'/>,保留其他配置:
<features>
<acpi/>
<apic/>
<pmu state='on'/>
</features>
从 Unraid 重新启动虚拟机,在 Ubuntu 内确认驱动和错误日志,再测计数:
sudo dmesg | grep -iE 'Performance Events|unchecked MSR|WRMSR'
sudo taskset -c 0 perf stat -e task-clock,cycles,instructions -- \
python3 -c 'sum(range(100000000))'
这次加载的是 Broadwell PMU 驱动,计数恢复了:
Performance Events: Broadwell events, Intel PMU driver.
578.77 msec task-clock
2344786616 cycles
13450293438 instructions
会不会变慢
程序仍在 i3-12100 上通过 KVM 执行,频率和物理缓存不会变成 Broadwell 的规格。不过,命名 CPU 模型会改变来宾可见的特性,部分程序可能因此选择不同的实现路径。
我没有做实际业务的重复对照测试,所以暂时只能确认基础计数恢复,不能说性能没有损失。Broadwell 专属事件、缓存指标和 Top-down 也没有验证。这套配置先解决了当前机器上的问题,不能直接套到所有虚拟机上。