perf pprof

常用的数据采样工具包括 linux perf、golang pprof 等

perf是一款Linux性能分析工具。Linux性能计数器是一个新的基于内核的子系统,它提供一个性能分析框架,比如硬件(CPU、PMU(Performance Monitoring Unit))功能和软件(软件计数器、tracepoint)功能。
通过perf,应用程序可以利用PMU、tracepoint和内核中的计数器来进行性能统计。它不但可以分析制定应用程序的性能问题(per thread),也可以用来分析内核的性能问题,当然也可以同事分析应用程序和内核,从而全面理解应用程序中的性能瓶颈。



使用perf,可以分析程序运行期间发生的硬件事件,比如instructions retired、processor clock cycles等;也可以分析软件时间,比如page fault和进程切换。
perf是一款综合性分析工具,大到系统全局性性能,再小到进程线程级别,甚至到函数及汇编级别。




  1. 背景知识
    1.1 tracepoints
    tracepoints是散落在内核源码中的一些hook,它们可以在特定的代码被执行到时触发,这一特定可以被各种trace/debug工具所使用。
    perf将tracepoint产生的时间记录下来,生成报告,通过分析这些报告,条有人缘便可以了解程序运行期间内核的各种细节,对性能症状做出准确的诊断。
    这些tracepint的对应的sysfs节点在/sys/kernel/debug/tracing/events目录下。
    1.2 硬件特性之cache
    内存读写是很快的,但是还是无法和处理器指令执行速度相比。为了从内存中读取指令和数据,处理器需要等待,用处理器时间来衡量,这种等待非常漫长。cache是一种SRAM,读写速度非常快,能和处理器相匹配。因此将常用的数据保存在cache中,处理器便无需等待,从而提高性能。cache的尺寸一般都很小,充分利用cache是软件调优非常重要部分。

  2. 主要关注点
    基于性能分析,可以进行算法优化(空间复杂度和时间复杂度权衡)、代码优化(提高执行速度、减少内存占用)。
    评估程序对硬件资源的使用情况,例如各级cache的访问次数、各级cache的丢失次数、流水线停顿周期、前端总线访问次数等。
    评估程序对操作系统资源的使用情况,系统调用次数、上下文切换次数、任务迁移次数。
    事件可以分为三种:



Hardware Event由PMU部件产生,在特定的条件下探测性能事件是否发生以及发生的次数。比如cache命中。
Software Event是内核产生的事件,分布在各个功能模块中,统计和操作系统相关性能事件。比如进程切换,tick数等。
Tracepoint Event是内核中静态tracepoint所触发的事件,这些tracepoint用来判断程序运行期间内核的行为细节,比如slab分配器的分配次数等。




  1. perf的使用
    perf –help之后可以看到perf的二级命令。
    | 序号 | 命令 | 作用 |
    | 1 | annotate | 解析perf record生成的perf.data文件,显示被注释的代码。 |
    | 2 | archive | 根据数据文件记录的build-id,将所有被采样到的elf文件打包。利用此压缩包,可以再任何机器上分析数据文件中记录的采样数据。 |
    | 3 | bench | perf中内置的benchmark,目前包括两套针对调度器和内存管理子系统的benchmark。 |
    | 4 | buildid-cache | 管理perf的buildid缓存,每个elf文件都有一个独一无二的buildid。buildid被perf用来关联性能数据与elf文件。 |
    | 5 | buildid-list | 列出数据文件中记录的所有buildid。 |
    | 6 | diff | 对比两个数据文件的差异。能够给出每个符号(函数)在热点分析上的具体差异。 |
    | 7 | evlist | 列出数据文件perf.data中所有性能事件。 |
    | 8 | inject | 该工具读取perf record工具记录的事件流,并将其定向到标准输出。在被分析代码中的任何一点,都可以向事件流中注入其它事件。 |
    | 9 | kmem | 针对内核内存(slab)子系统进行追踪测量的工具 |
    | 10 | kvm | 用来追踪测试运行在KVM虚拟机上的Guest OS。 |
    | 11 | list | 列出当前系统支持的所有性能事件。包括硬件性能事件、软件性能事件以及检查点。 |
    | 12 | lock | 分析内核中的锁信息,包括锁的争用情况,等待延迟等。 |
    | 13 | mem | 内存存取情况 |
    | 14 | record | 收集采样信息,并将其记录在数据文件中。随后可通过其它工具对数据文件进行分析。 |
    | 15 | report | 读取perf record创建的数据文件,并给出热点分析结果。 |
    | 16 | sched | 针对调度器子系统的分析工具。 |
    | 17 | script | 执行perl或python写的功能扩展脚本、生成脚本框架、读取数据文件中的数据信息等。 |
    | 18 | stat | 执行某个命令,收集特定进程的性能概况,包括CPI、Cache丢失率等。 |
    | 19 | test | perf对当前软硬件平台进行健全性测试,可用此工具测试当前的软硬件平台是否能支持perf的所有功能。 |
    | 20 | timechart | 针对测试期间系统行为进行可视化的工具 |
    | 21 | top | 类似于linux的top命令,对系统性能进行实时分析。 |
    | 22 | trace | 关于syscall的工具。 |
    | 23 | probe | 用于定义动态检查点。 |
    全局性概况:



perf list查看当前系统支持的性能事件;
perf bench对系统性能进行摸底;
perf test对系统进行健全性测试;
perf stat对全局性能进行统计;



