perf introduction

perf原理与应用

Posted by icecube on January 16, 2024

简介

与Ftrace相反,Perf的监控范围主要限于单个进程。
因此Perf更适合分析特定程序的行为,比如代码的缓存友好性,或者每个函数中花费的时间。

Perf工具本身是构建在内核的perf_events子系统之上,该子系统实际上实现了跟踪、分析和采样功能。

Perf还可以利用Ftrace的架构来连接到跟踪点,类似于Ftrace和LTTng进行跟踪。

Perf_events内部使用一个环形缓冲区,可以映射到用户空间进行使用。
通过perf_event_open()系统调用,用户空间进程可以获得要测量的指标/计数器的文件描述符。
然后,文件描述符可以通过mmap()映射,并从用户空间进程的内存空间访问。

功能

perf功能
1. 跟踪系统调用(比strace快)
2. 采样不同语言的运行程序
3. 跟踪、计数几乎任何内核事件

perf list

事件类型
• Hardware Events: cpu性能监测计数器counter
• Software Events: 基于内核计数器的底层事件。例如 CPU migration,minor faults,major faults
• Kernel Tracepoint Events: 内核静态定义的插入点,开发人员编码到感兴趣的代码逻辑路径上
• User Statically-Defined Tracing: 用户态程序定义的插入点
• Dynamic Tracing: 动态跟踪。可以根据需要在任何允许的位置插入探针。内核态利用了kprobes机制,用户态利用uprobes
• Timed Profiling: 以指定的频率扫描收集信息(perf record -F hz)。主要用于cpu usage profiling。通过创建自定义的时间中断事件。

perf list命令可以罗列出所有perf支持跟踪记录的事件

  1. 软件事件都有默认的收集时间间隔。采样的时候只是收集到其中部分事件,而不是每一次都能记录下来。
    $ perf list | grep -i "software event"                                                                                  
      alignment-faults                                   [Software event]                                                               
      context-switches OR cs                             [Software event]                                                               
      cpu-clock                                          [Software event]                                                               
      cpu-migrations OR migrations                       [Software event]                                                               
      dummy                                              [Software event]                                                               
      emulation-faults                                   [Software event]                                                               
      major-faults                                       [Software event]                                                               
      minor-faults                                       [Software event]                                                               
      page-faults OR faults                              [Software event]                                                               
      task-clock                                         [Software event]
    
  2. 硬件事件(PMCs)
    Perfomance montoring couters 性能监测计数器,统计底层处理器的活动,比如cpu时钟周期
    PMCs典型的处理器实现方式是:在同一时间,只能纪录几个或者一少部分事件,尽管处理器可以跟踪上千个不同类型的事件。
    这是因为cpu上这些寄存器数量是固定有限的,只能编程为统计计数指定的几个事件。
    $ perf list | grep -i "hardware event"                                                                                  
      branch-instructions OR branches                    [Hardware event]                                                               
      branch-misses                                      [Hardware event]                                                               
      cache-misses                                       [Hardware event]                                                               
      cache-references                                   [Hardware event]                                                               
      cpu-cycles OR cycles                               [Hardware event]                                                               
      instructions                                       [Hardware event]                                                               
      stalled-cycles-backend OR idle-cycles-backend      [Hardware event]                                                               
      stalled-cycles-frontend OR idle-cycles-frontend    [Hardware event]        
    

perf top/record

当一个进程cpu使用率很高时,可以使用perf top -p pid

top的统计粒度是进程
perf top 的统计粒度是进程运行时调用到的函数,精确到每个函数cpu使用率,包括用户态和内核态的函数

perf top 是及时输出出来,perf record却是和perf top一样收集信息,但是是把信息保存到perf.data文件,供稍后分析

perf record是以采样的方式检查当前正在执行哪个函数,比如说频率可以是100 times/second
perf record
perf record COMMAND start COMMAND and profile it until it exits
perf record PID profile PID until you press CTRL+C
perf record -a profile all process until you press CTRL+C

perf record -p 8325 sleep 5 profile 8325 for 5 seconds

perf record也可以记录多种不同的事件events,这个时候不再是采样的方式,而是试图记录每一次事件。

  • system calls
  • sending network packets
  • reading from a block device(disk)
  • context switches/page faults
  • make any kernel function into an event(kprobes)

-g 指示收集调用栈 这样可以追踪到产生该事件的具体的代码位置
perf record -e syscalls:sys_enter_connect -ag

分析perf record data
perf report 交互式显示哪个函数调用次数最多
perf annotate 可以打印出进程执行时的热点汇编指令
perf script 以文本方式打印出所有采样数据,类似于火焰图

有时候perf记录的用户进程栈里夹杂着内核函数,这是正常的。
这意味着要么进程执行了系统调用或者产生了page fault,从而触发了相应的内核函数。

perf stat

要写一个高性能的程序,有许多需要关注的地方

  • cpu/hardware level events
  • page faults
  • TLB misses
  • cpu cycles
  • L1 cache hits/misses
  • instructions per cycle
  • branch prediction misses

