4. strace 常用选项详解:-c、-e、-p、-o、-f、-t、-T 等核心选项的功能与使用
strace 的强大之处在于其丰富的选项体系,能够精确控制跟踪的范围、输出格式与统计维度。掌握这些核心选项,是高效定位性能瓶颈的基础。本章将逐一剖析最常用的七个选项,并结合实战场景说明其适用条件。
4.1 -c:统计汇总模式
功能:跟踪结束后输出每个系统调用的调用次数、总耗时、平均耗时、错误次数等统计信息,而非逐行输出调用详情。
适用场景:快速评估程序整体系统调用开销分布,定位高频或高耗时调用。
示例:统计 ls 命令的系统调用分布
$ strace -c ls /tmp
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
30.12 0.000412 34 12 newfstatat
22.45 0.000307 19 16 getdents64
18.36 0.000251 31 8 write
10.08 0.000138 17 8 close
8.92 0.000122 15 8 openat
5.67 0.000078 13 6 mmap
4.40 0.000060 12 5 fstat
------ ----------- ----------- --------- --------- ----------------
100.00 0.001368 63 total
输出字段解读:
| 字段 | 含义 | 分析价值 |
|---|---|---|
| % time | 该调用耗时占总耗时的百分比 | 快速定位热点调用 |
| seconds | 该调用累计耗时(秒) | 量化绝对开销 |
| usecs/call | 每次调用的平均微秒数 | 判断单次调用是否异常 |
| calls | 调用次数 | 识别高频调用 |
| errors | 错误次数 | 发现潜在故障 |
实战技巧:当 % time 集中在少数几个系统调用上时,说明性能瓶颈很可能就在这些调用中。例如 write 占比过高,可能意味着 I/O 写入是瓶颈。
4.2 -e:过滤表达式
功能:通过表达式精确控制跟踪哪些系统调用或事件,大幅减少输出噪音。
常用表达式格式:
| 表达式 | 含义 | 示例 |
|---|---|---|
trace=syscall_set | 跟踪指定的一组系统调用 | -e trace=open,read,write |
trace=file | 跟踪所有文件操作相关调用 | -e trace=file |
trace=network | 跟踪所有网络相关调用 | -e trace=network |
trace=process | 跟踪进程管理相关调用 | -e trace=process |
trace=signal | 跟踪信号相关调用 | -e trace=signal |
trace=ipc | 跟踪进程间通信调用 | -e trace=ipc |
read=fd | 显示指定文件描述符的读取内容 | -e read=3 |
write=fd | 显示指定文件描述符的写入内容 | -e write=2 |
示例:仅跟踪文件打开和读取操作
$ strace -e trace=open,openat,read cat /etc/hostname
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/etc/hostname", O_RDONLY) = 3
read(3, "my-server\n", 4096) = 10
+++ exited with 0 +++
注意:-e trace=file 是一个便捷分类,包含 open、stat、read、write 等数十个文件相关调用。如果只想看某几个调用,务必使用逗号分隔的精确列表,避免输出过多无用信息。
4.3 -p:附加到指定进程
功能:跟踪一个已经运行的进程,而不是启动一个新程序。可以同时附加多个进程。
适用场景:线上服务进程出现异常或性能抖动时,无需重启即可动态跟踪。
示例:跟踪 PID 为 1234 的进程
$ strace -p 1234
strace: Process 1234 attached
restart_syscall(<... resuming interrupted call ...>) = 0
epoll_wait(5, [], 64, 1000) = 0
epoll_wait(5, [], 64, 1000) = 0
...(持续输出)
多进程附加:
$ strace -p 1234 -p 5678 -p 9012
实战技巧:线上跟踪时建议配合 -o 将输出写入文件,避免终端输出影响进程性能。同时使用 -f 跟踪子进程,捕获完整调用链。
4.4 -o:输出到文件
功能:将跟踪结果写入指定文件,而非标准错误输出(stderr)。
适用场景:跟踪输出量巨大时,便于后续分析;避免终端滚动影响操作。
示例:将跟踪结果保存到文件
$ strace -o /tmp/strace.log -e trace=network curl https://example.com
$ wc -l /tmp/strace.log
245 /tmp/strace.log
与 -ff 组合使用:当同时使用 -f 跟踪子进程时,-o 可以配合 -ff 为每个进程生成独立文件。
$ strace -o /tmp/strace -ff -e trace=file make -j4
$ ls /tmp/strace*
/tmp/strace.12345 /tmp/strace.12346 /tmp/strace.12347 /tmp/strace.12348
4.5 -f:跟踪子进程
功能:跟踪由当前进程通过 fork、vfork、clone 等系统调用创建的子进程。
适用场景:多进程架构的服务(如 Nginx、Apache)、使用 fork 的脚本、Make 构建系统等。
示例:跟踪 bash 及其子进程
$ strace -f -e trace=execve bash -c "echo hello; ls"
execve("/usr/bin/bash", ["bash", "-c", "echo hello; ls"], ...) = 0
strace: Process 23456 attached
[pid 23456] execve("/usr/bin/echo", ["echo", "hello"], ...) = 0
hello
[pid 23456] +++ exited with 0 +++
strace: Process 23457 attached
[pid 23457] execve("/usr/bin/ls", ["ls"], ...) = 0
...(ls 输出)
注意:-f 会大幅增加输出量,建议配合 -e 过滤和 -o 输出到文件使用,避免终端被淹没。
4.6 -t:时间戳
功能:在每行系统调用输出前添加时间戳,精确到秒或微秒。
三种变体:
| 选项 | 时间格式 | 示例输出 |
|---|---|---|
-t | 时:分:秒 | 14:23:45 openat(...) = 3 |
-tt | 时:分:秒.微秒 | 14:23:45.123456 openat(...) = 3 |
-ttt | Unix 时间戳.微秒 | 1698765425.123456 openat(...) = 3 |
示例:使用微秒级时间戳分析调用时序
$ strace -tt -e trace=read,write cat /etc/hostname
14:23:45.123456 read(3, "my-server\n", 4096) = 10
14:23:45.123789 write(1, "my-server\n", 10) = 10
14:23:45.123912 read(3, "", 4096) = 0
分析价值:通过时间戳可以计算两次调用之间的时间间隔,识别出程序在何处发生了长时间等待(如网络 I/O、锁等待)。
4.7 -T:显示系统调用耗时
功能:在每行系统调用输出的末尾,以尖括号形式显示该次调用的耗时(微秒)。
适用场景:精确测量每个系统调用的执行时间,定位单次调用中的性能异常。
示例:显示每次系统调用的耗时
$ strace -T -e trace=read,write cat /etc/hostname
read(3, "my-server\n", 4096) = 10 <0.000012>
write(1, "my-server\n", 10) = 10 <0.000025>
read(3, "", 4096) = 0 <0.000008>
实战技巧:将 -T 与 -tt 组合使用,可以同时获得绝对时间点和单次调用耗时,是定位慢调用的黄金组合。
$ strace -tt -T -e trace=read,write cat /etc/hostname
14:23:45.123456 read(3, "my-server\n", 4096) = 10 <0.000012>
14:23:45.123789 write(1, "my-server\n", 10) = 10 <0.000025>
4.8 选项组合实战案例
以下是一个综合使用多个选项定位性能瓶颈的典型场景:
案例:分析 Nginx worker 进程的 I/O 行为
# 1. 先使用 -c 快速评估整体开销分布
$ strace -c -p $(pgrep -n nginx)
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
45.23 0.892134 23 38792 epoll_wait
22.15 0.436789 12 36399 writev
18.67 0.368234 15 24556 recvfrom
8.92 0.176001 8 22001 accept4
5.03 0.099234 5 19876 close
------ ----------- ----------- --------- --------- ----------------
100.00 1.972234 141624 total
# 2. 发现 epoll_wait 耗时最高,进一步跟踪详细调用
$ strace -tt -T -e trace=epoll_wait -p $(pgrep -n nginx) -o /tmp/nginx_epoll.log
# 3. 分析日志中耗时超过 100ms 的 epoll_wait 调用
$ awk -F'[<>]' '{if ($2 > 100000) print}' /tmp/nginx_epoll.log
14:23:45.123456 epoll_wait(5, [], 64, 5000) = 1 <0.234567>
14:23:48.456789 epoll_wait(5, [], 64, 5000) = 1 <0.345678>
分析结论:epoll_wait 耗时超过 100ms 说明事件等待时间较长,可能原因是后端服务响应慢或连接池不足。结合 -e trace=recvfrom 进一步分析网络接收延迟,可以精确定位瓶颈点。
4.9 选项速查表
| 选项 | 功能 | 常用组合 | 性能影响 |
|---|---|---|---|
-c | 统计汇总模式 | -c -p PID | 低(仅汇总) |
-e | 过滤系统调用 | -e trace=file,network | 低(减少输出) |
-p | 附加到运行进程 | -p PID1 -p PID2 | 中 |
-o | 输出到文件 | -o /tmp/log | 低 |
-f | 跟踪子进程 | -f -o /tmp/log | 高(输出量大) |
-t/-tt/-ttt | 添加时间戳 | -tt -T | 低 |
-T | 显示调用耗时 | -T -e trace=read | 低 |
最佳实践总结:
- 快速定位热点:
strace -c -p PID→ 根据 %time 确定瓶颈调用 - 深入分析单类调用:
strace -e trace=瓶颈调用 -tt -T -p PID -o log - 多进程服务:
strace -f -e trace=file -o /tmp/log ./app - 线上安全跟踪:始终使用
-o写入文件,避免终端 I/O 干扰