全局细节:



perf top可以实时查看当前系统进程函数占用率情况;
perf probe可以自定义动态事件;



特定功能分析:



perf kmem针对slab子系统性能分析;
perf kvm针对kvm虚拟化分析;
perf lock分析锁性能;
perf mem分析内存slab性能;
perf sched分析内核调度器性能;
perf trace记录系统调用轨迹;



最常用功能perf record,可以系统全局,也可以具体到某个进程,更甚具体到某一进程某一事件;可宏观,也可以很微观。



pref record记录信息到perf.data;
perf report生成报告;
perf diff对两个记录进行diff;
perf evlist列出记录的性能事件;
perf annotate显示perf.data函数代码;
perf archive将相关符号打包,方便在其它机器进行分析;
perf script将perf.data输出可读性文本;



可视化工具perf timechart



perf timechart record记录事件;
perf timechart生成output.svg文档;



3.0 perf引入的overhead
perf测试不可避免的会引入额外负荷,有三种形式:
counting:内核提供计数总结,多是Hardware Event、Software Events、PMU计数等。相关命令perf stat。
sampling:perf将事件数据缓存到一块buffer中,然后异步写入到perf.data文件中。使用perf report等工具进行离线分析。
bpf:Kernel 4.4+新增功能,可以提供更多有效filter和输出总结。
counting引入的额外负荷最小;sampling在某些情况下会引入非常大的负荷;bpf可以有效缩减负荷。
针对sampling,可以通过挂在建立在RAM上的文件系统来有效降低读写I/O引入的负荷。



mkdir /tmpfs
mount -t tmpfs tmpfs /tmpfs



3.1 perf list
perf list不能完全显示所有支持的事件类型,需要sudo perf list。
同时还可以显示特定模块支持的perf事件:hw/cache/pmu都是硬件相关的;tracepoint基于内核的ftrace;sw实际上是内核计数器。
hw/hardware显示支持的硬件事件相关,如:



al@al-System-Product-Name:~/perf$ sudo perf list hardware
List of pre-defined events (to be used in -e):
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]



sw/software显示支持的软件事件列表:



al@al-System-Product-Name:~/perf$ sudo perf list sw
List of pre-defined events (to be used in -e):
alignment-faults [Software event]
bpf-output [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]



cache/hwcache显示硬件cache相关事件列表:



al@al-System-Product-Name:~/perf$ sudo perf list cache
List of pre-defined events (to be used in -e):
L1-dcache-load-misses [Hardware cache event]
L1-dcache-loads [Hardware cache event]
L1-dcache-prefetch-misses [Hardware cache event]
L1-dcache-prefetches [Hardware cache event]
L1-icache-load-misses [Hardware cache event]
L1-icache-loads [Hardware cache event]
L1-icache-prefetches [Hardware cache event]
LLC-load-misses [Hardware cache event]
LLC-loads [Hardware cache event]
LLC-stores [Hardware cache event]
branch-load-misses [Hardware cache event]
branch-loads [Hardware cache event]
dTLB-load-misses [Hardware cache event]
dTLB-loads [Hardware cache event]
iTLB-load-misses [Hardware cache event]
iTLB-loads [Hardware cache event]
node-load-misses [Hardware cache event]
node-loads [Hardware cache event]



pmu显示支持的PMU事件列表:



al@al-System-Product-Name:~/perf$ sudo perf list pmu
List of pre-defined events (to be used in -e):
branch-instructions OR cpu/branch-instructions/ [Kernel PMU event]
branch-misses OR cpu/branch-misses/ [Kernel PMU event]
cache-misses OR cpu/cache-misses/ [Kernel PMU event]
cache-references OR cpu/cache-references/ [Kernel PMU event]
cpu-cycles OR cpu/cpu-cycles/ [Kernel PMU event]
instructions OR cpu/instructions/ [Kernel PMU event]
msr/aperf/ [Kernel PMU event]
msr/mperf/ [Kernel PMU event]
msr/tsc/ [Kernel PMU event]
stalled-cycles-backend OR cpu/stalled-cycles-backend/ [Kernel PMU event]
stalled-cycles-frontend OR cpu/stalled-cycles-frontend/ [Kernel PMU event]



tracepoint显示支持的所有tracepoint列表,这个列表就比较庞大:



al@al-System-Product-Name:~/perf$ sudo perf list tracepoint
List of pre-defined events (to be used in -e):
alarmtimer:alarmtimer_cancel [Tracepoint event]
alarmtimer:alarmtimer_fired [Tracepoint event]
alarmtimer:alarmtimer_start [Tracepoint event]
alarmtimer:alarmtimer_suspend [Tracepoint event]
block:block_bio_backmerge [Tracepoint event]
block:block_bio_bounce [Tracepoint event]
block:block_bio_complete [Tracepoint event]
block:block_bio_frontmerge [Tracepoint event]
block:block_bio_queue [Tracepoint event]



3.2 perf top
默认情况下perf top是无法显示信息的,需要sudo perf top或者echo -1 > /proc/sys/kernel/perf_event_paranoid(在Ubuntu16.04,还需要echo 0 > /proc/sys/kernel/kptr_restrict)。
即可以正常显示perf top如下:
第一列:符号引发的性能事件的比例,指占用的cpu周期比例。
第二列:符号所在的DSO(Dynamic Shared Object),可以是应用程序、内核、动态链接库、模块。
第三列:DSO的类型。[.]表示此符号属于用户态的ELF文件,包括可执行文件与动态链接库;[k]表述此符号属于内核或模块。
第四列:符号名。有些符号不能解析为函数名,只能用地址表示



