strace 用法介绍
创始人
2024-05-31 11:34:18
0

strace 是什么

strace 是一个可用于诊断和调试的 Linux 用户空间跟踪器。我们用它来监控用户空间进程和内核的交互,比如系统调用、信号传递、进程状态变更等。

strace 作为一种动态跟踪工具,能够帮助我们高效地定位进程和服务故障。它像是一个侦探,打开应用进程的这个黑盒子,通过系统调用的蛛丝马迹,告诉你进程大概在干嘛,进而找到异常的真相。

strace 怎么用

运行模式

strace 有两种运行模式。

一种是通过它启动要跟踪的进程。用法很简单,在原本的命令前加上 strace 即可。

比如我们要跟踪 “/usr/local/bin/a.out” 这个命令的执行,可以这样:

strace /usr/local/bin/a.out

另外一种运行模式,是跟踪已经在运行的进程,在不中断进程执行的情况下,理解它在干嘛。

这种情况,给 strace 传递个 -p pid 选项即可。

比如,a.out 进程的 pid 是 345,可以这样:

strace -p 345

完成跟踪时,按 Ctrl + C 结束 strace 即可。

常用选项

从一个示例命令来看:

strace -tt -T -v -f -e trace=file -o /tmp/strace.log -s 1024 -p 345
  • -tt:在每行输出的前面,显示毫秒级别的时间
  • -T:显示每次系统调用所花费的时间
  • -v:对于某些相关调用,把完整的环境变量,文件 stat 结构等打出来
  • -f:跟踪目标进程,以及目标进程创建的所有子进程
  • -e:控制要跟踪的事件和跟踪行为,比如指定要跟踪的系统调用名称
  • -o:把 strace 的输出单独写到指定的文件
  • -s:当系统调用的某个参数是字符串时,最多输出指定长度的内容,默认是 32 个字节
  • -p:指定要跟踪的进程 pid,要同时跟踪多个 pid,重复多次 -p 选项即可
  • -c:统计系统调用的次数和其所花的时间

这里特别说下 strace 的 -e trace 选项。

要跟踪某个具体的系统调用,如 -e trace=open 即可。

但有时候我们要跟踪一类系统调用,比如所有和文件名有关的调用、所有和内存分配有关的调用。

如果人工输入每一个具体的系统调用名称,可能容易遗漏。

于是 strace 提供了几类常用的系统调用组合名字。

  • -e trace=file 跟踪和文件访问相关的调用(参数中有文件名)
  • -e trace=process 和进程管理相关的调用,比如 fork/exec/exit_group
  • -e trace=network 和网络通信相关的调用,比如 socket/sendto/connect
  • -e trace=signal 信号发送和处理相关,比如 kill/sigaction
  • -e trace=desc 和文件描述符相关,比如 write/read/select/epoll
  • -e trace=ipc 进程间通信相关,比如 shmget

strace 问题定位案例

定位进程异常退出

/usr/local/samba/bin/nmbd 启动失败,nmbd 是一个域名服务的进程。

这个服务进程是开源代码编译出来的,也就是说,并不是我们自己开发的代码,因此该服务进程的启动流程我们并不熟悉。像这样的情况,可以用 strace 来跟踪看看,到底是哪里出现了异常。

strace -tt -T /usr/local/samba/bin/nmbd

在这里插入图片描述

咦?看到 nmbd 进程 exited with 0 正常退出了,考虑到这个进程是个守护进程,主进程确实会 exit 的。

再看到有个 clone 的系统调用,想到 fork 这个系统调用最终调用的是 clone,就知道 nmbd 进程创建了一个子进程,然后父进程就退出了。所以要加一个参数 -f 来跟踪子进程

strace -tt -T -f /usr/local/samba/bin/nmbd

在这里插入图片描述

看到确实子进程是异常退出了,exited with 1,所以 nmbd 进程启动失败。

对比了一下之前版本 OK 的启动 log。

在这里插入图片描述

发现 /usr/local/samba/var/nmbd 这个目录有异常

OK 时是一个普通的目录

NG 时是一个软链接

最终查看了相关代码,改成目录,nmbd 进程就可以正常启动了

性能分析

假如有个需求,统计某个目录 cpp 文件的代码行数。这里提供两个 Shell 脚本实现:

poor_script.sh

#!/bin/bash
total_line=0
while read filename; doline=$(wc -l $filename | awk '{print $1}')(( total_line += line ))
done < <(find . -type f -iname '*.cpp')
echo "total line: $total_line"

good_script.sh

#!/bin/bashfind . -type f -iname '*.cpp' -print0 | wc -l --files0-from=- | tail -n 1

两段代码实现的目的是一样的。我们通过 strace 的 -c 选项来分别统计两种版本的系统调用情况和其所花的时间(使用 -f 同时统计子进程的情况)

strace -c -f ./poor_script.sh
在这里插入图片描述

strace -c -f ./good_script.sh
在这里插入图片描述

从两个输出可以看出,good_script.sh 很快就可以得到结果:95985 行。它大部分的调用(calls)开销是文件操作(read/open/write/close)等,统计代码行数本来就是干这些事情。

而 poor_script.sh 完成同样的任务则花了更久的时间。它大部分的调用开销都在进程和内存管理上(wait4/mmap/getpid…)。

实际上,从两个图中 clone 系统调用的次数,我们可以看出 good_script.sh 只需要启动 3 个进程,而 poor_script.sh 完成整个任务居然启动了 392 个进程,而进程创建和销毁的代价是相当高的,性能不差才怪。如果目录下的 cpp 文件再多一些,那要花费的时间将会更久!

总结

当发现进程或服务异常时,我们可以通过 strace 来跟踪其系统调用,“看看它在干啥”,进而找到异常的原因。熟悉常用系统调用,能够更好地理解和使用 strace。

当然,strace 也不是万能的,当目标进程卡死在用户态时,strace 就没有输出了。

这个时候我们需要其他的跟踪手段,比如 gdb 等。

相关内容

热门资讯

修复 爱普生 EPSON L4... L4151 L4153 L4156 L4158 L4163 L4165 L4166 L4168 L4...
【PdgCntEditor】解... 一、问题背景 大部分的图书对应的PDF,目录中的页码并非PDF中直接索引的页码...
监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
【前端】‘??‘与‘||‘有什... 0 问题 经常写const data = res.data.a ?? ''或者const d...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
牛客计算器的改良(Python... 文章目录1.题目描述2.输入描述:3.输出描述:4.示例15.分析6.代码7.结语 链接࿱...
正大杯|市调大赛|2023备赛... 关键信息 同时随着精细化养宠趋势的深入,宠物消费类目日渐丰富。 本报告通过 Niuco...
QGIS下载在线地图(Goog... 前言 国内外有很多在线地图下载软件,但功能单一,基本上只能下载数据&#x...