| #!/bin/bash |
| # |
| # |
| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| # |
| # |
| |
| |
| usage() |
| { |
| echo "usage: process.sh <Qpid Version> <Test Type Queue/Topic/Latency..> <Volume of data %age> <broker details>" |
| echo "These parameters are used to title and name the graphs:" |
| echo 'Title = $<Qpid Version> $<Test Type> : $<Volume>% volume' |
| echo 'File = $<Qpid Version>-$<Broker Details>-$<Test Type>-$<Volume>' |
| exit 1 |
| } |
| |
| processCMSGCFile() |
| { |
| # Extract all the ParNew timings: Ignore any lines corrupted by concurrent CMS logging. |
| grep -v CMS gc.log|grep ParNew > $work/parnew.gc.log |
| |
| # Calculate Full GC Data |
| grep failure -B 1 gc.log | sed -e :a -e '$!N;s/\n.(concurrent/ /;ta' -e 'P;D' |grep -v ^\- > $work/full.gc.log |
| cut -d ':' -f 1 $work/full.gc.log > $work/full.time.log |
| sed -e 's/failure)/\#/g' $work/full.gc.log |cut -d '#' -f 2- |awk '{print $3}' > $work/full.dur.log |
| |
| # Move to the working directory to further process the gathered data. |
| pushd $work &> /dev/null |
| |
| # Extract the Heap and timing data. |
| #8 is the full gc data |
| #5 is the paranew gc data |
| cat parnew.gc.log | awk '{print $8}' | cut -d '(' -f 2 | cut -d 'K' -f 1 > HEAP_MAX.log |
| cat parnew.gc.log | awk '{print $8}' | cut -d 'K' -f 1 > HEAP_PRE_GC.log |
| cat parnew.gc.log | awk '{print $8}' | cut -d 'K' -f 2 | cut -d '>' -f 2 > HEAP_POST_GC.log |
| cat parnew.gc.log | awk '{print $1}' | cut -d ':' -f 1 > GC_TIME.log |
| |
| calculateStats "MEM_PRE" HEAP_PRE_GC.log |
| calculateStats "MEM_POST" HEAP_POST_GC.log |
| calculateStatsBC "GC_FREQ" GC_TIME.log |
| |
| |
| # Calculate ParNew GC Cumulative total |
| cat parnew.gc.log |awk '{sum=sum+$6; print $6, sum}' > GC_DUR.log |
| # Give a count of GC occurances |
| parNewGCCount=`wc -l GC_DUR.log| awk '{print $1}'` |
| |
| # Create the Heap data file |
| paste GC_TIME.log HEAP_POST_GC.log HEAP_PRE_GC.log HEAP_MAX.log > GC.Heap.data |
| # Create ParNew GC Duration data file for graphing |
| paste GC_TIME.log GC_DUR.log > GC.Dur.data |
| # Create Full GC occurance log file for plotting |
| paste full.time.log full.dur.log > GC.Full.data |
| |
| # Calculate All GC Timing and give a count of their occurance |
| awk '{print $1}' GC_DUR.log > gc_dur.log |
| paste GC_TIME.log gc_dur.log > gc_all.log |
| cat GC.Full.data >> gc_all.log |
| sort -n gc_all.log | awk '{sum=sum+$2;print $1 , sum}' > GC.Dur.All.data |
| fullGCCount=`wc -l GC.Full.data| awk '{print $1}'` |
| } |
| |
| processG1GCFile() |
| { |
| cat gc.log | grep -e \^[0-9]*.[0-9]*\: -e \^.*[0-9]*.\-\> > $work/g1.gc.log |
| |
| # Move to the working directory to further process the gathered data. |
| pushd $work &> /dev/null |
| |
| # Calculate Full GC Data |
| cat g1.gc.log | sed -e :a -e '$!N;s/\n.\ *\[/ \[/;ta' -e 'P;D' > full.gc.log |
| grep Full full.gc.log |awk '{print $1}'| tr ':' ' ' > full.time.log |
| grep Full full.gc.log |awk '{print $5}' > full.dur.log |
| fullGCCount=`wc -l GC.Full.data| awk '{print $1}'` |
| |
| # Create Full GC occurance log file for plotting |
| paste full.time.log full.dur.log > GC.Full.data |
| |
| # Extract the Heap and timing data. |
| # Create G1 Young Duration data file for graphing |
| grep "(young)," full.gc.log |awk '{print $1}' | tr ':' ' ' > GC_TIME.log |
| grep "(young)," full.gc.log |awk '{print $5}' > young.gc.time.log |
| # Calculate G1 young Cumulative total |
| cat young.gc.time.log |awk '{sum=sum+$1; print $1, sum}' > GC_DUR.log |
| # Create G1 Young Duration data file for graphing |
| paste GC_TIME.log GC_DUR.log > GC.Dur.data |
| |
| # Give a count of GC occurances |
| youngGCCount=`wc -l GC_DUR.log| awk '{print $1}'` |
| |
| # |
| # If we have no GCs then something is wrong |
| if [ $youngGCCount == 0 ] ; then |
| echo "Error no YoungGC log entries to proceses" |
| return |
| fi |
| |
| # Gather the Heap Size data |
| |
| grep "(young)," full.gc.log | awk '{print $8}' | cut -d '(' -f 2 | cut -d ')' -f 1 > HEAP_MAX.Sized.log |
| grep "(young)," full.gc.log | awk '{print $8}' | cut -d '-' -f 1 > HEAP_PRE_GC.Sized.log |
| grep "(young)," full.gc.log | awk '{print $8}' | cut -d '>' -f 2| cut -d '(' -f 1 > HEAP_POST_GC.Sized.log |
| |
| normaliseSizeMemFile HEAP_MAX.Sized.log HEAP_MAX.log |
| normaliseSizeMemFile HEAP_PRE_GC.Sized.log HEAP_PRE_GC.log |
| normaliseSizeMemFile HEAP_POST_GC.Sized.log HEAP_POST_GC.log |
| |
| |
| # Create the Heap data file |
| paste GC_TIME.log HEAP_POST_GC.log HEAP_PRE_GC.log HEAP_MAX.log > GC.Heap.data |
| |
| # Calculate All GC Timing and give a count of their occurance |
| awk '{print $1}' GC_DUR.log > gc_dur.log |
| paste GC_TIME.log gc_dur.log > gc_all.log |
| cat GC.Full.data >> gc_all.log |
| sort -n gc_all.log | awk '{sum=sum+$2;print $1 , sum}' > GC.Dur.All.data |
| |
| } |
| |
| calculateStatsBC() |
| { |
| label=$1 |
| statFile=$2 |
| # Calculate GC Frequencies |
| prevFreq=0 |
| countFreq=0 |
| gcFreqTotal=0 |
| minFreq=99999999 |
| maxFreq=0 |
| |
| echo "" > GC_FREQ.log |
| for time in `cat $statFile` ; do |
| if [ $prevFreq == 0 ] ; then |
| prevFreq=$time |
| else |
| freq=`echo $time - $prevFreq | bc` |
| echo $freq >> GC_FREQ.log |
| |
| prevFreq=$time |
| gcFreqTotal=`echo $gcFreqTotal + $freq | bc` |
| countFreq=$[$countFreq + 1] |
| |
| if [ `echo "$freq > $maxFreq " | bc` == 1 ] ; then |
| maxFreq=$freq |
| fi |
| |
| if [ `echo "$freq < $minFreq " | bc ` == 1 ] ; then |
| minFreq=$freq |
| fi |
| fi |
| done |
| |
| # Extract Min/Max/Avg |
| echo "#type:min/max/avg" > $statFile.stats |
| |
| if [ $countFreq != 0 ] ; then |
| avgFreq=`echo $gcFreqTotal / $countFreq | bc -l 2&> /dev/null` |
| echo "$label:$minFreq/$maxFreq/$avgFreq" >> $statFile.stats |
| echo "Done GC Freq Stat generation for $statFile" |
| else |
| echo "$label:-/-/-" >> $statFile.stats |
| echo "Unable to calculate GC Freq stats as no freq entries found." |
| fi |
| } |
| |
| calculateStats() |
| { |
| label=$1 |
| statFile=$2 |
| |
| # Calculate GC Frequencies |
| count=0 |
| gcTotal=0 |
| min=0 |
| max=0 |
| |
| |
| for item in `cat $statFile` ; do |
| if [ $min == 0 ] ; then |
| min=$item |
| fi |
| |
| gcTotal=$[$gcTotal + $item] |
| count=$[$count + 1] |
| |
| if [ $item -gt $max ] ; then |
| max=$item |
| fi |
| |
| if [ $item -lt $min ] ; then |
| min=$item |
| fi |
| done |
| |
| # Extract Min/Max/Avg |
| echo "#type:min/max/avg" > $statFile.stats |
| |
| if [ $count != 0 ] ; then |
| avg=`echo $gcTotal / $count | bc -l` |
| |
| echo "$label:$min/$max/$avg" >> $statFile.stats |
| echo "Done $label Stat generation for $statFile" |
| else |
| echo "$label:-/-/-" >> $statFile.stats |
| echo "Unable to calculate $label stats as no entries found." |
| fi |
| |
| } |
| |
| # |
| # Take an input file ($1) of lines |
| # <value><K|M> |
| # and output file $2 of <value> in whole M |
| # |
| normaliseSizeMemFile() |
| { |
| rm -f $2 |
| for i in `cat $1` ; do |
| if [[ `echo $i | grep -c "K" ` == 1 ]] ; then |
| kb=`echo $i|cut -d 'K' -f 1` |
| echo $[ $kb / 1024 ] >> $2 |
| else |
| echo $i|cut -d 'M' -f 1 >> $2 |
| fi |
| done |
| |
| |
| } |
| |
| |
| # Parse command line |
| # TODO more advanced processing |
| # Check we have enough parameters |
| if [ $# != 4 ] ; then |
| # Take one arg to be a graph data file. |
| if [ $# == 1 ] ; then |
| textArray[0]="" # hold text |
| length=0 |
| # read whole file in loop |
| while read line |
| do |
| textArray[$length]=$line # store line |
| length=$(expr $length + 1) # increase length by 1 |
| done < $1 |
| |
| if [ $length != 2 ] ; then |
| usage |
| fi |
| |
| #Get Title and file name |
| title=${textArray[0]} |
| file=${textArray[1]} |
| |
| pushd `dirname $1` |
| |
| else |
| usage |
| fi |
| else |
| version=$1 |
| type=$2 |
| volume=$3 |
| brokerState=$4 |
| |
| |
| # Configure Graph Title and image file names |
| title="$version $type : $volume% volume" |
| file="$version-$brokerState-$type-$volume" |
| fi |
| |
| work=work |
| |
| mkdir -p $work |
| |
| echo -n "Processing GC Usage Data : " |
| ParNew=`grep -c ParNew gc.log` |
| |
| if [ $ParNew != 0 ] ; then |
| echo "CMS log file" |
| processCMSGCFile |
| PLOT="\"GC.Dur.data\" with lines axis x1y1 ti \"ParNew GC Time ($parNewGCCount)\", " |
| else |
| echo "G1 log file" |
| processG1GCFile |
| PLOT="\"GC.Dur.data\" with lines axis x1y1 ti \"G1 Young Time ($youngGCCount)\", " |
| fi |
| |
| # |
| # Colate Stats |
| # |
| echo -n "Colating stat Data : " |
| echo "#type:min/max/avg" > $file.statistics.txt |
| find .. -name "*stats" -exec grep -v "type" {} >> $file.statistics.txt \; |
| |
| |
| # Prepare the plot command |
| # If a Full GC occured during this test then plot those |
| if [[ $fullGCCount > 0 ]] ; then |
| PLOT=$PLOT"\"GC.Dur.data\" using 1:3 with lines axis x1y2 ti \"Cumulative Total Time(ParNew)\", \ |
| \"GC.Dur.All.data\" with lines axis x1y2 ti \"Cumulative Total Time(All)\", \ |
| \"GC.Full.data\" with points ti \"Full GCs Time ($fullGCCount)\" " |
| else |
| PLOT=$PLOT"\"GC.Dur.data\" using 1:3 with lines axis x1y2 ti \"Cumulative Total Time(ParNew)\", \ |
| \"GC.Dur.All.data\" with lines axis x1y2 ti \"Cumulative Total Time(All)\" " |
| fi |
| |
| if [ $ParNew != 0 ] ; then |
| gcs=$parNewGCCount |
| else |
| gcs=$youngGCCount |
| fi |
| |
| # Call out to gnuplot to generate graphs |
| # Only do this if we have data |
| if [ $gcs != 0 ] ; then |
| # Generate the Heap Graph and the GC Duration Graph |
| gnuplot << EOGNUPLOT |
| set xlabel "Run Time(s)" |
| |
| set title "$title : Heap Size" |
| set term png |
| set output "$file-Heap.png" |
| set ylabel "MB" +0.5,0 |
| plot "GC.Heap.data" using 1:2 with lines axis x1y1 ti "GC Size Post",\ |
| "GC.Heap.data" using 1:4 with lines axis x1y1 ti "GC Size Max ", \ |
| "GC.Heap.data" using 1:3 with lines axis x1y1 ti "GC Size Pre " |
| |
| set y2tics nomirror |
| set ytics nomirror |
| set key top left |
| set title "$title GC Time" |
| set ylabel "Time(s)" +0.5,0 |
| set y2label "Total Time(s)" |
| set output "$file-GCDuration.png" |
| plot $PLOT |
| EOGNUPLOT |
| |
| else |
| echo "Warning: No GC Data to graph" |
| fi |
| |
| # pop back to further process for CPU usage |
| popd &> /dev/null |
| |
| echo "Processing CPU Usage Data" |
| |
| # CPU.data is just TimeStamp + %age |
| cat broker_cpu.log |awk '{print $1 "T" $2 " " $3}' > $work/CPU.data |
| |
| # Move to work directory to run gnuplot |
| pushd $work &> /dev/null |
| |
| # Call out to gnuplot to generate graphs |
| # Generate the Heap Graph and the GC Duration Graph |
| gnuplot << EOGNUPLOT |
| set term png |
| set title "$title : CPU" |
| set output "$file-CPU.png" |
| unset key |
| set xlabel "Real Time(h:m)" |
| set ylabel "Usage(%)" |
| |
| set xdata time |
| set timefmt "%Y-%m-%dT%H:%M:%S" |
| set format x "%H:%M" |
| plot "CPU.data" using 1:2 with lines |
| EOGNUPLOT |
| |
| #" |
| # Pop out of $work directory. |
| # |
| popd &> /dev/null |