关于perf top界面常用命令如下:



h:显示帮助,即可显示详细的帮助信息。
UP/DOWN/PGUP/PGDN/SPACE:上下和翻页。
a:annotate current symbol,注解当前符号。能够给出汇编语言的注解,给出各条指令的采样率。
d:过滤掉所有不属于此DSO的符号。非常方便查看同一类别的符号。
P:将当前信息保存到perf.hist.N中。



perf top常用选项有:



-e :指明要分析的性能事件。
-p :Profile events on existing Process ID (comma sperated list). 仅分析目标进程及其创建的线程。
-k :Path to vmlinux. Required for annotation functionality. 带符号表的内核映像所在的路径。
-K:不显示属于内核或模块的符号。
-U:不显示属于用户态程序的符号。
-d :界面的刷新周期,默认为2s,因为perf top默认每2s从mmap的内存区域读取一次性能数据。
-g:得到函数的调用关系图。



perf top –call-graph [fractal],路径概率为相对值,加起来为100%,调用顺序为从下往上。
perf top –call-graph graph,路径概率为绝对值,加起来为该函数的热度。



3.3 perf stat
perf stat用于运行指令,并分析其统计结果。虽然perf top也可以指定pid,但是必须先启动应用才能查看信息。
perf stat能完整统计应用整个生命周期的信息。
命令格式为:



perf stat [-e | --event=EVENT] [-a]
perf stat [-e | --event=EVENT] [-a] — []



下面简单看一下perf stat 的输出:



al@al-System-Product-Name:~/perf$ sudo perf stat
^C
Performance counter stats for ‘system wide’:



输出解释如下:



cpu-clock:任务真正占用的处理器时间,单位为ms。CPUs utilized = task-clock / time elapsed,CPU的占用率。
context-switches:程序在运行过程中上下文的切换次数。
CPU-migrations:程序在运行过程中发生的处理器迁移次数。Linux为了维持多个处理器的负载均衡,在特定条件下会将某个任务从一个CPU迁移到另一个CPU。
CPU迁移和上下文切换:发生上下文切换不一定会发生CPU迁移,而发生CPU迁移时肯定会发生上下文切换。发生上下文切换有可能只是把上下文从当前CPU中换出,下一次调度器还是将进程安排在这个CPU上执行。
page-faults:缺页异常的次数。当应用程序请求的页面尚未建立、请求的页面不在内存中,或者请求的页面虽然在内存中,但物理地址和虚拟地址的映射关系尚未建立时,都会触发一次缺页异常。另外TLB不命中,页面访问权限不匹配等情况也会触发缺页异常。
cycles:消耗的处理器周期数。如果把被ls使用的cpu cycles看成是一个处理器的,那么它的主频为2.486GHz。可以用cycles / task-clock算出。
stalled-cycles-frontend:指令读取或解码的质量步骤,未能按理想状态发挥并行左右,发生停滞的时钟周期。
stalled-cycles-backend:指令执行步骤,发生停滞的时钟周期。
instructions:执行了多少条指令。IPC为平均每个cpu cycle执行了多少条指令。
branches:遇到的分支指令数。branch-misses是预测错误的分支指令数。



其他常用参数



-a, –all-cpus 显示所有CPU上的统计信息
-C, –cpu 显示指定CPU的统计信息
-c, --scale scale/normalize counters
-D, --delay ms to wait before starting measurement after program start
-d, --detailed detailed run - start a lot of events
-e, --event event selector. use 'perf list' to list available events
-G, --cgroup monitor event in cgroup name only
-g, --group put the counters into a counter group
-I, --interval-print
print counts at regular interval in ms (>= 10)
-i, --no-inherit child tasks do not inherit counters
-n, --null null run - dont start any counters
-o, --output 输出统计信息到文件
-p, --pid stat events on existing process id
-r, --repeat repeat command and print average + stddev (max: 100, forever: 0)
-S, --sync call sync() before starting a run
-t, --tid stat events on existing thread id
...



示例
前面统计程序的示例,下面看一下统计CPU信息的示例:
执行sudo perf stat -C 0,统计CPU 0的信息。想要停止后,按下Ctrl+C终止。可以看到统计项一样,只是统计对象变了。



al@al-System-Product-Name:~/perf$ sudo perf stat -C 0
^C
Performance counter stats for ‘CPU(s) 0’:



如果需要统计更多的项,需要使用-e,如:
| perf stat -e task-clock,context-switches,cpu-migrations,page-faults,cycles,stalled-cycles-frontend,stalled-cycles-backend,instructions,branches,branch-misses,L1-dcache-loads,L1-dcache-load-misses,LLC-loads,LLC-load-misses,dTLB-loads,dTLB-load-misses ls |
结果如下,关注的特殊项也纳入统计。



al@al-System-Product-Name:~/perf$ sudo perf stat -e task-clock,context-switches,cpu-migrations,page-faults,cycles,stalled-cycles-frontend,stalled-cycles-backend,instructions,branches,branch-misses,L1-dcache-loads,L1-dcache-load-misses,LLC-loads,LLC-load-misses,dTLB-loads,dTLB-load-misses ls
Performance counter stats for ‘ls’:



