今天没有代码,需要捋一捋 pppof 采样过程的笔记,便于之后灵活运用,因为可统计的指标有很多。
pprof 采样过程和原理
CPU
对于 CPU 上面的性能讨论,主要是函数调用和其占用时间。采样率设置为每秒 100 次,固定死,然后手动启动采样,一段时间以后手动结束。
手动开始的流程大概是:
flowchart LR
开始采样 --> 设定信号处理函数 --> 开启定时器
手动结束刚好相反:
flowchart LR
停止采样 --> 取消信号处理函数 --> 关闭定时器
采样时(进程开启定时器和关闭定时器之间)操作系统每 10 ms 向进程发送一次 SIGPROF 信号,进程每次接收到 SIGPROF 就记录调用堆栈,写缓冲每 100 ms 读取已经记录的调用栈并写入输出流。
Heap 堆内存
性能指标不止一种,采样程序通过内存分配器在堆上分配和释放的内存,记录分配或释放的大小和数量。采样率设置为每分配 512 KB 记录一次,可以在运行开头修改,设置上 1 表示每次分配都记录。采样时间的计算是从程序运行开始到采样时。采样的指标有 alloc_space,alloc_objects,inuse_space,inuse_objects。计算方式为 inuse_ = alloc_ - free_
Goroutine 协程和 ThreadCreate 线程创建
这是另一套指标。对于 Goroutine:记录所有用户发起且在运行中的 goroutine(函数入口非 runtime 开头的)runtime.main 的调用栈信息
flowchart LR
n1[Stop The World] --> n2[遍历 allg 切片] --> n3[输出创建 g 的堆栈] --> n4[Start The World]
对于 ThreadCreate:记录程序创建的所有系统线程的信息。
flowchart LR
n1[Stop The World] --> n2[遍历 allm 切片] --> n3[输出创建 m 的堆栈] --> n4[Start The World]
Block 阻塞和 Mutex 锁
对于阻塞操作,采样阻塞操作的次数和耗时,采样率设置为阻塞耗时超过阈值记录一次,设置上 1 表示每次阻塞均记录。
flowchart TD
n1[阻塞操作] -- 上报调用栈和消耗时间 --> n2[Profiler] -- 采样 --> n4[遍历阻塞记录] --> n5[统计阻塞次数和耗时]
n2 --> n3[时间未到阈值则丢弃]
对于锁竞争,采样争抢锁的次数和耗时,采样率设置为只记录固定比例的锁操作,设置上 1 表示每次加锁均记录。
flowchart TD
n1[锁竞争操作] -- 上报调用栈和消耗时间 --> n2[Profiler] -- 采样 --> n4[遍历锁记录] --> n5[统计锁竞争次数和耗时]
n2 --> n3[比例未命中则丢弃]