#!/bin/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 'echo 0 > /d/tracing/tracing_on' elif ! is_mac; then # shellcheck disable=SC2016 local script=' if [ ! -w /sys/kernel/debug ]; then echo "debugfs not accessible, try sudo chown -R $USER /sys/kernel/debug" sudo chown -R "$USER" /sys/kernel/debug fi echo 0 > /sys/kernel/debug/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=@ $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 # (re)build the binaries BUILD_TARGETS=(traced traced_probes perfetto test/configs) if [[ SKIP_CONVERTERS -eq 0 ]]; then BUILD_TARGETS+=(trace_to_text) 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.protobuf\x1b[0m" pull trace "$TRACE.protobuf" if [[ SKIP_CONVERTERS -eq 0 ]]; then echo -e "\n\x1b[32mPulling trace into $TRACE.pbtext\x1b[0m" "$OUT/trace_to_text" text <"$TRACE.protobuf" >"$TRACE.pbtext" echo -e "\n\x1b[32mPulling trace into $TRACE.json\x1b[0m" "$OUT/trace_to_text" systrace <"$TRACE.protobuf" >"$TRACE.json" # Keep this last so it can fail. fi