3.4 perf bench
perf bench作为benchmark工具的通用框架,包含sched/mem/numa/futex等子系统,all可以指定所有。
perf bench可用于评估系统sched/mem等特定性能。



perf bench sched:调度器和IPC机制。包含messaging和pipe两个功能。
perf bench mem:内存存取性能。包含memcpy和memset两个功能。
perf bench numa:NUMA架构的调度和内存处理性能。包含mem功能。
perf bench futex:futex压力测试。包含hash/wake/wake-parallel/requeue/lock-pi功能。
perf bench all:所有bench测试的集合



3.4.1 perf bench sched all
测试messaging和pipi两部分性能。
3.4.1.1 sched messaging评估进程调度和核间通信
sched message 是从经典的测试程序 hackbench 移植而来,用来衡量调度器的性能,overhead 以及可扩展性。
该 benchmark 启动 N 个 reader/sender 进程或线程对,通过 IPC(socket 或者 pipe) 进行并发的读写。一般人们将 N 不断加大来衡量调度器的可扩展性。
sched message 的用法及用途和 hackbench 一样,可以通过修改参数进行不同目的测试:



-g, –group Specify number of groups
-l, --nr_loops Specify the number of loops to run (default: 100)
-p, --pipe Use pipe() instead of socketpair()
-t, --thread Be multi thread instead of multi process



最初的时候,它叫做 Performance counter,在 2.6.31 中第一次亮相。此后他成为内核开发最为活跃的一个领域。在 2.6.32 中它正式改名为 Performance Event,因为 perf 已不再仅仅作为 PMU 的抽象,而是能够处理所有的性能相关的事件。



使用 perf,您可以分析程序运行期间发生的硬件事件,比如 instructions retired ,processor clock cycles 等;您也可以分析软件事件,比如 Page Fault 和进程切换。



这使得 Perf 拥有了众多的性能分析能力,举例来说,使用 Perf 可以计算每个时钟周期内的指令数,称为 IPC,IPC 偏低表明代码没有很好地利用 CPU。Perf 还可以对程序进行函数级别的采样,从而了解程序的性能瓶颈究竟在哪里等等。Perf 还可以替代 strace,可以添加动态内核 probe 点,还可以做 benchmark 衡量调度器的好坏。。。



人们或许会称它为进行性能分析的“瑞士军刀”,但我不喜欢这个比喻,我觉得 perf 应该是一把世间少有的倚天剑。



金庸笔下的很多人都有对宝刀的癖好,即便本领低微不配拥有,但是喜欢,便无可奈何。我恐怕正如这些人一样,因此进了酒馆客栈,见到相熟或者不相熟的人,就要兴冲冲地要讲讲那倚天剑的故事。



背景知识
有些背景知识是分析性能问题时需要了解的。比如硬件 cache;再比如操作系统内核。应用程序的行为细节往往是和这些东西互相牵扯的,这些底层的东西会以意想不到的方式影响应用程序的性能,比如某些程序无法充分利用 cache,从而导致性能下降。比如不必要地调用过多的系统调用,造成频繁的内核 / 用户切换。等等。方方面面,这里只是为本文的后续内容做一些铺垫,关于调优还有很多东西,我所不知道的比知道的要多的多。



性能相关的处理器硬件特性,PMU 简介
当算法已经优化,代码不断精简,人们调到最后,便需要斤斤计较了。cache 啊,流水线啊一类平时不大注意的东西也必须精打细算了。



硬件特性之 cache
内存读写是很快的,但还是无法和处理器的指令执行速度相比。为了从内存中读取指令和数据,处理器需要等待,用处理器的时间来衡量,这种等待非常漫长。Cache 是一种 SRAM,它的读写速率非常快,能和处理器处理速度相匹配。因此将常用的数据保存在 cache 中,处理器便无须等待,从而提高性能。Cache 的尺寸一般都很小,充分利用 cache 是软件调优非常重要的部分。



硬件特性之流水线,超标量体系结构,乱序执行
提高性能最有效的方式之一就是并行。处理器在硬件设计时也尽可能地并行,比如流水线,超标量体系结构以及乱序执行。



处理器处理一条指令需要分多个步骤完成,比如先取指令,然后完成运算,最后将计算结果输出到总线上。在处理器内部,这可以看作一个三级流水线,



