性能专家Brendan Gregg的网站。
Linux性能
该页面链接到我创建的各种Linux性能材料,包括右侧的工具图。它们使用大字体来适合滑盖。您也可以将它们打印出来用于办公室墙壁。它们显示:Linux可观察性工具, Linux静态性能分析工具, Linux基准测试工具, Linux调整工具和Linux sar。在图像上检查年份(右下)以查看年份。
还有一个高分辨率图,它结合了可观察性,静态性能调整和perf-tools / bcc:png,svg(请参见讨论),但是它不如其他图完整。有关更多图表,请参见下面的幻灯片。
2020年7月18日:我有一本新书出版:《系统性能:企业与云》第二版(2020),其中以Linux为例。
http://www.brendangregg.com/linuxperf.html
文献资料
- 60,000毫秒内的Linux性能分析显示了调查中要使用的前十个命令(视频,PDF)。由我本人和Netflix的性能工程团队撰写(2015年)。
- 我的文章《 EC2上的性能调整Linux实例》包含了我们在Netflix(2015)上使用的可调参数。
- 关于Linux平均负载:解决奥秘的文章,解释了它们是什么以及为什么它们包括不间断的睡眠状态(2017)。
- 一个gdb调试完整示例(教程),其中包括一些perf / debugging工具的使用(2016年)。
- 《BPF性能工具:Linux系统和应用程序可观察性》一书概述了传统的Linux性能工具(iostat(1),perf(1)等)以及新的BPF工具。
- 使用perf和eBPF在Linux上生成火焰图:
Java
我在JavaOne 2016上发表的带有火焰图的Linux上的Java性能分析总结了使用Linux性能来生成混合模式火焰图的最新技术。
背景
为了生成火焰图,您需要一个可以对堆栈轨迹进行采样的探查器。历史上有两种类型的探查器:
- 系统分析器:类似于Linux性能,它显示系统代码路径(例如JVM GC,系统调用,TCP),但不显示Java方法。
- JVM探查器:如hprof,LJP和商业探查器。这些显示Java方法,但通常不显示系统代码路径。
可以如前所述执行使用(1)的火焰图。(2)取决于您要使用的探查器。火焰图软件包括stackcollapse-ljp.pl,用于处理轻量级Java Profiler(LJP)的输出。我的博客文章Java Flame Graphs总结了如何使用LJP。如果创建系统火焰图(例如,在Linux上使用perf)以及LJP火焰图,则通常可以通过同时检查所有问题来解决所有问题。
理想情况下,我们有一个火焰图可以完成所有工作:系统和Java代码路径。除了方便之外,它还显示了Java上下文中的系统代码路径,这对于正确理解概要文件至关重要。
问题是让系统分析器了解Java方法和堆栈跟踪。例如,如果您尝试使用Linux perf_events,您将看到十六进制数字和中断的堆栈跟踪,因为它无法将地址转换为Java符号,也无法遍历JVM堆栈。DTrace长期以来一直支持jstack()操作,但是它也存在问题,稍后将进行介绍。
有两个特定的问题:
- JVM即时编译方法(即时:JIT),并且不公开传统的符号表供系统分析器读取。
- JVM还使用帧指针寄存器(x86-64上的RBP)作为通用寄存器,打破了传统的堆栈遍历。
Linux perf_events
解决上述两个问题的一种方法涉及:
- JVMTI代理perf-map-agent(以前在此处),可以提供Java符号表供perf读取(/tmp/perf-PID.map)。
- -XX:+ PreserveFramePointer JVM选项,因此perf可以遍历基于帧指针的堆栈。
+ PreserveFramePointer已添加到JDK8u60中,以方便生成性能图和火焰图(我已将原型通过电子邮件发送到热点编译器devs邮件列表,一个用于堆栈分析的热点补丁(框架指针),其变为JDK-8068945:使用RBP寄存器作为在x64上的JIT编译代码中正确的帧指针)。我在Netflix Tech博客上总结了最后的步骤:Java in Flames。以下是更新的步骤:
1.安装perf-map-agent:
须藤bash
apt-get install cmake
导出JAVA_HOME = /您的新jdk8路径
cd / destination-for-perf-map-agent#我使用/ usr / lib / jvm
git clone --depth = 1 https://github.com/jvm-profiling-tools/perf-map-agent
cd perf-map-agent
cmake。
使
2.轮廓分析和火焰图生成:
git clone --depth = 1 https://github.com/brendangregg/FlameGraph
须藤bash
性能记录-F 49 -a -g-睡眠30; ./FlameGraph/jmaps
性能脚本> out.stacks01
猫out.stacks01 | ./FlameGraph/stackcollapse-perf.pl | grep -v cpu_idle | \
./FlameGraph/flamegraph.pl --color = java --hash> out.stacks01.svg
请注意,jmaps(调用perf-map-agent进行符号转储的帮助程序脚本)在perf记录后立即运行,以最大程度地减少符号流失。
生成的火焰图示例为(SVG,支持单击缩放):
当运行flamegraph.pl时,我使用了--color = java,它对不同类型的帧使用不同的色调。绿色是Java,黄色是C ++,橙色是内核,红色是其余部分(本机用户级别或内核模块)。
当前这是一个概念证明,并且不支持该修补程序。有关讨论和状态,请参阅邮件列表,有关此方法的注意事项。返回帧指针的确会花费一些性能(取决于工作量,它可以忽略不计),并且Flame图未显示内联方法。我希望该修补程序作为可调选项包括在内,例如-XX:+ NoOmitFramePointer。
DTrace
DTrace使用其jstack()操作,可以对用户级堆栈以及Java方法和类进行概要分析。(理论上:请参见下面列出的错误。)其使用的功能称为“ DTrace ustack助手”(搜索该术语以了解更多信息)。因此,要为Java程序生成CPU火焰图,可以使用以下命令收集堆栈:
#dtrace将-n“轮廓-97 / execname == “Java”的/ {@ [jstack(100,8000)] =计数(); }
tick-30s {exit(0); }'-o out.javastacks_01
然后可以将输出文件输入到stackcollapse.pl和flamegraph.pl中,如前面的部分所示。
ustack helper动作是jstack(),如果成功,您将拥有如下所示的堆栈:
libjvm.so`jni_GetObjectField + 0x10f
libnet.so`Java_java_net_PlainSocketImpl_socketAvailable + 0x39
java / net / PlainSocketImpl.socketAvailable()I *
java / net / PlainSocketImpl.available()I *
java / lang / Thread.run()V
0xfb60035e
libjvm.so`__1cJJavaCallsLcall_helper6FpnJJavaValue_pnMmethodHa ...
libjvm.so`__1cCosUos_exception_wrapper6FpFpnJJavaValue_pnMmeth ...
libjvm.so`__1cJJavaCallsMcall_virtual6FpnJJavaValue_nGHandle_n ...
libjvm.so`__1cMthread_entry6FpnKJavaThread_pnGThread__v_ + 0x113
libjvm.so`__1cKJavaThreadDrun6M_v_ + 0x2c6
libjvm.so`java_start + 0x1f2
libc.so.1`_thrp_setup + 0x88
libc.so.1`_lwp_start
9
请注意,它同时包含libjvm框架和类/方法:java / net / PlainSocketImpl.available()等。如果没有可见的类/方法,只有十六进制数,则需要首先使jstack()起作用。
不幸的是,存在多个问题。首先,jstack()在许多JVM版本中根本不起作用。有关列表,请参见错误JDK-7187999。幸运的是,对于第一个问题,有一个解决方法,请参见Adam的电子邮件和illumos问题3123中所述,并且最终用法(自他的原始建议以来已更改)涉及在启动Java程序时设置环境变量,从而确保了ustack帮助器已加载。例如:
illumos#LD_AUDIT_32 = / usr / lib / dtrace / libdtrace_forceload.so java myprog
请注意,这可能会增加60秒钟以上的启动时间。(这本身需要性能分析。)
看到的火焰图为SVG或PNG。工作负载为ttcp(测试TCP),这是用Java编写的TCP基准测试。火焰图显示,大多数CPU时间都用在socketWrite()中,而9.2%用在releaseFD()中。
第二个问题是jstack()可能由于2005年提交的JDK-6276264错误而无法正确遍历堆栈,而自2014年以来尚未修复。对于我的生产工作负载,由于此错误,几乎所有采样的堆栈都损坏了。jstack()不可用。
常用的性能优化的工具图
参考:https://www.yuque.com/buermuzi/qz84xg/eltckw