| #!/usr/bin/env bash | |
| # Copyright (C) 2018 The Android Open Source Project | |
| # | |
| # Licensed 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. | |
| set -e | |
| SCRIPT_DIR="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" | |
| if [ "$TMPDIR" == "" ]; then | |
| TMPDIR=/tmp | |
| fi | |
| function get_gn_value() { | |
| local out=$1 | |
| local key=$2 | |
| "$SCRIPT_DIR/gn" args "$out" --list=$key --short | awk '{print $3}' \ | |
| | tr -d '"' | |
| } | |
| function is_monolithic() { | |
| local out=$1 | |
| value=$(get_gn_value "$out" "monolithic_binaries") | |
| test "$value" == "true" | |
| } | |
| function is_android() { | |
| local out=$1 | |
| value=$(get_gn_value "$out" "target_os") | |
| test "$value" == "android" | |
| } | |
| function is_ssh_target() { | |
| [[ -n "$SSH_TARGET" ]] | |
| } | |
| function is_mac() { | |
| # shellcheck disable=2251 | |
| ! test -d /proc | |
| return $? | |
| } | |
| function tmux_ensure_bash() { | |
| if [[ $SHELL == *"fish" ]]; then | |
| tmux send-keys "bash" Enter | |
| fi | |
| } | |
| function reset_tracing() { | |
| if is_android "$OUT"; then | |
| adb shell 'test -d /sys/kernel/tracing && echo 0 > /sys/kernel/tracing/tracing_on' | |
| elif ! is_mac; then | |
| # shellcheck disable=SC2016 | |
| local script=' | |
| if [ ! -w /sys/kernel/tracing ]; then | |
| echo "tracefs not accessible, try sudo chown -R $USER /sys/kernel/tracing" | |
| sudo chown -R "$USER" /sys/kernel/tracing | |
| fi | |
| echo 0 > /sys/kernel/tracing/tracing_on | |
| ' | |
| if is_ssh_target; then | |
| # shellcheck disable=SC2029 | |
| ssh -t "$SSH_TARGET" "sh -c '$script'" | |
| else | |
| sh -c "$script" | |
| fi | |
| fi | |
| } | |
| function adb_supports_push_sync() { | |
| adb --help 2>&1 | grep 'push.*\[--sync\]' >/dev/null 2>&1 | |
| } | |
| function push() { | |
| if is_android "$OUT"; then | |
| local maybe_sync='' | |
| if adb_supports_push_sync; then | |
| maybe_sync='--sync' | |
| fi | |
| echo adb push $maybe_sync "$1" "$DIR" | |
| adb push $maybe_sync "$1" "$DIR" | |
| elif is_ssh_target; then | |
| echo scp "$1" "$SSH_TARGET:$DIR" | |
| scp "$1" "$SSH_TARGET:$DIR" | |
| else | |
| echo cp "$1" "$DIR" | |
| cp "$1" "$DIR" | |
| fi | |
| } | |
| function pull() { | |
| if is_android "$OUT"; then | |
| echo adb pull "$DIR/$1" "$2" | |
| adb pull "$DIR/$1" "$2" | |
| elif is_ssh_target; then | |
| echo scp "$SSH_TARGET:$DIR/$1" "$2" | |
| scp "$SSH_TARGET:$DIR/$1" "$2" | |
| else | |
| echo mv "$DIR/$1" "$2" | |
| mv "$DIR/$1" "$2" | |
| fi | |
| } | |
| BACKGROUND=0 | |
| SKIP_CONVERTERS=0 | |
| TMUX_LAYOUT="even-vertical" | |
| CPU_MASK="" | |
| while getopts "bl:nt:c:C:z:s:" o; do | |
| case "$o" in | |
| b) BACKGROUND=1 ;; | |
| l) TMUX_LAYOUT=${OPTARG} ;; | |
| n) SKIP_CONVERTERS=1 ;; | |
| t) SSH_TARGET=${OPTARG} ;; | |
| c) CONFIG=${OPTARG} ;; | |
| C) OUT=${OPTARG} ;; | |
| z) CPU_MASK=${OPTARG} ;; | |
| s) SCRIPT=${OPTARG} ;; | |
| *) | |
| echo >&2 "Invalid option $o" | |
| exit | |
| ;; | |
| esac | |
| done | |
| # Allow out to be passed as argument | |
| shift $((OPTIND - 1)) | |
| OUT="${OUT:-$1}" | |
| # Provide useful usage information | |
| if [ -z "$OUT" ]; then | |
| echo "Usage: $0 [OPTION]... [OUTPUT]" | |
| echo "" | |
| echo "Options:" | |
| echo " -b run in the background" | |
| echo " -l LAYOUT tmux pane layout" | |
| echo " -n skip post-trace convertors" | |
| echo " -t TARGET SSH device target" | |
| echo " -c CONFIG trace configuration file" | |
| echo " -C OUTPUT output directory" | |
| echo " -z MASK constrain binaries to given cpu mask (taskset syntax)" | |
| echo " -s SCRIPT a script to put into a tmux pane" | |
| echo "" | |
| echo "Environment variables:" | |
| echo " SSH_TARGET SSH device target" | |
| echo " CONFIG trace configuration file" | |
| echo " OUT output directory" | |
| exit 1 | |
| fi | |
| # Warn about invalid output directories | |
| if [ ! -f "$OUT/args.gn" ]; then | |
| echo >&2 "OUT=$OUT doesn't look like an output directory." | |
| echo >&2 "Please specify a directory by doing:" | |
| echo >&2 " export OUT=out/xxx $0" | |
| exit 1 | |
| fi | |
| # Check SSH target is valid | |
| if is_ssh_target && ! ssh -q "$SSH_TARGET" exit; then | |
| echo >&2 "SSH_TARGET=$SSH_TARGET doesn't look like a valid SSH target." | |
| echo >&2 "Please specify a SSH cross-compilation target by doing:" | |
| echo >&2 " export SSH_TARGET=<user>@<host> $0" | |
| exit 1 | |
| fi | |
| if ! builtin type -P tmux &>/dev/null; then | |
| echo >&2 "tmux not found" | |
| exit 1 | |
| fi | |
| # You can set the config to one of the files under test/configs e.g. | |
| # CONFIG=ftrace.cfg or to :test. Defaults to :test. | |
| CONFIG="${CONFIG:-:test}" | |
| if is_android "$OUT"; then | |
| DIR=/data/local/tmp | |
| elif is_ssh_target; then | |
| DIR=$(ssh "$SSH_TARGET" mktemp -d $TMPDIR/perfetto.XXXXXX) | |
| elif is_mac; then | |
| DIR=$(mktemp -d $TMPDIR/perfetto.XXXXXX) | |
| else | |
| DIR=$(mktemp -p $TMPDIR -d perfetto.XXXXXX) | |
| fi | |
| if is_android "$OUT"; then | |
| TRACECONV="gcc_like_host/traceconv" | |
| else | |
| TRACECONV="traceconv" | |
| fi | |
| # (re)build the binaries | |
| BUILD_TARGETS=(traced traced_probes perfetto test/configs) | |
| if [[ SKIP_CONVERTERS -eq 0 ]]; then | |
| BUILD_TARGETS+=($TRACECONV) | |
| fi | |
| "$SCRIPT_DIR/ninja" -C "$OUT" ${BUILD_TARGETS[*]} | |
| push "$OUT/traced" | |
| push "$OUT/traced_probes" | |
| push "$OUT/perfetto" | |
| reset_tracing | |
| if is_android "$OUT"; then | |
| PREFIX="PERFETTO_CONSUMER_SOCK_NAME=@perfetto_test_consumer PERFETTO_PRODUCER_SOCK_NAME=@perfetto_test_producer" | |
| else | |
| PREFIX="" | |
| fi | |
| if ! is_monolithic "$OUT"; then | |
| PREFIX="$PREFIX LD_LIBRARY_PATH=$DIR" | |
| push "$OUT/libperfetto.so" | |
| fi | |
| CONFIG_DEVICE_PATH="$CONFIG" | |
| CMD_OPTS="" | |
| # Shorthand for using serialized test configs. | |
| if [[ "$CONFIG" == *.protobuf ]]; then | |
| CONFIG_DEVICE_PATH="$CONFIG" | |
| CONFIG_PATH=$OUT/$CONFIG | |
| if [[ ! -f $CONFIG_PATH ]]; then | |
| echo >&2 "Config \"$CONFIG_PATH\" not known." | |
| exit 1 | |
| fi | |
| push "$CONFIG_PATH" | |
| elif [[ "$CONFIG" != ":test" ]]; then | |
| CONFIG_DEVICE_PATH="$(basename "$CONFIG")" | |
| CONFIG_PATH=$CONFIG | |
| # If path isn't valid, assume it's a name of a test config. | |
| if [[ ! -f $CONFIG_PATH ]]; then | |
| CONFIG_PATH=test/configs/$CONFIG | |
| if [[ ! -f $CONFIG_PATH ]]; then | |
| echo >&2 "Config \"$CONFIG\" not known." | |
| exit 1 | |
| fi | |
| fi | |
| CMD_OPTS="--txt $CMD_OPTS" | |
| push "$CONFIG_PATH" | |
| fi | |
| if [[ -f "$SCRIPT" ]]; then | |
| push "$SCRIPT" | |
| fi | |
| POSTFIX="" | |
| if [[ -n "$CPU_MASK" ]]; then | |
| PREFIX="$PREFIX taskset $CPU_MASK" | |
| fi | |
| if [[ BACKGROUND -eq 1 ]]; then | |
| PREFIX="$PREFIX nohup" | |
| POSTFIX=" &> /dev/null &" | |
| fi | |
| if tmux has-session -t demo; then | |
| tmux kill-session -t demo | |
| fi | |
| tmux -2 new-session -d -s demo | |
| if [ ! -z "$ANDROID_ADB_SERVER_PORT" ]; then | |
| tmux set-environment -t demo ANDROID_ADB_SERVER_PORT $ANDROID_ADB_SERVER_PORT | |
| fi | |
| if tmux -V | awk '{split($2, ver, "."); if (ver[1] < 2) exit 1 ; else if (ver[1] == 2 && ver[2] < 1) exit 1 }'; then | |
| tmux set-option -g mouse on | |
| else | |
| tmux set-option -g mode-mouse on | |
| tmux set-option -g mouse-resize-pane on | |
| tmux set-option -g mouse-select-pane on | |
| tmux set-option -g mouse-select-window on | |
| fi | |
| tmux split-window -v | |
| tmux split-window -v | |
| if [[ -n "$SCRIPT" ]]; then | |
| tmux split-window -v | |
| fi | |
| tmux select-layout "${TMUX_LAYOUT}" | |
| tmux select-pane -t 0 | |
| tmux send-keys "clear" C-m | |
| if is_android "$OUT"; then | |
| tmux send-keys "adb shell" C-m | |
| fi | |
| tmux select-pane -t 1 | |
| tmux send-keys "clear" C-m | |
| if is_android "$OUT"; then | |
| tmux send-keys "adb shell" C-m | |
| fi | |
| tmux select-pane -t 2 | |
| tmux send-keys "clear" C-m | |
| if is_android "$OUT"; then | |
| tmux send-keys "adb shell" C-m | |
| fi | |
| if [[ -n "$SCRIPT" ]]; then | |
| tmux select-pane -t 3 | |
| tmux send-keys "clear" C-m | |
| if is_android "$OUT"; then | |
| tmux send-keys "adb shell" C-m | |
| fi | |
| fi | |
| sleep 2 | |
| tmux select-pane -t 1 | |
| if is_ssh_target; then | |
| tmux send-keys "ssh $SSH_TARGET" Enter | |
| fi | |
| tmux_ensure_bash | |
| tmux send-keys "PS1='[traced]$ '" Enter | |
| tmux send-keys "cd $DIR" Enter | |
| tmux send-keys "clear" C-m | |
| tmux send-keys "$PREFIX ./traced $POSTFIX" Enter | |
| tmux select-pane -t 0 | |
| if is_ssh_target; then | |
| tmux send-keys "ssh $SSH_TARGET" Enter | |
| fi | |
| tmux_ensure_bash | |
| tmux send-keys "PS1='[traced_probes]$ '" Enter | |
| tmux send-keys "cd $DIR" Enter | |
| tmux send-keys "clear" C-m | |
| tmux send-keys "$PREFIX ./traced_probes $POSTFIX" Enter | |
| tmux select-pane -t 2 | |
| if is_ssh_target; then | |
| tmux send-keys "ssh $SSH_TARGET" Enter | |
| fi | |
| tmux_ensure_bash | |
| tmux send-keys "PS1='[consumer]$ '" Enter | |
| tmux send-keys "cd $DIR" Enter | |
| tmux send-keys "clear" C-m | |
| tmux send-keys "$PREFIX ./perfetto $CMD_OPTS -c $CONFIG_DEVICE_PATH -o trace $POSTFIX" | |
| if [[ -n "$SCRIPT" ]]; then | |
| tmux select-pane -t 3 | |
| if is_ssh_target; then | |
| tmux send-keys "ssh $SSH_TARGET" Enter | |
| fi | |
| tmux_ensure_bash | |
| tmux send-keys "PS1='[script]$ '" Enter | |
| tmux send-keys "cd $DIR" Enter | |
| tmux send-keys "clear" C-m | |
| if [[ -f "$SCRIPT" ]]; then | |
| tmux send-keys "./$(basename "$SCRIPT")" | |
| else | |
| tmux send-keys "$SCRIPT" | |
| fi | |
| fi | |
| # Select consumer pane. | |
| tmux select-pane -t 2 | |
| tmux -2 attach-session -t demo | |
| if [[ BACKGROUND -eq 1 ]]; then | |
| exit 0 | |
| fi | |
| reset_tracing | |
| TRACE=$TMPDIR/trace | |
| echo -e "\n\x1b[32mPulling trace into $TRACE.perfetto-trace\x1b[0m" | |
| pull trace "$TRACE.perfetto-trace" | |
| if [[ SKIP_CONVERTERS -eq 0 ]]; then | |
| echo -e "\n\x1b[32mPulling trace into $TRACE.pbtext\x1b[0m" | |
| "$OUT/$TRACECONV" text <"$TRACE.perfetto-trace" >"$TRACE.pbtext" | |
| fi |