Perf是Linux kernel自带的系统性能优化工具。Perf的优势在于与Linux Kernel的紧密结合,它可以最先应用到加入Kernel的new feature。pef可以用于查看热点函数,查看cashe miss的比率,从而帮助开发者来优化程序性能。



  1.perf的安装



  由于我们经常是在自己编译的内核上进行开发工作,这里需要有包含调式信息的内核启动镜像文件vmlinux,在自定义内核的基础之上,进入linux内核源码,linux/tools/perf



  make



  make install



  提示:



  1)可能在编译的时候,有报错大概是由于平台问题,数据类型不匹配,导致所有的warning都被当作error对待:出现这问题的原因是-Werror这个gcc编译选项。只要在makefile中找到包含这个-Werror选项的句子,将-Werror删除,或是注释掉就行了



  2)安装完毕,perf可执行程序往往位于当前目录,可能不在系统的PATH路径中,此时需要改变环境变量PATH



  2.perf的运行原理



  性能调优工具如 perf,Oprofile 等的基本原理都是对被监测对象进行采样,最简单的情形是根据 tick 中断进行采样,即在 tick 中断内触发采样点,在采样点里判断程序当时的上下文。假如一个程序 90% 的时间都花费在函数 foo() 上,那么 90% 的采样点都应该落在函数 foo() 的上下文中。运气不可捉摸,但我想只要采样频率足够高,采样时间足够长,那么以上推论就比较可靠。因此,通过 tick 触发采样,我们便可以了解程序中哪些地方最耗时间,从而重点分析。



  稍微扩展一下思路,就可以发现改变采样的触发条件使得我们可以获得不同的统计数据:



  以时间点 ( 如 tick) 作为事件触发采样便可以获知程序运行时间的分布。



  以 cache miss 事件触发采样便可以知道 cache miss 的分布,即 cache 失效经常发生在哪些程序代码中。如此等等。



  因此让我们先来了解一下 perf 中能够触发采样的事件有哪些。



  使用perf list(在root权限下运行),可以列出所有的采样事件



  事件分为以下三种:



  1)Hardware Event 是由 PMU 硬件产生的事件,比如 cache 命中,当您需要了解程序对硬件特性的使用情况时,便需要对这些事件进行采样;



  2)Software Event 是内核软件产生的事件,比如进程切换,tick 数等 ;



  3)Tracepoint event 是内核中的静态 tracepoint 所触发的事件,这些 tracepoint 用来判断程序运行期间内核的行为细节,比如 slab 分配器的分配次数等。



  上述每一个事件都可以用于采样,并生成一项统计数据,时至今日,尚没有文档对每一个 event 的含义进行详细解释。



 3.perfstat——概览程序的运行情况



  面对一个问题程序,最好采用自顶向下的策略。先整体看看该程序运行时各种统计事件的大概,再针对某些方向深入细节。而不要一下子扎进琐碎细节,会一叶障目的。



  有些程序慢是因为计算量太大,其多数时间都应该在使用CPU进行计算,这叫做CPUbound型;有些程序慢是因为过多的IO,这种时候其CPU利用率应该不高,这叫做IObound型;对于CPUbound程序的调优和IObound的调优是不同的。



  如果您认同这些说法的话,Perfstat应该是您最先使用的一个工具。它通过概括精简的方式提供被调试程序运行的整体情况和汇总数据。
  
 go的pprof包
go中有pprof包来做代码的性能监控,在两个地方有包:



net/http/pprof



runtime/pprof



其实net/http/pprof中只是使用runtime/pprof包来进行封装了一下,并在http端口上暴露出来.



一、代码部分
1.import 增加net/http/pprof包



import(
_ net/http/pprof
)




  1. 打开http 监听端口



go func() {
log.Println(http.ListenAndServe(“localhost:10000”, nil))
}()



二、网页上查看
*浏览器可以打开 http://127.0.0.1:10000/debug/pprof/ 可以查看各种profile索引



1.如果安装过graphviz直接提交过这步骤,否则可以到 http://www.graphviz.org/download/下载,并把bin加入到环境变量



2.查看profile :在命令行输入



go tool pprof http://localhost:10000/debug/pprof/profile
此后的30秒进入收集profile信息的状态。



30秒后进入pprof的交互模式,然后输入



web
然后浏览器自动弹开到网页展示svg图



3.查看已经保存的profile文件



go tool pprof profile C:\Users\user\pprof\pprof.samples.cpu.004.pb.gz



然后也是进入pprof的交互模式,然后输入web



还可以查看heap和goroutine



go tool pprof http://localhost:10000/debug/pprof/heap
go tool pprof http://127.0.0.1:10000/debug/pprof/goroutine
  



pprof 以 profile.proto 读取分析样本的集合,并生成报告以可视化并帮助分析数据(支持文本和图形报告)
profile.proto 是一个 Protocol Buffer v3 的描述文件,它描述了一组 callstack 和 symbolization 信息, 作用是表示统计分析的一组采样的调用栈,是很常见的 stacktrace 配置文件格式



支持什么使用模式



Report generation:报告生成
Interactive terminal use:交互式终端使用
Web interface:Web 界面



可以做什么



CPU Profiling:CPU 分析,按照一定的频率采集所监听的应用程序 CPU(含寄存器)的使用情况,可确定应用程序在主动消耗 CPU 周期时花费时间的位置
Memory Profiling:内存分析,在应用程序进行堆分配时记录堆栈跟踪,用于监视当前和历史内存使用情况,以及检查内存泄漏
Block Profiling:阻塞分析,记录 goroutine 阻塞等待同步(包括定时器通道)的位置
Mutex Profiling:互斥锁分析,报告互斥锁的竞争情况



一、通过 Web 界面
查看当前总览:访问 http://127.0.0.1:6060/debug/pprof/



cpu(CPU Profiling): $HOST/debug/pprof/profile,默认进行 30s 的 CPU Profiling,得到一个分析用的 profile 文件
block(Block Profiling):$HOST/debug/pprof/block,查看导致阻塞同步的堆栈跟踪
goroutine:$HOST/debug/pprof/goroutine,查看当前所有运行的 goroutines 堆栈跟踪
heap(Memory Profiling): $HOST/debug/pprof/heap,查看活动对象的内存分配情况
mutex(Mutex Profiling):$HOST/debug/pprof/mutex,查看导致互斥锁的竞争持有者的堆栈跟踪
threadcreate:$HOST/debug/pprof/threadcreate,查看创建新OS线程的堆栈跟踪



