负载分析和排查七
明白了 👍
你的需求是 全系统范围统计 syscall 的耗时占比,而不仅仅是单个进程或 perf trace 默认输出的那种“分进程 + syscall”的 summary。
我给你梳理一下思路和可行方案:
1. 为什么你现在的 perf trace -a --summary 不行
-
perf trace默认 summary 是 按进程分组,然后在每个进程下列 syscall。 -
所以你看到的输出是:
-
containerd-shim 的 syscall summary
-
runc 的 syscall summary
-
…每个进程单独统计。
-
-
你后面
awk只是取了单个 summary 区块的数值,并没有把所有进程的 syscall 聚合。
2. 全系统聚合统计 syscall 耗时占比的几种方法
方法一:perf stat -e syscalls:sys_enter_*
sudo perf stat -a -e 'syscalls:sys_enter_*' sleep 10
-
它能统计所有 syscall 的调用次数(event count),全系统范围。
-
但缺点:只统计调用次数,没法直接得出 syscall 耗时。
方法二:perf record + perf script 聚合
-
记录一段时间的 syscall:
sudo perf record -a -e syscalls:sys_enter_* -e syscalls:sys_exit_* sleep 10sys_enter+sys_exit配对,才能得到耗时。 -
用
perf script导出原始事件:sudo perf script > out.perf -
用 bcc 工具 / 自己写脚本做聚合:
-
把 enter/exit 配对求耗时
-
按 syscall 汇总调用次数 & 总耗时
-
最后算百分比。
-
方法三:直接用 bcc/eBPF(推荐)
比如 bcc 自带的 syscount / syslatency:
sudo /usr/share/bcc/tools/syscount -p # 统计所有进程所有 syscalls 次数
sudo /usr/share/bcc/tools/syslatency # 统计每个 syscall 的耗时分布
要做 耗时占比 可以直接改 syscount.py,让它统计:
-
调用次数
-
总耗时
-
占比 = 总耗时 / 所有 syscall 耗时
这样就能得到类似:
SYSCALL CALLS TOTAL(ms) AVG(us) PERCENT
futex 12345 1256.3 101.7 34.5%
read 6789 980.1 144.4 26.9%
write 4567 876.2 191.8 23.9%
...
3. 总结对比
| 方法 | 是否全系统 | 是否有耗时 | 是否需要额外工具 |
|---|---|---|---|
| perf stat sys_enter | ✅ | ❌ | 无 |
| perf record + script | ✅ | ✅ | 需要自己写脚本聚合 |
| bcc syscount/syslatency | ✅ | ✅ | 需要安装 bcc/eBPF |
👉 所以结论是:
如果你只要调用次数,用 perf stat -a -e syscalls:sys_enter_* 就够了。
如果你要调用耗时占比,最稳妥的方法是 用 bcc 的 syscount/syslatency 脚本,直接能拿到全系统聚合数据。
要不要我帮你写一个 基于 bcc 的 Python 脚本,直接输出“全系统 syscalls 总耗时占比表”?
#!/usr/bin/env python3
import sys
import re
from collections import defaultdict
if len(sys.argv) != 2:
print(f"Usage: {sys.argv[0]} out.perf")
sys.exit(1)
filename = sys.argv[1]
# syscall 统计
calls = defaultdict(int)
time_us = defaultdict(float)
# 存储每个 pid 的 enter 时间戳
stack = dict() # key = (pid, syscall), value = timestamp
# 匹配 enter/exit
enter_re = re.compile(r'\s*(\S+)\s+(\d+)\s+\[\d+\]\s+([\d.]+):\s+syscalls:sys_enter_(\w+):')
exit_re = re.compile(r'\s*(\S+)\s+(\d+)\s+\[\d+\]\s+([\d.]+):\s+syscalls:sys_exit_(\w+):')
with open(filename) as f:
for line in f:
m_enter = enter_re.match(line)
if m_enter:
comm, pid, ts, syscall = m_enter.groups()
stack[(pid, syscall)] = float(ts) * 1e6 # 秒->微秒
continue
m_exit = exit_re.match(line)
if m_exit:
comm, pid, ts, syscall = m_exit.groups()
key = (pid, syscall)
if key in stack:
elapsed = float(ts)*1e6 - stack.pop(key)
calls[syscall] += 1
time_us[syscall] += elapsed
total = sum(time_us.values())
if total == 0:
print("No syscall data")
sys.exit(0)
print(f"{'syscall':20} {'calls':>8} {'time(us)':>12} {'%':>6}")
for s, t in sorted(time_us.items(), key=lambda x: x[1], reverse=True):
print(f"{s:20} {calls[s]:8d} {t:12.3f} {t/total*100:6.2f}%")
浙公网安备 33010602011771号