perf
安装(需要安装perl)
yum install perf
使用
perf top -p 进程号
但是这样看起来比较难受,没有图表,因此有人发明了火焰图,便于分析进程占用的CPU,见下文
FlameGraph
下载源码(无须安装,建议创建软链接)
https://github.com/brendangregg/FlameGraph
使用方法
# 进程号是pid,秒数是采集时间
perf record -F 99 -p 进程号 -g -- sleep 秒数
# 下面这个命令可以直接查看采集的数据,但是不友好
# perf report -n --stdio
# 生成perf文件
perf script > out.perf
# 生成folded文件 (pl文件在上面下载的FlameGraph根目录下)
FlameGraph-master/stackcollapse-perf.pl out.perf > out.folded
# 生成svg文件,也就是火焰图文件 (建议使用chrome打开,ie打开有问题,ctrl + f 可以正则搜索)
FlameGraph-master/flamegraph.pl out.folded > kernel.svg
如果想监控java,需要再安装一套东西 ,见下文
perf-map-agent
下载地址
安装(需要java环境)
# 安装环境,需要先安装gcc-c++,以及cmake,yum就能安装
yum install gcc-c++
yum install cmake
# yum install java-1.8.0-openjdk
yum install java-1.8.0-openjdk-devel
# java_home根据实际情况配置
export JAVA_HOME=/usr/lib/jvm/java-openjdk/
# 安装perf-map-agent
cmake .
make
# 创建软链接(但是不全)
bin/create-links-in /usr/local/bin
可选安装 dtrace
Oracle Linux 7 (x86_64) UEK Release 6 | Oracle, Software. Hardware. Complete.
下载 dtrace-2.0.0-1.9.1.el7.x86_64 和 libdtrace-ctf-1.1.0-2.el7.x86_64 的rpm并安装
配置FlameGraph目录(不配置无法使用perf-java-flame)
export FLAMEGRAPH_DIR=/root/FlameGraph-master
永久配置需要写入 ~/.bashrc
不配置可能报错
FlameGraph executable not found at '/stackcollapse-perf.pl'. Please set FLAMEGRAPH_DIR to the root of the clone of https://github.com/brendangregg/FlameGraph.
使用perf-map-agent (火焰图方法,其他方法可以百度)
# !!!! 被监控进程需要加入java启动参数 -XX:+PreserveFramePointer 不然啥也看不见
# 默认收集15秒,如果要修改默认收集时间,参考下面注释
# export PERF_RECORD_SECONDS=60
perf-java-flames 进程号
使用中可能遇到的错误:
没安装java可能会报错(实际上是没安装javah,即java-1.8.0-openjdk-devel)
-- Could NOT find JNI (missing: JAVA_INCLUDE_PATH JAVA_INCLUDE_PATH2 JAVA_AWT_INCLUDE_PATH)
CMake Error at /usr/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:108 (message):
Could NOT find Java (missing: Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE
Java_JAVAH_EXECUTABLE Java_JAVADOC_EXECUTABLE) (found version "1.8.0.322")
Call Stack (most recent call first):
/usr/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:315 (_FPHSA_FAILURE_MESSAGE)
/usr/share/cmake/Modules/FindJava.cmake:191 (find_package_handle_standard_args)
CMakeLists.txt:23 (find_package)
其实关键是这句 (missing: Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE
Java_JAVAH_EXECUTABLE Java_JAVADOC_EXECUTABLE) ,找不到javac,javah等,只要指定了JAVA_HOME即可(前提装了java)
export JAVA_HOME=/usr/lib/jvm/java-openjdk/
# 前提是这个java_home的bin目录下有javah,javac等应用程序
没指定java_home还可能报错(没有tools.jar)
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/tools/attach/AgentInitializationException
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
at java.lang.Class.getMethod0(Class.java:3018)
at java.lang.Class.getMethod(Class.java:1784)
at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:650)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:632)
Caused by: java.lang.ClassNotFoundException: com.sun.tools.attach.AgentInitializationException
at java.net.URLClassLoader.findClass(URLClassLoader.java:387)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
... 7 more
我看有人用指定tools.jar解决,一般来说指定java_home就能解决,如果还没解决,看看是不是权限不对
-Xbootclasspath/a:/usr/lib/jvm/java-openjdk/lib/tools.jar
cmake可能报错
-- Could NOT find JNI (missing: JAVA_AWT_LIBRARY JAVA_JVM_LIBRARY)
-- Configuring done
-- Generating done
-- Build files have been written to: /root/perf-map-agent-master
我还以为是java_home配置错了,结果是因为我的java_home里的jre文件夹名称不对,我的jre文件夹的名称叫做jre1.8.0_151,而实际上cmake只认识jre这个名称,我把jre1.8.0_151改名jre成功解决
如果报错这个
ERROR: No stack counts found
可能是java程序没跑什么东西,拿不到样本
cmake安装有问题可能报错(gcc没装好)
-- The C compiler identification is GNU 4.8.5
-- The CXX compiler identification is GNU 4.8.5
-- Check for working C compiler: /bin/cc
-- Check for working C compiler: /bin/cc -- broken
CMake Error at /usr/share/cmake/Modules/CMakeTestCCompiler.cmake:61 (message):
The C compiler "/bin/cc" is not able to compile a simple test program.
It fails with the following output:
Change Dir: /root/perf-map-agent-master/CMakeFiles/CMakeTmp
Run Build Command:/bin/gmake "cmTryCompileExec1466212255/fast"
/bin/gmake -f CMakeFiles/cmTryCompileExec1466212255.dir/build.make
CMakeFiles/cmTryCompileExec1466212255.dir/build
gmake[1]: Entering directory
`/root/perf-map-agent-master/CMakeFiles/CMakeTmp'
/usr/bin/cmake -E cmake_progress_report
/root/perf-map-agent-master/CMakeFiles/CMakeTmp/CMakeFiles 1
Building C object
CMakeFiles/cmTryCompileExec1466212255.dir/testCCompiler.c.o
/bin/cc -o CMakeFiles/cmTryCompileExec1466212255.dir/testCCompiler.c.o -c
/root/perf-map-agent-master/CMakeFiles/CMakeTmp/testCCompiler.c
Linking C executable cmTryCompileExec1466212255
/usr/bin/cmake -E cmake_link_script
CMakeFiles/cmTryCompileExec1466212255.dir/link.txt --verbose=1
/bin/cc CMakeFiles/cmTryCompileExec1466212255.dir/testCCompiler.c.o -o
cmTryCompileExec1466212255 -rdynamic
collect2: fatal error: cannot find 'ld'
compilation terminated.
gmake[1]: Leaving directory
`/root/perf-map-agent-master/CMakeFiles/CMakeTmp'
gmake[1]: *** [cmTryCompileExec1466212255] Error 1
gmake: *** [cmTryCompileExec1466212255/fast] Error 2
CMake will not be able to correctly generate this project.
Call Stack (most recent call first):
CMakeLists.txt:2 (project)
-- Configuring incomplete, errors occurred!
See also "/root/perf-map-agent-master/CMakeFiles/CMakeOutput.log".
See also "/root/perf-map-agent-master/CMakeFiles/CMakeError.log".
上述问题我使用gcc随便编译代码也报错
# gcc -o a.out a.c
collect2: fatal error: cannot find 'ld'
compilation terminated.
于是使用下面方法解决
yum update binutils
perf-java-flames 运行可能报错
Exception in thread "main" java.lang.UnsatisfiedLinkError: no attach in java.library.path
at java.lang.ClassLoader.loadLibrary(Unknown Source)
at java.lang.Runtime.loadLibrary0(Unknown Source)
at java.lang.System.loadLibrary(Unknown Source)
at sun.tools.attach.LinuxVirtualMachine.<clinit>(LinuxVirtualMachine.java:342)
at sun.tools.attach.LinuxAttachProvider.attachVirtualMachine(LinuxAttachProvider.java:63)
at com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:208)
at net.virtualvoid.perf.AttachOnce.loadAgent(AttachOnce.java:38)
at net.virtualvoid.perf.AttachOnce.main(AttachOnce.java:34)
说明jdk的版本和tools.jar不匹配
perf-java-flames 运行可能报错
Couldn't record kernel reference relocation symbol
Symbol resolution may be skewed if relocation was used (e.g. kexec).
Check /proc/kallsyms permission or run as root.
解决办法
echo 0 > /proc/sys/kernel/kptr_restrict
cat /proc/sys/kernel/kptr_restrict
perf-java-flames 运行可能报错
Error: Could not find or load main class net.virtualvoid.perf.AttachOnce
解决办法
# 然后检查所起的java程序的用户,有没有perf-map-agent和FlameGraph目录的权限(我Tomcat起的java程序,然后那两个目录被我放在了root下)
chmod -R 777 /root/
还可能报错(未解决,我换了其他java程序是正常跑的,这个不知道为什么)
Exception in thread "main" com.sun.tools.attach.AttachNotSupportedException: Unable to open socket file: target process not responding or HotSpot VM not loaded
at sun.tools.attach.LinuxVirtualMachine.<init>(LinuxVirtualMachine.java:106)
at sun.tools.attach.LinuxAttachProvider.attachVirtualMachine(LinuxAttachProvider.java:63)
at com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:208)
at net.virtualvoid.perf.AttachOnce.loadAgent(AttachOnce.java:38)
at net.virtualvoid.perf.AttachOnce.main(AttachOnce.java:34)
说说自己对火焰图的理解
x轴:CPU占用时间,非时间顺序轴
y轴:堆栈调用深度
上图我是拿excl表格生成的,从上图看e函数和d函数吃CPU的时间最长,剩下时间被f函数和c函数吃完,a函数和b函数只是当了跳板,并未实际吃到CPU,真正的CPU时间应该被其上面的函数吃完