二、通过交互式终端使用
(1)go tool pprof http://localhost:6060/debug/pprof/profile?seconds=60



(pprof) top10
Showing nodes accounting for 25.92s, 97.63% of 26.55s total
Dropped 85 nodes (cum <= 0.13s)
Showing top 10 nodes out of 21
flat flat% sum% cum cum%
23.28s 87.68% 87.68% 23.29s 87.72% syscall.Syscall
0.77s 2.90% 90.58% 0.77s 2.90% runtime.memmove



flat:给定函数上运行耗时
flat%:同上的 CPU 运行耗时总比例
sum%:给定函数累积使用 CPU 总比例
cum:当前函数加上它之上的调用运行总耗时
cum%:同上的 CPU 运行耗时总比例



最后一列为函数名称,在大多数的情况下,我们可以通过这五列得出一个应用程序的运行情况,加以优化



(2)go tool pprof http://localhost:6060/debug/pprof/heap
$ go tool pprof http://localhost:6060/debug/pprof/heap
Fetching profile over HTTP from http://localhost:6060/debug/pprof/heap
Saved profile in /Users/eddycjy/pprof/pprof.alloc_objects.alloc_space.inuse_objects.inuse_space.008.pb.gz
Type: inuse_space
Entering interactive mode (type “help” for commands, “o” for options)
(pprof) top
Showing nodes accounting for 837.48MB, 100% of 837.48MB total
flat flat% sum% cum cum%
837.48MB 100% 100% 837.48MB 100% main.main.func1



-inuse_space:分析应用程序的常驻内存占用情况
-alloc_objects:分析应用程序的内存临时分配情况



(3) go tool pprof http://localhost:6060/debug/pprof/block
(4) go tool pprof http://localhost:6060/debug/pprof/mutex



(2)执行测试用例
$ go test -bench=. -cpuprofile=cpu.prof
pkg: github.com/EDDYCJY/go-pprof-example/data
BenchmarkAdd-4 10000000 187 ns/op
PASS
ok github.com/EDDYCJY/go-pprof-example/data 2.300s



-memprofile 也可以了解一下



启动 PProf 可视化界面
方法一:
$ go tool pprof -http=:8080 cpu.prof



方法二:
$ go tool pprof cpu.prof
$ (pprof) web



如果出现 Could not execute dot; may need to install graphviz.,就是提示你要安装 graphviz



查看 PProf 可视化界面
(1)Top
2)Graph
框越大,线越粗代表它占用的时间越大
(3)Peek
(4)Source



通过 PProf 的可视化界面,我们能够更方便、更直观的看到 Go 应用程序的调用链、使用情况等,并且在 View 菜单栏中,还支持如上多种方式的切换



四、PProf 火焰图
另一种可视化数据的方法是火焰图,需手动安装原生 PProf 工具:
(1) 安装 PProf
$ go get -u github.com/google/pprof
(2) 启动 PProf 可视化界面:



$ pprof -http=:8080 cpu.prof
(3) 查看 PProf 可视化界面



打开 PProf 的可视化界面时,你会明显发现比官方工具链的 PProf 精致一些,并且多了 Flame Graph(火焰图)



go tool pprof -inuse_space -cum -svg http://ip:8899/debug/pprof/heap > heap_inuse.svg



golang 的性能分析库在 runtime/pprof 里,主要提供下面几个接口



// 堆栈分析
func WriteHeapProfile(w io.Writer) error
// cpu分析
func StartCPUProfile(w io.Writer) error
func StopCPUProfile()
使用上面比较简单,只需要将文件指针传给对应的函数即可,性能数据将写入到文件中,然后可以使用 golang 自带的 pprof 工具生成 svg,pdf 的可视化图,然后就可以很直观地从这些图里面看到主要的性能消耗了



pprof 文件分析
pprof 文件是二进制的,不是给人读的,需要翻译一下,而 golang 原生就给我们提供了分析工具,直接执行下面命令即可,会生成一张很直观的 svg 图片,直接用 chrome 就可以打开,当然也可以生成别的格式(pdf,png 都可以),可以用 go tool pprof -h 命令查看支持的输出类型



go tool pprof -svg ./pprof_runtime cpu.pprof.201801301415 > cpu.svg
注意这个工具依赖于 graphviz 工具,Mac 上可用 brew install graphviz,centos yum install graphviz 即可



http 接口
net/http/pprof 里面对 runtime/pprof 作了一些封装,对外提供了 http 接口,可以直接通过浏览器访问,但是只是一些字符串的结果,没有作可视化,体验并不是很好,用 go tool 访问体验能好一点



go tool pprof http://localhost:3000/debug/pprof/profile
go tool pprof http://localhost:3000/debug/pprof/heap



除了上面生成的 svg 图,还可以生成火焰图,这是 uber 提供的一个工具,在显示上面可能更直观一些



安装命令如下:



go get github.com/uber/go-torch
git clone git@github.com:brendangregg/FlameGraph.git
export PATH=$PATH:/path/to/FlameGraph



使用方法如下:



go-torch –binaryname=./pprof_runtime –binaryinput=cpu.pprof.201801301415



