什么是strace?
strace是一個(gè)非常簡(jiǎn)單的工具,它可以跟蹤系統(tǒng)調(diào)用的執(zhí)行。最簡(jiǎn)單的方式,它可以從頭到尾跟蹤binary的執(zhí)行,然后以一行文本輸出系統(tǒng)調(diào)用的名字,參數(shù)和返回值。
其實(shí)它可以做的更多:
可以對(duì)特定的系統(tǒng)調(diào)用或者幾組系統(tǒng)調(diào)用進(jìn)行過濾
可以通過統(tǒng)計(jì)特定系統(tǒng)調(diào)用的調(diào)用次數(shù)、耗費(fèi)的時(shí)間、成功和失敗的次數(shù)來配置(profile)系統(tǒng)調(diào)用的使用 I
跟蹤發(fā)送給進(jìn)程的信號(hào)量
可以通過pid附著(attach)到任何運(yùn)行的進(jìn)程
如果你使用的是其它Unix系統(tǒng),它類似于"truss"。其它更復(fù)雜的是Sun的Dtrace.
怎么使用它
1) 找出程序在startup的時(shí)候讀取的哪個(gè)config文件?
有沒有嘗過解決為什么某些程序不讀去你認(rèn)為它應(yīng)該讀取的config文件的問題?
$ strace php 2>&1 | grep php.ini open("/usr/local/bin/php.ini", O_RDONLY) = -1 ENOENT (No such file or directory) open("/usr/local/lib/php.ini", O_RDONLY) = 4 lstat64("/usr/local/lib/php.ini", {st_mode=S_IFLNK|0777, st_size=27, ...}) = 0 readlink("/usr/local/lib/php.ini", "/usr/local/Zend/etc/php.ini", 4096) = 27 lstat64("/usr/local/Zend/etc/php.ini", {st_mode=S_IFREG|0664, st_size=40971, ...}) = 0
可以看出這個(gè)版本的PHP從/usr/local/lib/php.init讀取config文件(但是先嘗試/usr/locl/bin)
如果只關(guān)心特定的系統(tǒng)調(diào)用,有更精致的方法
$ strace -e open php 2>&1 | grep php.ini open("/usr/local/bin/php.ini", O_RDONLY) = -1 ENOENT (No such file or directory) open("/usr/local/lib/php.ini", O_RDONLY) = 4
相同的方法適用于很多其它類似的問題。比如說,安裝了不同版本的library,不確定實(shí)際上加載了哪一個(gè)版本。
-e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...
options: trace, abbrev, verbose, raw, signal, read, write
2) 為什么這個(gè)程序沒有打開我的文件?
是否曾經(jīng)碰到過一個(gè)程序拒絕讀取它沒有權(quán)限的文件,但是你發(fā)誓原因是它沒有真正找到那個(gè)文件?對(duì)程序跟蹤open,access調(diào)用,注意失敗的情況
$ strace -e open,access 2>&1 | grep your-filename
3) 某個(gè)進(jìn)程現(xiàn)在在做什么?
某個(gè)進(jìn)程突然占用了很多CPU? 或者某個(gè)進(jìn)程看起來像hanging了?
找到對(duì)應(yīng)的pid,然后
hang:
懸掛,掛起的意思
就是一個(gè)進(jìn)程被暫時(shí)停止執(zhí)行.
root@dev:~# strace -p 15427 Process 15427 attached - interrupt to quit futex(0x402f4900, FUTEX_WAIT, 2, NULL Process15427detached
嗯,這個(gè)例子里面,它在調(diào)用futex()的時(shí)候掛起了。
"strace -p"非常有用,它減少了很多猜測(cè)工作,也不需要重新啟動(dòng)應(yīng)用。
-p pid -- trace process with process id PID, may be repeated
4) 是誰偷走了時(shí)間?
你可以重新編譯app,打開profiling,以獲取精確的信息。但是通常利用strace附著(attach)一個(gè)進(jìn)程以快速地看一下當(dāng)前時(shí)間花費(fèi)在哪里非常有用。可以看下是否90%的CPU用在真正的工作,或者用在其它方面了。
root@dev:~# strace -c -p 11084 Process 11084 attached - interrupt to quit Process 11084 detached % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 94.59 0.001014 48 21 select 2.89 0.000031 1 21 getppid 2.52 0.000027 1 21 time ------ ----------- ----------- --------- --------- ---------------- 100.00 0.001072 63 total root@dev:~#
-c -- count time, calls, and errors for each syscall and report summary
-C -- like -c but also print regular output
在執(zhí)行strace -c -p命令以后,等到你關(guān)注的時(shí)間到了后,按ctrl-c退出,strace會(huì)列出如上的profiling數(shù)據(jù)。
在這個(gè)例子中,程序花了絕大部分時(shí)間在等待select()。它在每一個(gè)slect()調(diào)用這件調(diào)用getpid()和time(),這是一種典型的事件循環(huán)。
你也可以運(yùn)行"start to finish",這里是"ls"
root@dev:~# strace -c >/dev/null ls % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 23.62 0.000205 103 2 getdents64 18.78 0.000163 15 11 1 open 15.09 0.000131 19 7 read 12.79 0.000111 7 16 old_mmap 7.03 0.000061 6 11 close 4.84 0.000042 11 4 munmap 4.84 0.000042 11 4 mmap2 4.03 0.000035 6 6 6 access 3.80 0.000033 3 11 fstat64 1.38 0.000012 3 4 brk 0.92 0.000008 3 3 3 ioctl 0.69 0.000006 6 1 uname 0.58 0.000005 5 1 set_thread_area 0.35 0.000003 3 1 write 0.35 0.000003 3 1 rt_sigaction 0.35 0.000003 3 1 fcntl64 0.23 0.000002 2 1 getrlimit 0.23 0.000002 2 1 set_tid_address 0.12 0.000001 1 1 rt_sigprocmask ------ ----------- ----------- --------- --------- ---------------- 100.00 0.000868 87 10 total
正如你的預(yù)期,它耗費(fèi)了大部分時(shí)間在兩次調(diào)用來讀取目錄條目上(因?yàn)檫\(yùn)行于一個(gè)小的目錄上,所有只有兩次)
5) 為什么 無法連接到服務(wù)器?
調(diào)試進(jìn)程無法連接到遠(yuǎn)端服務(wù)器有時(shí)候是件非常頭痛的事。DNS會(huì)失敗,connect會(huì)掛起,server有可能返回一些意料之外的數(shù)據(jù)。
可以使用tcpdump來分析這些情況,它是一個(gè)非常棒的工作。但是有時(shí)候你strace可以給你更簡(jiǎn)單,耿直借的角度,因?yàn)閟trace只返回你的進(jìn)程相關(guān)的系統(tǒng)調(diào)用產(chǎn)生的數(shù)據(jù)。
如果你要從100個(gè)連接到統(tǒng)一個(gè)數(shù)據(jù)服務(wù)器的運(yùn)行進(jìn)程里面找出一個(gè)連接所做的事情,用strace就比tcpdump簡(jiǎn)單得多。
下面是跟蹤"nc"連接到www.news.com 80端口的例子
$ strace -e poll,select,connect,recvfrom,sendto nc www.news.com 80 sendto(3, "24