strace可以跟踪到一个进程产生的系统调用,包括参数,返回值,执行消耗的时间。
要跟踪的Taskdemo.php代码如下(即之前使用swoole实现的生产者消费者模型)。
require('./Schedule.php');
class Taskdemo extends Schedule{
protected $_consumerNum = 1;
protected function doProduce($worker){
$all = 5;
for($i=0; $i<$all; $i+=1){
yield json_encode(array('data'=>$i));
}
}
protected function doConsume($data, $worker){
sleep(1);
echo "consumer:{$worker->pid} recv {$data}\n";
}
}
$t = new Taskdemo();
$t->run();
执行如下命令,开始跟踪
strace -ff -o task php Taskdemo.php
执行后我们得到三个文件
task.28203 task.28204 task.28205
熟悉代码的同学应该可以猜到,这三个文件分别对应主进程,生产者子进程和消费者子进程。下面我们分别来看下。
- task.28203(主进程,通常来说进程号最小的文件就是主进程对应的文件)
/*生成生产者和消费者进程各一个*/
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x2b6ea214c810) = 28204
clone(child_stack=0, clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x2b6ea214c810) = 28205
write(1, "msgqkey:1053566\n", 16) = 16
/*等待并回收子进程*/
epoll_wait(7, 3841680, 4096, 4294967295) = -1 EINTR (Interrupted system call)
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG, NULL) = 28204
write(1, "master clear pid:28204, code:0\n", 31) = 31
epoll_wait(7, 3841680, 4096, 4294967295) = -1 EINTR (Interrupted system call)
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG, NULL) = 28205
write(1, "master clear pid:28205, code:0\n", 31) = 31
/*从消息队列中取数据,输出*/
msgrcv(7176192, 7176192{2, "{\"data\":0}\0\0\0\0\0\0R7\247r8\0\0\0HJ\325r8\0\0\0"...}, 8192, 0, 0) = 10
write(1, "consumer:28204 recv {\"data\":0}\n", 31) = 31
msgrcv(7176192, 7176192{2, "{\"data\":1}\0\0\0\0\0\0R7\247r8\0\0\0HJ\325r8\0\0\0"...}, 8192, 0, 0) = 10
write(1, "consumer:28204 recv {\"data\":1}\n", 31) = 31
msgrcv(7176192, 7176192{2, "{\"data\":2}\0\0\0\0\0\0R7\247r8\0\0\0HJ\325r8\0\0\0"...}, 8192, 0, 0) = 10
write(1, "consumer:28204 recv {\"data\":2}\n", 31) = 31
msgrcv(7176192, 7176192{2, "{\"data\":3}\0\0\0\0\0\0R7\247r8\0\0\0HJ\325r8\0\0\0"...}, 8192, 0, 0) = 10
write(1, "consumer:28204 recv {\"data\":3}\n", 31) = 31
msgrcv(7176192, 7176192{2, "{\"data\":4}\0\0\0\0\0\0R7\247r8\0\0\0HJ\325r8\0\0\0"...}, 8192, 0, 0) = 10
write(1, "consumer:28204 recv {\"data\":4}\n", 31) = 31
msgrcv(7176192, 7176192{1, "ALLDONE:4}\0\0\0\0\0\0R7\247r8\0\0\0HJ\325r8\0\0\0"...}, 8192, 0, 0) = 7
write(1, "consumer 28204 exit\n", 20) = 20
write(1, "producer begin:\n", 16) = 16
/*向队列中放入任务*/
msgsnd(7176192, {2, "{\"data\":0}"}, 10, 0) = 0
msgsnd(7176192, {2, "{\"data\":1}"}, 10, 0) = 0
msgsnd(7176192, {2, "{\"data\":2}"}, 10, 0) = 0
msgsnd(7176192, {2, "{\"data\":3}"}, 10, 0) = 0
msgsnd(7176192, {2, "{\"data\":4}"}, 10, 0) = 0
/*放入完成标识*/
msgsnd(7176192, {1, "ALLDONE"}, 7, 0) = 0
/*标签队列长度*/
msgctl(7176192, IPC_STAT, 0x7fffd6dbedb0) = 0
/*删除队列*/
msgctl(7176192, IPC_RMID, 0) = 0
统计每种系统调用所执行的时间,调用次数,出错次数。
strace -c php Taskdemo.php
我们执行上面的命令,看下主进程进行的系统调用。
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
59.06 0.000857 429 2 clone
10.34 0.000150 1 153 mmap
6.20 0.000090 1 109 42 open
3.72 0.000054 1 78 fstat
3.72 0.000054 1 62 mprotect
3.58 0.000052 2 33 27 stat
3.51 0.000051 1 74 close
3.45 0.000050 1 66 read
2.14 0.000031 1 26 brk
1.79 0.000026 7 4 1 wait4
... ...
0.00 0.000000 0 1 epoll_create
0.00 0.000000 0 2 2 epoll_wait
------ ----------- ----------- --------- --------- ----------------
100.00 0.001451 754 82 total
各项含义如下:
- % time:执行耗时占总时间百分比
- seconds:执行总时间
- usecs/call:单个命令执行时间
- calls:调用次数
- errors: 出错次数
- syscall: 系统调用
说明:
- clone是主进程生成子进程时的系统调用。
- epoll_create, epoll_wait,wait4用于创建信号处理函数,回收僵尸子进程。