Go tool pprof常用基本调试基本命令(默认30s采集时间,可通过–seconds)
HTTP场景(参数可选:–text):
Heap profile:
go tool pprof –text http://localhost:8080/debug/pprof/heap



CPU profile:
go tool pprof –text http://localhost:8080/debug/pprof/profile



Goroutine blocking profile:
go tool pprof –text http://localhost:8080/debug/pprof/block



1.实时通过地址查看浏览器: http://localhost:8080/debug/pprof/;
2.通过生成的profile文件分析;
选择指定的profile压缩gz文件(.gz),使用go tool pprof进入
go tool pprof http://localhost:8080/debug/pprof/profile
#结束后直接进入交互:
(pprof)
web
(pprof)



如查看历史调试文件信息,通过指定的profile文件进入即可:
go tool pprof [*.gz]
pprof交互基本命令:web 直接生成web浏览器可访问的svg图;
(其他命令自行摸索)
Windows下自动生成.svg文件且调用默认浏览器访问;
MacOS下自动生成.gz文件,系统限制可根据提示文件路径通过手动访问查看;



【注意事项】:
profile文件为空的问题, heap和block一般不受影响。
执行交互web命令会报:
(pprof) web
profile is empty
(pprof)



产生原因:
pprof内存分析器采取抽样的方式,它仅仅从一些内存分配的子集中收集信息。有可能对一个对象的采样与被采样对象的大小成比例。通过使用go test –memprofilerate标识,或者通过程序启动时 的运行配置中的MemProfileRate变量来改变调整这个采样的比例。如果比例为1,则会导致全部申请的信息都会被收集,但是这样的话将会使得执行变慢。默认的采样比例是每512KB的内存申请就采样一次。



方法1).在进行调试时,指定运行参数,或运行代码中动态调整参数



go tool pprof –text http://localhost:8080/debug/pprof/profile



此命令将会打印耗费最多CPU时间的函数列表。
这里有几种可用的输出形式,最实用的有 –text, –web 和 –list。运行 “go tool pprof” 来得到完整的列表。
【备注】:
实际测试时,MacOS下基本是空的,需要指定参数。



方法2).设置环境变量(此方法极不推荐!)设置Go环境变量 GODEBUG=”memprofilerate=1”.
通过控制采样的比例和行为,可以达到性能调试粒度的控制!



内存分析器显示了函数分配堆内存的情况。你可以以 CPU profile 相似的方式收集:使用 go test –memprofile,通过 http://myserver:6060:/debug/pprof/heap 使用 net/http/pprof 或是通过调用 runtime/pprof.WriteHeapProfile。



你仅可以显示在概要文件收集的时间分配的内存(默认,pprof 的 –inuse_space 标志),或是从程序启动起的所有分配(pprof 的 –alloc_space 标志)。前者对对于 net/http/pprof 的现场应用的概要文件收集非常有用,后者对程序结束的时候的概要文件收集非常有用(否则你将看到空荡荡的概要文件)。



注意:内存分析器很简单,也就是说,它收集的信息仅仅是关于内存分配的一些子集。概率抽样对象与它的大小成正比,你可以使用 go test –memprofilerate 标志改变抽样比率,或者是在程序启动的时候设置 runtime.MemProfileRate 变量。比率 1 将导致收集所有分配的信息。但是它可能导致执行很慢,默认的采样率是每 512kb 的内存分配 1个样本。



你也可以显示分配的字节数,或者是分配的对象数量(–inuse/alloc_space 和 –inuse/alloc_objects 标志)。分析器在分析时更倾向于大样本对象。但是更重要的是要明白大对象影响内存消耗和 GC 时间,然而大量微小的分配影响执行速度(同样是某种程度的 GC 时间),所以两个都观察可能是非常有用的。



对象可以是持久的或是瞬态的。如果在程序开始的时候,你有一些大的持久化对象分配,它们将最有可能被分析器采样(因为它们足够大)。这样的对象会影响内存的消耗和 GC 时间,但是它们不影响正常的执行速度(没有内存管理操作发生在它们身上)。换句话说,如果你有大量的生命周期非常短暂的对象,在概要文件中,它们几乎可以代表(如果你使用默认的 –inuse_space 模式),但它们很明显的会影响执行速度。因为它们在不断的分配和释放。因此,再一次声明,观察两种类型的对象是非常有用的。



因此,通常如果你想降低内存消耗,在正常的程序操作期间,你需要查看 –inuse_space 概要文件收集。如果你想提升执行速度,查看 –alloc_objects 概要文件收集,在重要的运行时间或程序结束之后。



这有一些标志控制报告的粒度。–functions 使得 pprof 报告在函数级别(默认)。–lines 使得 pprof 报告在源码的行级别。这是非常有用的,如果热函数在不同的行。这里也有 –addresses 和 –files 各自对应准确的指令地址和文件级别。



对于内存概要文件来说,这是非常有用的选项 – 你可以在浏览器中查看它(提供这个功能需要你 imported net/http/pprof)。如果你打开 http://myserver:6060/debug/pprof/heap?debug=1,



pprof - manual page for pprof (part of gperftools)



是gperftools工具的一部分



gperftools又是啥?



These tools are for use by developers so that they can create more robust applications. Especially of use to those developing multi-threaded applications in C++ with templates. Includes TCMalloc, heap-checker, heap-profiler and cpu-profiler.



