perf kvm查看虚机热点调用

使用PerfKVM分析无法连接虚机的函数调用
当无法直接连接到虚拟机进行分析时,可以借助PerfKVM在宿主机上进行监控。首先从虚机导出kallsyms和modules文件,然后在宿主机上使用PerfKVM记录并分析指定虚机进程的调用情况。通过示例展示,当虚机执行dd命令时,观察到大量shmen写操作,验证了分析的有效性。

背景:

当需要分析虚机内部函数调用情况,有时候无法连接到虚机(例如ssh和vnc都连不进去),这时候常规手段就无法进行分析。此时可用perf kvm在宿主机上去分析虚机内部得调用情况。

步骤:

1. 导出虚机内部的kallsyms和modules文件到宿主机上。如果虚机已经无法连接进去,可找一台相同的虚机(内核和硬件配置都一致)并导出这两个文件。下面示例,guest对应待导出文件的虚机。

   ssh guest  "cat /proc/kallsyms" > /tmp/guest.kallsyms
   ssh guest  "cat /proc/modules" > /tmp/guest.modules

2. 在宿主机上开始监测,pid对应虚机的主进程号:

   perf kvm  --host --guest --guestkallsyms=/tmp/guest.kallsyms --guestmodules=/tmp/guest.modules  record -p pid  -a -g

   采集一段时间后 ctrl + c停止采集,会在当前目录下生成perf.data.kvm文件

3. 分析采集报告:

   perf kvm --guest --guestkallsyms=/tmp/guest.kallsyms --guestmodules=/tmp/guest.modules report -i perf.data.kvm

  

 示例:  

测试在虚机上进行dd命令:

dd if=/dev/zero of=/tmp/tmp.bin bs=1048576 count=10240

在宿主机上执行采集分析后得到下面结果:

可以看出有大量的shmen写操作,符合预期