perf stat 会带来很多开销,统计计数每一次进程触发的系统调用事件可能会使系统慢6倍以上

perf stat -e context-switches ls -R /              // count context-switches between the kernel and userspace  
perf stat -e 'syscalls:sys_enter_*' ls -R /        // count system calls  
perf stat -ddd ls      // -ddd d is for detailed

perf trace

strace好用,但是会使程序运行慢很多(10x slower)
perf trace跟踪系统调用开销很小,可以用在客户环境,但是perf trace也有两个缺点

  • 有时候会丢失syscalls事件(也算优点,限制了开销)
  • 不会显示读写的字符串

perf 工作原理

perf 分成两部分

  • 运行在用户态的 perf 程序
  • 响应 perf 命令的内核部分

内核负责进程调度,所以内核知道正在运行哪个进程,以及正在执行哪条指令(PC程序计数器)

当运行 perf record/perf stat/perf top命令时,实现步骤如下:

  1. perf 要求内核收集相应信息
  2. 内核根据perf要求采样获取samples/traces/cpu counters
  3. perf显示收集到的数据

有时候perf不能把指令地址转换为函数名称字符串,所以显示的就是地址数值

perf推算出运行的程序的步骤如下

  • 获取到程序指令指针地址
  • 获取到程序调用栈
  • 展开栈找到函数调用关系
  • 使用符号表把各个栈地址翻译成符号名称字符串
    如果二进制程序符号表被strip掉了,那perf是没办法给出函数名称字符串的,只能显示成地址数值

具体到代码实现

  1. perf调用perf_event_open系统调用
  2. 内核把事件信息写入用户态ringbuffer
  3. perf从ringbuffer读出信息并显示出来(或者存到perf.data)

ringbuffer就是内核分配的固定大小的环形缓冲区,每次写入一个记录record就会占用一部分内存。
因为缓冲区大小固定,所以写入的记录数量是受限的。当缓冲区被写满的时候,就会发生丢失,此时perf会有告警打印。

perf / bcc等工具都会使用到perf_event_open系统调用。
bcc(BCC_PERF_OUTPUT)利用该系统调用写出自己定制的profiling/trace events,按照自己的意愿收集并显示跟踪记录数据。

内核版本
perf和内核版本号深度绑定

  • 安装perf命令时需要匹配对应的内核版本
  • perf功能特性可能随着内核版本号而改变

注意事项
perf_events 和其它debug工具一样,也需要符号表,用于把内存地址映射成对应的变量名称字符串,方便开发人员。
没有符号表就只能看到十六进制数字地址.也自己编译软件,生成符号表。

使用perf命令需要时刻注意给系统带来的开销。这取决于指定跟踪的事件发生的频率,事件发生越频繁,系统开销越大,perf.data文件越大。

命令示例

-F 指定采用频率
-g 记录栈信息
-e 指定跟踪的事件
-a 跟踪整个系统
-p 指定进程pid

perf top -F 49  
perf top -ns comm,dso        
perf top -e raw_syscalls:sys_enter -ns comm -d 1       //统计系统调用次数,每一秒刷新一次  
stdbuf -oL perf top -e net:net_dev_xmit  -ns comm | strings     //统计进程发包次数  
perf stat COMMAND  
perf sat -ddd command     
perf stat -e cycles,instructions,cache-misses -a  
perf stat -e 'syscalls:sys_enter_*' -p pid  
perf stat -e 'block:*' -a sleep 10  
perf report  
perf report --stdio  
perf scirpt  
perf annotate [--stdio]  
perf trace            // trace syscalls system-wide  
perf trace -p pid     // trace syscalls for PID  
perf record -F 99 COMMAND  
perf record -p PID  
perf record -p PID sleep 10  
perf record -p PID -g -- sleep 10  
perf record -p PID --call-graph dwarf    // using DWARF to unwind stack  

perf record -e sched:sched_process_exec -a     // tracing new processes, until ctrl-c  
perf record -e context-switches -a             // tracing all context-switches, until ctrl-c  
perf record -e context-switches -ag -- sleep 10  
perf record -e page-faults -ag                 // tracing all page faults with stack traces,until ctrl-c  
// add a tracepoint for kernel function tcp_sendmsg(),and trace this newly created probe
perf probe 'tcp_sendmsg' && perf record -e -a probe:tcp_sendmsg     

// add a tracepoint for myfunc() return, and include the reval as a string
perf probe 'myfunc%return +0($retval):string'     

// trace and filter   (state is not TCP_ESTABLISHED(1)
perf probe 'tcp_sendmsg' && perf record -e -a probe:tcp_sendmsg --filter 'size > 0 && skc_state != 1' -a     

// add a tracepoint for do_sys_open() with the filename as a string  
perf probe 'do_sys_open filename:string'           

参考

https://wizardzines.com/zines/perf/
https://www.brendangregg.com/perf.html