一个性能分析的工具,可以查看堆栈、cpu信息等等。



go tool pprof http://localhost:6060/debug/pprof/heap这种方式出现了错误parsing profile: unrecognized profile format



少了一些东西,应该是这样 go tool pprof http://127.0.0.1:8601/debug/pprof/heap?debug=1,或者使用浏览器直接访问 http://127.0.0.1:8601/debug/pprof/ ,最后的斜杠不要忘了



Golang pprof heap profile is empty
Q:



When you use go tool pprof get heap data, profile is empty.



A:



The default sampling rate is 1 sample per 512KB of allocated memory.



So If you application use little memory, the profiling can’t sampling any data.



You can change runtime.MemProfileRate to reduce sampling rate.



The easy way is add Environment Variables GODEBUG=”memprofilerate=1”, before run you application.



执行命令 go test -test.bench=”BenchmarkHeapSort” -cpuprofile cpu.out,会得到两个文件:
cpu.out mysort.test cpu.out是cpu采样结果,mysort.test是测试的二进制文件,使用命令go tool pprof mysort.test cpu.out可得到如下结果:
File: mysort.test
Type: cpu
Time: Feb 17, 2019 at 12:55pm (CST)
Duration: 2.06s, Total samples = 1.67s (80.90%)
Entering interactive mode (type “help” for commands, “o” for options)
(pprof) top10
Showing nodes accounting for 1.67s, 100% of 1.67s total
Showing top 10 nodes out of 16
flat flat% sum% cum cum%
1.06s 63.47% 63.47% 1.38s 82.63%



一、官方文档
https://blog.golang.org/profiling-go-programs



$cd your_programe_dir
$go build
$./your_programe -cpuprofile=xxx.prof
$go tool pprof ./your_programe xxx.prof
Entering interactive mode (type “help” for commands)
(pprof) top 10

(pprof) web 生成svg文件并打开



1.如果出现提示:
Cannot find dot, have you installed Graphviz?



需要用root用户安装Graphviz



2.如果出现提示:
profile is empty



那是因为默认的pprof的采样频率是每秒100次,如果你的程序运行太快,在第一次采样前就结束了,就会出现这个情况。
要不就在程序里面加for循环或者sleep,要不就调整采样频率(见二)



还有一种可能就程序没有执行,比如没有请求



https://github.com/pkg/profile



1、pprof
pprof是Golang官方自带的程序性能分析包,可以在net/http/pprof、runtime/pprof这两个地方引用,net/http/pprof实际也调用了runtime/pprof,并在http端口上暴露。
(1)服务程序
引入方式如下:



import _ “net/http/pprof”
demo代码如下



package main



import “net/http”
import _ “net/http/pprof”



func main() {
http.ListenAndServe(“:8080”, http.DefaultServeMux)
}
然后访问该链接 http://127.0.0.1:8080/debug/pprof/
可以看到当前web服务的状态,包括CPU占用情况和内存使用情况



(2)应用程序
这种场景下需要引入runtime/pprof包,对CPU运行信息进行采样存储,比如



package main



import “runtime/pprof”
import “os”
import “log”



func main() {
f, err := os.Create(“cpu.prof”)
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
下一步需要使用pprof文件做出性能分析图



go tool pprof test.exe cpu.prof
然后输入web命令生成svg文件,svg用浏览器打开可以看到调用链。如果提示”profile is empty”是由于程序使用了很少的内存,无法进行采样导致,可以修改runtime.MemProfileRate降低采样率,运行前加上环境变量GODEBUG=”memprofilerate=1”。



2、torch
go-torch是Uber公司开源的一款针对Go语言程序的火焰图生成工具(https://github.com/uber/go-torch),能收集 stack traces,并把它们整理成火焰图,直观地程序给开发人员,很方便地分析Go的各个方法所占用的CPU的时间。
(1)安装FlameGraph
Stack trace visualizer:profile数据的可视化层工具



git clone https://github.com/brendangregg/FlameGraph.git
cp flamegraph.pl /usr/local/bin
(2)安装torch



go get -v github.com/uber/go-torch
(3)使用torch
go-torch命令用法非常多,比如



Usage:
go-torch [options] [binary]



pprof Options:
/u, /url: Base URL of your Go program (default:
http://localhost:8080)
/suffix: URL path of pprof profile (default: /debug/pprof/profile)
/t, /seconds: Number of seconds to profile for (default: 30)
/pprofArgs: Extra arguments for pprof



Output Options:
/f, /file: Output file name (must be .svg) (default: torch.svg)
/p, /print Print the generated svg to stdout instead of writing to
file
/r, /raw Print the raw call graph output to stdout instead of
creating a flame graph; use with Brendan Gregg’s flame
graph perl script (see
https://github.com/brendangregg/FlameGraph)
……
(4)demo
使用torch采样方式分析程序30s性能情况,结束后会生成torch.svg。



go-torch -u http://localhost:8080 -t 30
torch.png
火焰图的y轴表示cpu调用方法的先后,x轴表示在每个采样调用时间内,方法所占的时间百分比,越宽代表占据cpu时间越多。



在Go语言中,我们可以通过标准库的代码包runtime和runtime/pprof中的程序来生成三种包含实时性数据的概要文件,分别是CPU概要文件、内存概要文件和程序阻塞概要文件



Category linux