图例 | Java混合模式分析之火焰图实例 - mySoul

/ 0评 / 0

这是小小的第五篇

前言

在进行性能调优的时候,通常会借助性能分析工具,常用的性能分析工具有perf,DTrace,分析系统资源的使用情况,这些情况根据CPU,内存,生成相关的文本数据,这些文本数据不容易直接理解,所以采用火焰图进行分析。用图表的形式展示出来。
本文将会展示具体实例。

火焰图

火焰图有不同的资源和事件类型,包括的主要数据有 CPU,Memory,Off-CPU,Hot/Cold。等等。
下文中,所描述的火焰图指的是CPU的火焰图。

小方块 每个小方块代表一个函数,对应一个栈帧,小方块的宽度表示该函数在采样期间出现的频率,宽度越宽表示出现的频率越高。

栈帧 用于记录函数的活动记录,保存函数局部变量,函数参数等信息。因此想要分析函数调用堆栈关系,这里就需要使用采样得到栈帧信息。

Y 表示函数的调用栈,体现了stack深度,每个垂直方向的顶端小方块表示正在使用CPU的栈的深度。

X 表示采用数据的总量,X表示数据在对调用进行合并之后的结果。根据函数的字母顺序进行排列。X不代表使用CPU的长短,只是说明该方法出现的次数,宽度越宽表示该方法出现的次数越多。X可以直接作为CPU的时间长短。

生成火焰图

采样数据 -> 使用脚本生成
图解如下

工具

火焰图是根据任何包含stack traces 的 profile 数据生成,需要采集stack traces 数据,
列举如下的工具,采集相关的数据

Linux perf_events
Mac DTrace and Instruments
windows Xperf.exe

这里采用的是perf,在Linux系统下实验

安装

sudo yum install perf

生成数据

sudo perf record -F 99 -a -g -- sleep 30

此时会在当前目录下生成perf.data文件。

生成火焰图

sudo perf script | ./stackcollapse-perf.pl | ./flamegraph.pl > out.svg

会自动在当前目录下查找perf.data文件,然后生成svg文件。

然后会自动生成相对应的火焰图

Java混合模式火焰图

安装 perf

perf --version

安装perf-map-agent

安装gcc和gcc-c++

sudo yum install gcc
sudo yum install gcc-c++

安装cmake

sudo mkdir /home/q/perf-tools
cd /home/q/perf-tools/cmake-2.8.6
sudo  ./configure --prefix=/home/q/cmake-2.8.6
sudo make && make install

安装perf-map-agent

git clone https://github.com/jvm-profiling-tools/perf-map-agent
cd /home/q/perf-tools/perf-map-agent
sudo /home/q/cmake-2.8.6/bin/cmake . && sudo make

配置Java选项

JDK >= Java 8 update 60 build 19
参数  **-XX:+PreserveFramePointer**

检查Jdk

java -version

检查JVM

ps wwp `pgrep -n java`|grep PreserveFramePointer  --color

设置 -XX:+PreserveFramePointer

-Xms24g -Xmx24g -server -XX:+DisableExplicitGC -Dqunar.logs=$CATALINA_BASE/logs -Dqunar.cache=$CATALINA_BASE/cache -verbose:gc -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime -XX:+PrintGC -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=1 -Xloggc:$CATALINA_BASE/logs/gc.log -XX:+PrintSafepointStatistics -XX:ReservedCodeCacheSize=512m -XX:CMSInitiatingOccupancyFraction=50 -XX:+UseCMSInitiatingOccupancyOnly -XX:MaxTenuringThreshold=14 -XX:+PreserveFramePointer

安装FlameGraph

git clone https://github.com/brendangregg/FlameGraph.git

生成脚本

sudo ./gen-flame-graph.sh $SLEEP_SECONDS $PID

具体脚本内容

#!/bin/bash
SLEEP_SECONDS=$1
PID=$2
PERF_TOOLS_HOME=$(pwd)
GEN_RESULTS_DIR=$PERF_TOOLS_HOME/gen-flame-graphs-result
AGENT_HOME=$PERF_TOOLS_HOME/perf-map-agent
AGENT_JAR=$AGENT_HOME/attach-main.jar
AGENT_OUT=$AGENT_HOME/out
FLAME_GRAPH_PL_HOME=$PERF_TOOLS_HOME/FlameGraph
FLAME_GRAPH_GENERAGED_FILE=$PERF_TOOLS_HOME/flamegraph-mixed-model-`date +%Y%m%d-%H%M%S`.svg
MAP_FILE=/tmp/perf-$PID.map
function check_env(){
  if [[ ! -x $JAVA_HOME ]]; then
      echo "ERROR: JAVA_HOME not set correctly; edit $0 and fix"
      exit
  fi
  if [[ ! -x $AGENT_HOME ]]; then
      echo $AGENT_HOME
      echo "ERROR: AGENT_HOME not set correctly; edit $0 and fix."
      exit
  fi
  if [[ ! -x $GEN_RESULTS_DIR ]]; then
      echo "ERROR: '$GEN_RESULTS_DIR' not found;Please mkdir a file :'$GEN_RESULTS_DIR'"
      exit
  fi
}
#generate perf.data with command: perf record
function perf_record(){
  echo "Perf record for all processors with sleep 30 seconds."
  cmd_perf="sudo perf record -F 99 -a -g -- sleep 30"
  eval $cmd_perf
  if [[ -e "./perf.data" ]]; then
     echo "SUCCESS: perf.data was generated."
  else
     echo "ERROR: perf.data not generated;edit $0 and fix."
     exit
  fi
}
#agent mapping pid
function gen_map_file(){
  user=$(ps ho user -p $PID)
  echo "Agent mapping PID $PID with user $user"
  cmd_agent="cd $AGENT_HOME;java -cp attach-main.jar:$JAVA_HOME/lib/tools.jar net.virtualvoid.perf.AttachOnce $PID"
  cmd_agent="sudo -u $user sh -c '$cmd_agent'"
  eval $cmd_agent
  if [[ -e "$MAP_FILE" ]]; then
     echo "generate map file"
     chown root $MAP_FILE
     chmod 666 $MAP_FILE
  else
     echo "ERROR: $MAP_FILE not created."
     exit
  fi
}
#generate flame graph
function gen_flame_graph(){
  cmd_stack="sudo perf script|$FLAME_GRAPH_PL_HOME/stackcollapse-perf.pl  --pid|$FLAME_GRAPH_PL_HOME/flamegraph.pl --color=java --width=800 --minwidth=0.5 --title="$PID flame graph"  --hash > $FLAME_GRAPH_GENERAGED_FILE"
  eval $cmd_stack
}
check_env
perf_record
gen_map_file
gen_flame_graph
echo "SUCCESS: generate flame graph."

使用脚本

改脚本是对Java进程的8708采样30s,生成flamegraph-mixed-model-date +%Y%m%d-%H%M%S.svg的Java混合模式火焰图

sudo ./gen-flame-graph.sh 30 8708

生成的图片

发表评论

电子邮件地址不会被公开。 必填项已用*标注