#!/bin/bash
#
# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# Start / stop profiling in chrome.

# The profiling data is saved to directory /sdcard/Download. The files
# are named beginning chrome-profile-results-
#
# Assumes you have sourced the android build environment script
# (e.g. 'adb' is on your path).
set -e

usage() {
  echo "adb_profile_chrome [--start [-o file] [-c C]|--stop|-d|-t N] [-v N]"
  echo "See http://dev.chromium.org/developers/how-tos/trace-event-profiling-tool for detailed instructions on profiling."
  echo ""
  echo "  --start            Start profiling."
  echo "  --output|-o file   Save profile output to file. "
  echo "                     (Default is /sdcard/Download/chrome-profile-results-*)"
  echo "  --categories|-c C  Select categories to trace with comma-delimited wildcards."
  echo "                     e.g. '*', 'cat1*,-cat1a'. Default is '*'."
  echo "  --continuous       Using the trace buffer as a ring buffer, continuously"
  echo "                     profile until stopped."
  echo "  --stop             Stop profiling."
  echo "  --download|-d      Download latest trace."
  echo "  --time|-t N        Profile for N seconds and download the resulting trace."
  echo "  --version|v N      Select among installed browsers."
  echo "                     One of stable (default), beta, dev, build"
  echo ""
  echo "Profiling data is saved to the device."
  exit 0
}

send_intent() {
  local PACKAGE=$1
  local INTENT=$2
  shift
  shift
  adb shell am broadcast -a $PACKAGE.$INTENT $*
}

download_latest_trace() {
  (adb logcat -d | grep -q "Logging performance trace to file") || {
    echo "WARNING: Trace start marker not found. Is the correct version of Chrome running?"
  }

  local ITERATION=0
  while true; do
    # Chrome logs two different messages related to tracing:
    #
    # 1. "Logging performance trace to file [...]"
    # 2. "Profiler finished. Results are in [...]"
    #
    # The first one is printed when tracing starts and the second one indicates
    # that the trace file is ready to be downloaded.
    #
    # We have to look for both of these messages to make sure we get the results
    # from the latest trace and that the trace file is complete. This is done by
    # first looking for the last instance of the first message and then checking
    # for the second message in the remaining part of the log.
    TRACE_FILE=$(adb logcat -d | \
        tac | \
        grep --max-count=1 --before-context=100000 "Logging performance trace to file" | \
        tac | \
        grep "Profiler finished[.] Results are in " | \
        perl -pi -e "s{.*/storage/emulated/.+/([^\r]+)[.].*}{/sdcard/Download/\\1}g")
    if [ -n "$TRACE_FILE" ]; then
      break
    fi
    if [ $ITERATION -eq 0 ]; then
      echo -n "Waiting for Chrome to finish tracing..."
    else
      echo -n "."
    fi
    let ITERATION=ITERATION+1
    if [ $ITERATION -eq 60 ]; then
      echo "Timed out"
      exit 1
    fi
    sleep 1
  done

  adb pull $TRACE_FILE 2> /dev/null
  LOCAL_TRACE_FILE=$(basename $TRACE_FILE)
  if [ ! -f "$LOCAL_TRACE_FILE" ]; then
    echo "Unable to download trace file"
    exit 1
  fi
}

do_timed_capture() {
  local PACKAGE=$1
  local INTERVAL=$2
  shift
  shift
  echo -n "Capturing trace..."
  send_intent ${PACKAGE} "GPU_PROFILER_START" $* > /dev/null
  sleep ${INTERVAL}
  send_intent ${PACKAGE} "GPU_PROFILER_STOP" > /dev/null
  echo "done"

  echo -n "Downloading trace..."
  sleep $[${INTERVAL} / 4 + 1]
  download_latest_trace
  echo "done"

  echo "Trace written to ${PWD}/${LOCAL_TRACE_FILE}"
}

PACKAGE=${DEFAULT_PACKAGE:-com.android.chrome}

while test -n "$1"; do
  case "$1" in
    -v|--version)
      if [[ -z "$2" ]] ; then
        usage
      fi
      shift
      case "$1" in
        stable) PACKAGE="com.android.chrome" ;;
        beta) PACKAGE="com.chrome.beta" ;;
        dev) PACKAGE="com.google.android.apps.chrome_dev" ;;
        build) PACKAGE="com.google.android.apps.chrome" ;;
        *) usage ;;
      esac
      ;;
    --start) FUNCTION="GPU_PROFILER_START" ;;
    --stop) FUNCTION="GPU_PROFILER_STOP" ;;
    -o|--output)
      if [ -z "$2" ] ; then
        usage
      fi
      OUTPUT="-e file '$2'"
      shift
      ;;
    -c|--categories)
      if [ -z "$2" ]; then
        usage
      fi
      CATEGORIES="-e categories '$2'"
      shift
      ;;
    --continuous) CONTINUOUS="-e continuous ." ;;
    -t|--time)
      shift
      if [ -z "$1" ] ; then
        usage
      fi
      INTERVAL="$1"
      ;;
    -d|--download)
      shift
      download_latest_trace
      echo "Trace written to ${PWD}/${LOCAL_TRACE_FILE}"
      ;;
    *) usage ;;
  esac
  shift
done

if [ -z "${INTERVAL}" ] ; then
  if [ -z "${FUNCTION}" ] ; then
    usage
  else
    send_intent ${PACKAGE} ${FUNCTION} ${OUTPUT} ${CATEGORIES} ${CONTINUOUS}
  fi
else
  do_timed_capture ${PACKAGE} ${INTERVAL} ${CATEGORIES} ${CONTINUOUS}
fi
exit 0