<think>我们正在处理一个关于perf report显示调用调用次数的问题。根据用户的问题,用户希望了解如何在perf report中显示每个调用链的调用次数。这通常用于性能分析和优化,以便了解哪些代码路径被频繁执行。首先,我们需要回顾一下perfreport的基本功能。perf report用于展示perfrecord记录的性能数据。默认情况下,它按照函数或符号的样本数量(即事件发生的次数)来排序,并显示每个函数的样本数占总样本数的百分比。但是,用户希望看到的是每个调用链的调用次数,也就是整个调用路径被采样的次数。在perf中,调用链(callchain)是通过记录函数调用的堆栈信息来构建的。当使用`-g`选项进行perf record时,会记录调用链信息。在perf report中,我们可以通过展开调用链来查看从顶层函数到底层函数的整个路径。然而,默认的perfreport并不直接显示每个调用链的调用次数(即该调用链被采样的次数)。它显示的是每个函数的样本数(包括该函数自身以及其子调用链的样本)。如果我们想看到每个完整的调用链的调用次数,我们需要使用perfreport的`--sort`选项来定制排序和显示。根据引用[3]中提到的,`--sort`参数可以指定多个键来对直方图条目进行排序和分组。我们可以使用`srcline`(源代码行)或`symbol`(符号)等键,但更重要的是,我们可以使用`callchain`相关的键吗?实际上,在perf中,我们可以通过`--fields`参数(或`-F`)来指定显示的字段,而`--sort`则用于排序。但是,查看perf的帮助文档(man perf-report),我们发现有一个`--fields`选项可以指定显示的字段。默认情况下,perfreport显示`overhead`(开销)、`command`(命令)、`shared object`(共享对象)和`symbol`(符号)。我们可以通过`--fields`添加更多的字段,例如`srcline`(源代码行)或`symbol`(函数符号)等。然而,我们想要显示的是整个调用链的调用次数,这实际上是一个调用链的样本计数。在perf中,每个调用链样本实际上是一个堆栈,而perf report默认将样本按照函数(即堆栈顶部的函数)进行聚合。如果我们想按完整的调用链进行聚合,我们需要使用`--group`或类似的选项?但perf并没有直接提供按整个调用链分组的功能。实际上,我们可以通过以下方式近似实现:1.使用`perf script`命令将原始数据输出,然后使用脚本(如awk或Python)对调用链进行聚合计数。2.在perfreport中,我们可以通过展开调用链并查看每个调用链条目的样本数,但这需要手动展开,并且不是以整个调用链为单位的计数。但是,用户可能希望直接在perfreport中看到。经过查阅,我们发现perf report有一个`--children`选项(默认启用),它使得每个函数的样本数包括其子函数的样本。而使用`--no-children`(引用[1])则只显示函数本身的样本。但这并不是我们需要的。另一种思路:使用`--sort`按照调用链的根节点(即最顶层的函数)进行分组,然后展开调用查看每个分支的样本数。但这仍然不是整个调用链的计数。实际上,perfreport目前不支持直接按整个调用链分组并计数。但我们可以使用`perf script`来导出数据,然后使用其他工具处理。不过,我们也可以尝试使用`perf report`的`-n`选项(或`--show-nr-samples`)来显示每个条目的样本数(即该函数被采样的次数,不包括子调用)。但是,这只能显示每个函数的样本数,而不是整个调用链的。因此,我建议使用以下步骤来获取每个调用链的调用次数:1.使用`perfscript`命令将记录的数据导出为文本格式,其中每一行代表一个样本,并包含完整的调用链。2.使用脚本处理这些文本,对相同的调用链进行计数。例如:``` perfscript >perf.script```然后,我们可以使用awk等工具对调用链进行计数。但是,由于调用链可能很长,而且每个样本的调用链深度不同,我们需要将整个调用链作为键来计数。一个简单的awk脚本示例(假设调用链在每一行中以堆栈的方式表示,从最内层到最外层):注意:perfscript输出的调用链格式通常是:函数名(模块)[地址],我们可以忽略地址和模块,只关注函数名,但要注意同一函数的不同地址(如内联)可能被视为不同。但是,perf script的输出格式可能比较复杂,我们可以使用`--fields`来控制输出字段。例如,我们可以只输出调用链的符号:``` perfscript -F comm,pid,tid,time,event,sym,symoff,dso```然而,更简单的方法是使用`perf script`的`-G`选项(调用链图)?或者使用`stackcollapse-perf.pl`(来自BrendanGregg的FlameGraph工具)将perf数据转换为折叠格式,然后进行计数。具体步骤:1.下载FlameGraph工具:https://github.com/brendangregg/FlameGraph2.使用以下命令将perf数据转换为折叠格式:```perf script| stackcollapse-perf.pl> out.folded```折叠格式的每一行是一个调用链(用分号分隔的函数名)和一个样本数(或该调用链出现的次数)。3.这样,我们就可以在out.folded文件中看到每个调用链出现的次数。例如,out.folded中的一行:main;foo;bar10表示调用链main->foo->bar出现了10次。因此,通过FlameGraph的stackcollapse-perf.pl脚本,我们可以很容易地得到每个调用链的调用次数。如果用户希望不借助外部工具,而直接使用perf内置的功能,那么目前perfreport无法直接按整个调用链计数。但是,我们可以通过perf report的`--call-graph`选项设置显示调用链的深度,并查看每个调用路径上的样本数。在perfreport的交互式界面中,展开调用链后,每个调用链分支的样本数会显示在括号中(即该分支上的样本数,不包括更深层的调用)。但这并不是整个调用链的计数,而是该分支点上的计数。总结:要获得每个完整调用链的调用次数,推荐使用FlameGraph工具中的`stackcollapse-perf.pl`脚本。如果用户希望使用perfreport本身,那么可以尝试以下:-使用`perf report--sortsrcline,symbol`等,并查看调用链,但这样只能看到每个函数的样本数,而不是整个调用链的。因此,我建议使用外部工具进行处理。相关问题:1.如何安装和使用FlameGraph工具?2.除了FlameGraph,还有其他方法可以统计调用链的调用次数吗?3.在perf report中,如何设置调用链的显示深度?注意:在回答中,我们引用了站内引用[1][2][3],但根据用户的问题,我们主要关注的是显示调用次数,而引用中提到的参数(如--no-children, -v,--sort)并不是直接解决这个问题的,因此我们参考了这些参数的功能,但给出了不同的解决方案。回答结构:1.解释问题:用户希望看到每个调用链的调用次数。2.说明perfreport默认不直接支持。3.提供替代方案:使用perf script和FlameGraph工具。4.给出具体步骤。5.如果用户坚持使用perfreport,说明可以查看调用链分支的样本数(但不是整个调用链的计数)。下面开始正式回答。</think>### Perf Report 显示调用调用次数的方法 在 `perf report` 中显示每个调用链的调用次数(即采样事件在特定代码路径上的发生次数),可以通过以下两种方式实现: #### 方法 1:使用 `perf script` + 自定义脚本(推荐) 这是最直接获取完整调用链统计的方式: ```bash # 1. 导出原始采样数据(需先通过 perf record -g 记录调用链) perf script > perf.data.txt # 2. 使用 AWK 统计调用链出现次数 awk ' BEGIN { FS = "[ /]+" } /^ / { stack = "" for (i=5; i<=NF; i++) { if ($i ~ /^\./) break # 跳过地址偏移量 if ($i != "") stack = stack (stack==""?"":";") $i } count[stack]++ } END { for (s in count) print count[s], s }' perf.data.txt | sort -nr ``` **输出示例**: ``` 1200 main;process_data;validate_input 850 main;io_operation;read_file 300 interrupt_handler;disk_interrupt ``` **说明**: - 每行显示调用链及其出现次数 - 调用链格式:`函数A;函数B;函数C`(从外层到内层) - 按调用次数降序排序 #### 方法 2:在 `perf report` 交互界面查看 1. **启动报告**: ```bash perf report -n --stdio # -n 显示采样次数 ``` 2. **解读输出**: ```perf # Overhead Samples Command Shared Object Symbol # ........ ....... ....... ............. ...... # 42.30% 10500 myapp myapp [.] main | ---main | |--65.00%-- process_data | | | |--80.00%-- validate_input | | 0.5%-- log_error # 此行显示 10500 * 65% * 80% ≈ 5460 次 | |--30.00%-- io_operation | |--90.00%-- read_file # 10500 * 30% * 90% ≈ 2835 次 ``` **关键点**: - **`-n` 参数**:在每行显示绝对采样次数(上例中的 `10500`)[^1] - **百分比计算**: - 第一级百分比(如 `65.00%`)基于父节点采样数 - 实际调用次数 = 父节点采样数 × 当前分支百分比 - **限制**:只能查看分支节点计数,无法直接导出完整调用链计数 ### 补充说明 1. **采样精度**: - 实际次数 ≈ `采样总数 × (函数在调用链中的百分比)` - 精确值需通过 `perf script` 统计(方法1) 2. **其他有用参数**: ```bash perf report --sort=srcline # 显示源代码行号[^2] perf report --no-children # 仅显示函数自身耗时[^1] perf report -g graph,0.5 # 过滤掉占比<0.5%的调用链 ``` 3. **可视化工具**: - **FlameGraph**:生成调用链频率火焰图 ```bash perf script | stackcollapse-perf.pl | flamegraph.pl > out.svg ``` ### 相关问题 1. 如何过滤 `perf report` 中低于特定阈值的调用链? 2. `perf script` 输出的调用链格式如何解析? 3. 火焰图(FlameGraph)在性能分析中有哪些具体应用? 4. 如何关联 `perf report` 中的符号与源代码行号?[^2] [^1]: 默认情况下 `perf report` 会包含子函数耗时,使用 `--no-children` 可仅显示函数自身消耗。 [^2]: 通过 `-v` 参数可显示符号地址和源代码行号,帮助定位具体代码位置。 [^3]: `--sort` 参数支持按 PID、符号、源代码行等多维度分类数据。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值