#!/bin/bash
set -e

script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)

let capture_freq=99
reverse=

# search replace filter that will combine thread names like
# GC-Thread-1 to GC-Thread- in perf-script sample header lines.
sr_filter='s/^([a-zA-Z\-]+)[0-9]*-?([a-zA-z]*) (.*?)$/\1\2 \3/g'

help_msg() {
 echo "Requires perf to be installed and in your PATH"
 echo "usage: $0 oncpu|offcpu|<custom_event> [time seconds|default 300] --f|--frequency 99 -R|--Reverse -r|--regexfilter 's/hi/bye/g'"
 echo "custom_event is any event listed in perf-list"
}

process_perf_data () {
  perf inject -j -i perf.data -o perf.data.jit
  perf script -f -i perf.data.jit > script.out
  if [[ ! -z "${sr_filter}" ]]; then
    perl -pi -e "${sr_filter}" script.out
  fi
  "$script_dir/FlameGraph/stackcollapse-perf.pl" --kernel --jit script.out > folded.out
  "$script_dir/FlameGraph/flamegraph.pl" ${reverse:+--reverse} --colors java folded.out > flamegraph_$1_$4_$3_$2.svg
  rm perf.data perf.data.jit script.out folded.out
}

capture_on_cpu () {
  perf record -a -g -k 1 -F${capture_freq} -e cpu-clock:pppH -- sleep $1
  process_perf_data "oncpu" $2 $3 $4
}

capture_off_cpu () {
  perf record -a -g -k 1 -F${capture_freq} -e sched:sched_switch -- sleep $1
  process_perf_data "offcpu" $2 $3 $4
}

capture_custom_event () {
  perf record -a -g -k 1 -F${capture_freq} -e $1 -- sleep $2
  process_perf_data $1 $3 $4 $5
}

if [[ $(id -u) -ne 0 ]]; then
  echo "Must be run with sudo privileges"
  exit 1
fi

# Test perf exists
test_perf=$(perf list &> /dev/null)
if [[ $? -ne 0 ]]; then
  help_msg
  exit 1
fi

POSITIONAL=()
while [[ $# -gt 0 ]]
do
  key="$1"
  case $key in
    -f|--frequency)
      let capture_freq="$2"
      shift; shift
      ;;
    -r|--regexfilter)
      sr_filter="$2"
      shift; shift
      ;;
    -R|--Reverse)
      let reverse=1
      shift;
      ;;
    -h|--help)
      help_msg
      exit 1
      ;;
    *)
      POSITIONAL+=("$1")
      shift
      ;;
  esac
done
set -- "${POSITIONAL[@]}"

if [[ $# -lt 1 ]]; then
  help_msg
  exit 1
fi

capture_time=300
if [[ $# -gt 1 ]]; then
  capture_time=$2
fi

date=$(date "+%Y-%m-%d_%H:%M:%S")
# Try to get meta-data using IMDSv2
if token=$(curl --max-time 1 -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") ; then
  instance_type=$(curl -s -H "X-aws-ec2-metadata-token: $token" http://169.254.169.254/latest/meta-data/instance-type)
  instance_id=$(curl -s -H "X-aws-ec2-metadata-token: $token" http://169.254.169.254/latest/meta-data/instance-id)
else
  instance_type="unknown"
  instance_id="unknown"
fi

if [[ "$1" == "oncpu" ]]; then
  capture_on_cpu $capture_time $date $instance_type $instance_id
elif [[ "$1" == "offcpu" ]]; then
  capture_off_cpu $capture_time $date $instance_type $instance_id
else
  capture_custom_event $1 $capture_time $date $instance_type $instance_id
fi
