perf record 可捕获 Workerman 的内核系统调用栈,需以 root 或 perf_event_paranoid≤2 运行,跟进主/worker 进程,使用 -e 指定 syscalls 并加 --call-graph dwarf 查看内核栈;PHP 函数名不可见因解释执行无 ELF 符号,应聚焦 epoll_wait、accept4 等内核 I/O 行为分析。

perf record 怎么抓 Workerman 的内核函数调用栈?
Workerman 是 PHP 进程模型,本身不直接进入内核,但它的网络 I/O(如 epoll_wait、accept4、sendto)和内存操作(如 mmap、brk)都会触发系统调用。要捕获这些,必须让 perf record 跟进 Workerman 主进程及其子进程(尤其是 worker 进程),且需启用内核符号(/proc/kallsyms 可读)和调试信息。
- 必须以 root 或
perf_event_paranoid≤ 2 运行:echo 1 | sudo tee /proc/sys/kernel/perf_event_paranoid
- 启动 Workerman 后,用
ps aux | grep workerman找到主进程 PID(通常是 master)和至少一个 worker PID - 抓内核函数调用,重点加
-e syscalls:sys<em>enter</em>*或更轻量的-e 'syscalls:sys_enter_accept4,syscalls:sys_enter_epoll_wait,syscalls:sys_enter_read' - 若想看内核栈(比如谁在调
tcp_v4_do_rcv),得加--call-graph dwarf并确保内核有vmlinux或debuginfo包已安装
perf script 输出里为什么看不到 PHP 函数名,只有 [unknown] 或 [kernel.kallsyms]?
perf record 默认只采集内核和用户态指令指针(IP),PHP 是解释执行,没有标准 ELF 符号表,perf 无法自动解析 Zend VM 的执行帧。你看到的 [unknown] 很可能就是 PHP 的 execute_ex 或 zend_execute 入口,但没符号就显示不出来。
- 解决办法不是强行加 PHP 符号(成本高、不稳定),而是聚焦「内核侧可观测性」:确认
epoll_wait是否长时阻塞、accept4调用频次是否异常、是否有大量syscalls:sys_exit_sendto返回 -EAGAIN - 若真需要关联 PHP 行号,得配合
php -d 'xdebug.mode=profile' -d 'xdebug.start_with_request=trigger'单独采样,不要混进perf流程 - 注意
perf script默认输出是 raw 格式,加-F comm,pid,tid,cpu,time,ip,sym,dso才能看清调用来源模块
用 perf report 看内核函数热点时,哪些指标最值得盯?
perf report 默认按采样次数排序,但对 Workerman 这类高并发 I/O 服务,光看“谁被采到最多”容易误判。真正关键的是:
-
epoll_wait的平均等待时间(结合perf script时间戳算 delta)——若常 >10ms,说明事件循环空转或 fd 数量超限 -
accept4调用后紧接setsockopt和fcntl的 pattern 是否密集——反映连接建立开销是否被放大 - 出现大量
__do_softirq或net_rx_action样本——说明网卡软中断处理积压,可能和 Workerman 处理太慢有关,而非它自身问题 -
copy_to_user/copy_from_user占比突增——暗示应用层频繁小包收发,或 buffer 未对齐导致额外拷贝
perf probe 加自定义点会不会干扰 Workerman 稳定性?
可以加,但必须避开 PHP 运行时关键路径。Workerman 基于 stream_select 或 event 扩展,底层仍是 libc 的 epoll_ctl 和系统调用。用 perf probe 在 libc 或内核函数上打点是安全的,比如:
perf probe -x /lib/x86_64-linux-gnu/libc.so.6 'accept4 ret=$retval'perf probe 'kernel:sys_epoll_wait fd=%ax maxevents=%dx timeout=%dx'
但绝对不要 probe zend_execute、zif_socket_accept 这类 PHP 内部函数——它们没稳定 ABI,版本一升级 probe 就失效,还可能因 kprobe 插桩引发偶发 crash。
实际中,95% 的 Workerman 性能瓶颈都落在内核 I/O 路径上,把 epoll_wait 的阻塞分布、tcp_sendmsg 的重传率、sock_alloc 的分配延迟摸清楚,比试图追踪 PHP 字节码要实在得多。



















