1#!/bin/bash 2# Copyright (C) 2018 The Android Open Source Project 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15set -e 16SCRIPT_DIR="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" 17 18if [ "$TMPDIR" == "" ]; then 19 TMPDIR=/tmp 20fi 21 22function get_gn_value() { 23 local out=$1 24 local key=$2 25 "$SCRIPT_DIR/gn" args "$out" --list=$key --short | awk '{print $3}' \ 26 | tr -d '"' 27} 28 29function is_monolithic() { 30 local out=$1 31 value=$(get_gn_value "$out" "monolithic_binaries") 32 test "$value" == "true" 33} 34 35function is_android() { 36 local out=$1 37 value=$(get_gn_value "$out" "target_os") 38 test "$value" == "android" 39} 40 41function is_ssh_target() { 42 [[ -n "$SSH_TARGET" ]] 43} 44 45function is_mac() { 46 # shellcheck disable=2251 47 ! test -d /proc 48 return $? 49} 50 51function tmux_ensure_bash() { 52 if [[ $SHELL == *"fish" ]]; then 53 tmux send-keys "bash" Enter 54 fi 55} 56 57function reset_tracing() { 58 if is_android "$OUT"; then 59 adb shell 'test -d /sys/kernel/tracing && echo 0 > /sys/kernel/tracing/tracing_on' 60 elif ! is_mac; then 61 # shellcheck disable=SC2016 62 local script=' 63 if [ ! -w /sys/kernel/tracing ]; then 64 echo "tracefs not accessible, try sudo chown -R $USER /sys/kernel/tracing" 65 sudo chown -R "$USER" /sys/kernel/tracing 66 fi 67 68 echo 0 > /sys/kernel/tracing/tracing_on 69 ' 70 71 if is_ssh_target; then 72 # shellcheck disable=SC2029 73 ssh -t "$SSH_TARGET" "sh -c '$script'" 74 else 75 sh -c "$script" 76 fi 77 fi 78} 79 80function adb_supports_push_sync() { 81 adb --help 2>&1 | grep 'push.*\[--sync\]' >/dev/null 2>&1 82} 83 84function push() { 85 if is_android "$OUT"; then 86 local maybe_sync='' 87 if adb_supports_push_sync; then 88 maybe_sync='--sync' 89 fi 90 echo adb push $maybe_sync "$1" "$DIR" 91 adb push $maybe_sync "$1" "$DIR" 92 elif is_ssh_target; then 93 echo scp "$1" "$SSH_TARGET:$DIR" 94 scp "$1" "$SSH_TARGET:$DIR" 95 else 96 echo cp "$1" "$DIR" 97 cp "$1" "$DIR" 98 fi 99} 100 101function pull() { 102 if is_android "$OUT"; then 103 echo adb pull "$DIR/$1" "$2" 104 adb pull "$DIR/$1" "$2" 105 elif is_ssh_target; then 106 echo scp "$SSH_TARGET:$DIR/$1" "$2" 107 scp "$SSH_TARGET:$DIR/$1" "$2" 108 else 109 echo mv "$DIR/$1" "$2" 110 mv "$DIR/$1" "$2" 111 fi 112} 113 114BACKGROUND=0 115SKIP_CONVERTERS=0 116TMUX_LAYOUT="even-vertical" 117CPU_MASK="" 118 119while getopts "bl:nt:c:C:z:s:" o; do 120 case "$o" in 121 b) BACKGROUND=1 ;; 122 l) TMUX_LAYOUT=${OPTARG} ;; 123 n) SKIP_CONVERTERS=1 ;; 124 t) SSH_TARGET=${OPTARG} ;; 125 c) CONFIG=${OPTARG} ;; 126 C) OUT=${OPTARG} ;; 127 z) CPU_MASK=${OPTARG} ;; 128 s) SCRIPT=${OPTARG} ;; 129 *) 130 echo >&2 "Invalid option $o" 131 exit 132 ;; 133 esac 134done 135 136# Allow out to be passed as argument 137shift $((OPTIND - 1)) 138OUT="${OUT:-$1}" 139 140# Provide useful usage information 141if [ -z "$OUT" ]; then 142 echo "Usage: $0 [OPTION]... [OUTPUT]" 143 echo "" 144 echo "Options:" 145 echo " -b run in the background" 146 echo " -l LAYOUT tmux pane layout" 147 echo " -n skip post-trace convertors" 148 echo " -t TARGET SSH device target" 149 echo " -c CONFIG trace configuration file" 150 echo " -C OUTPUT output directory" 151 echo " -z MASK constrain binaries to given cpu mask (taskset syntax)" 152 echo " -s SCRIPT a script to put into a tmux pane" 153 echo "" 154 echo "Environment variables:" 155 echo " SSH_TARGET SSH device target" 156 echo " CONFIG trace configuration file" 157 echo " OUT output directory" 158 exit 1 159fi 160 161# Warn about invalid output directories 162if [ ! -f "$OUT/args.gn" ]; then 163 echo >&2 "OUT=$OUT doesn't look like an output directory." 164 echo >&2 "Please specify a directory by doing:" 165 echo >&2 " export OUT=out/xxx $0" 166 exit 1 167fi 168 169# Check SSH target is valid 170if is_ssh_target && ! ssh -q "$SSH_TARGET" exit; then 171 echo >&2 "SSH_TARGET=$SSH_TARGET doesn't look like a valid SSH target." 172 echo >&2 "Please specify a SSH cross-compilation target by doing:" 173 echo >&2 " export SSH_TARGET=<user>@<host> $0" 174 exit 1 175fi 176 177if ! builtin type -P tmux &>/dev/null; then 178 echo >&2 "tmux not found" 179 exit 1 180fi 181 182# You can set the config to one of the files under test/configs e.g. 183# CONFIG=ftrace.cfg or to :test. Defaults to :test. 184CONFIG="${CONFIG:-:test}" 185 186if is_android "$OUT"; then 187 DIR=/data/local/tmp 188elif is_ssh_target; then 189 DIR=$(ssh "$SSH_TARGET" mktemp -d $TMPDIR/perfetto.XXXXXX) 190elif is_mac; then 191 DIR=$(mktemp -d $TMPDIR/perfetto.XXXXXX) 192else 193 DIR=$(mktemp -p $TMPDIR -d perfetto.XXXXXX) 194fi 195 196if is_android "$OUT"; then 197 TRACECONV="gcc_like_host/traceconv" 198else 199 TRACECONV="traceconv" 200fi 201 202 203# (re)build the binaries 204BUILD_TARGETS=(traced traced_probes perfetto test/configs) 205if [[ SKIP_CONVERTERS -eq 0 ]]; then 206 BUILD_TARGETS+=($TRACECONV) 207fi 208 209"$SCRIPT_DIR/ninja" -C "$OUT" ${BUILD_TARGETS[*]} 210 211push "$OUT/traced" 212push "$OUT/traced_probes" 213push "$OUT/perfetto" 214reset_tracing 215 216if is_android "$OUT"; then 217 PREFIX="PERFETTO_CONSUMER_SOCK_NAME=@perfetto_test_consumer PERFETTO_PRODUCER_SOCK_NAME=@perfetto_test_producer" 218else 219 PREFIX="" 220fi 221 222if ! is_monolithic "$OUT"; then 223 PREFIX="$PREFIX LD_LIBRARY_PATH=$DIR" 224 push "$OUT/libperfetto.so" 225fi 226 227CONFIG_DEVICE_PATH="$CONFIG" 228CMD_OPTS="" 229# Shorthand for using serialized test configs. 230if [[ "$CONFIG" == *.protobuf ]]; then 231 CONFIG_DEVICE_PATH="$CONFIG" 232 CONFIG_PATH=$OUT/$CONFIG 233 if [[ ! -f $CONFIG_PATH ]]; then 234 echo >&2 "Config \"$CONFIG_PATH\" not known." 235 exit 1 236 fi 237 push "$CONFIG_PATH" 238elif [[ "$CONFIG" != ":test" ]]; then 239 CONFIG_DEVICE_PATH="$(basename "$CONFIG")" 240 CONFIG_PATH=$CONFIG 241 # If path isn't valid, assume it's a name of a test config. 242 if [[ ! -f $CONFIG_PATH ]]; then 243 CONFIG_PATH=test/configs/$CONFIG 244 if [[ ! -f $CONFIG_PATH ]]; then 245 echo >&2 "Config \"$CONFIG\" not known." 246 exit 1 247 fi 248 fi 249 CMD_OPTS="--txt $CMD_OPTS" 250 push "$CONFIG_PATH" 251fi 252 253if [[ -f "$SCRIPT" ]]; then 254 push "$SCRIPT" 255fi 256 257POSTFIX="" 258 259if [[ -n "$CPU_MASK" ]]; then 260 PREFIX="$PREFIX taskset $CPU_MASK" 261fi 262 263if [[ BACKGROUND -eq 1 ]]; then 264 PREFIX="$PREFIX nohup" 265 POSTFIX=" &> /dev/null &" 266fi 267 268if tmux has-session -t demo; then 269 tmux kill-session -t demo 270fi 271tmux -2 new-session -d -s demo 272 273if [ ! -z "$ANDROID_ADB_SERVER_PORT" ]; then 274 tmux set-environment -t demo ANDROID_ADB_SERVER_PORT $ANDROID_ADB_SERVER_PORT 275fi 276 277if tmux -V | awk '{split($2, ver, "."); if (ver[1] < 2) exit 1 ; else if (ver[1] == 2 && ver[2] < 1) exit 1 }'; then 278 tmux set-option -g mouse on 279else 280 tmux set-option -g mode-mouse on 281 tmux set-option -g mouse-resize-pane on 282 tmux set-option -g mouse-select-pane on 283 tmux set-option -g mouse-select-window on 284fi 285 286tmux split-window -v 287tmux split-window -v 288 289if [[ -n "$SCRIPT" ]]; then 290 tmux split-window -v 291fi 292 293tmux select-layout "${TMUX_LAYOUT}" 294 295tmux select-pane -t 0 296tmux send-keys "clear" C-m 297if is_android "$OUT"; then 298 tmux send-keys "adb shell" C-m 299fi 300 301tmux select-pane -t 1 302tmux send-keys "clear" C-m 303if is_android "$OUT"; then 304 tmux send-keys "adb shell" C-m 305fi 306 307tmux select-pane -t 2 308tmux send-keys "clear" C-m 309if is_android "$OUT"; then 310 tmux send-keys "adb shell" C-m 311fi 312 313if [[ -n "$SCRIPT" ]]; then 314 tmux select-pane -t 3 315 tmux send-keys "clear" C-m 316 if is_android "$OUT"; then 317 tmux send-keys "adb shell" C-m 318 fi 319fi 320 321sleep 2 322 323tmux select-pane -t 1 324if is_ssh_target; then 325 tmux send-keys "ssh $SSH_TARGET" Enter 326fi 327tmux_ensure_bash 328tmux send-keys "PS1='[traced]$ '" Enter 329tmux send-keys "cd $DIR" Enter 330tmux send-keys "clear" C-m 331tmux send-keys "$PREFIX ./traced $POSTFIX" Enter 332 333tmux select-pane -t 0 334if is_ssh_target; then 335 tmux send-keys "ssh $SSH_TARGET" Enter 336fi 337tmux_ensure_bash 338tmux send-keys "PS1='[traced_probes]$ '" Enter 339tmux send-keys "cd $DIR" Enter 340tmux send-keys "clear" C-m 341tmux send-keys "$PREFIX ./traced_probes $POSTFIX" Enter 342 343tmux select-pane -t 2 344if is_ssh_target; then 345 tmux send-keys "ssh $SSH_TARGET" Enter 346fi 347tmux_ensure_bash 348tmux send-keys "PS1='[consumer]$ '" Enter 349tmux send-keys "cd $DIR" Enter 350tmux send-keys "clear" C-m 351tmux send-keys "$PREFIX ./perfetto $CMD_OPTS -c $CONFIG_DEVICE_PATH -o trace $POSTFIX" 352 353if [[ -n "$SCRIPT" ]]; then 354 tmux select-pane -t 3 355 if is_ssh_target; then 356 tmux send-keys "ssh $SSH_TARGET" Enter 357 fi 358 tmux_ensure_bash 359 tmux send-keys "PS1='[script]$ '" Enter 360 tmux send-keys "cd $DIR" Enter 361 tmux send-keys "clear" C-m 362 if [[ -f "$SCRIPT" ]]; then 363 tmux send-keys "./$(basename "$SCRIPT")" 364 else 365 tmux send-keys "$SCRIPT" 366 fi 367fi 368 369# Select consumer pane. 370tmux select-pane -t 2 371 372tmux -2 attach-session -t demo 373if [[ BACKGROUND -eq 1 ]]; then 374 exit 0 375fi 376 377reset_tracing 378 379TRACE=$TMPDIR/trace 380echo -e "\n\x1b[32mPulling trace into $TRACE.perfetto-trace\x1b[0m" 381pull trace "$TRACE.perfetto-trace" 382 383if [[ SKIP_CONVERTERS -eq 0 ]]; then 384 echo -e "\n\x1b[32mPulling trace into $TRACE.pbtext\x1b[0m" 385 "$OUT/$TRACECONV" text <"$TRACE.perfetto-trace" >"$TRACE.pbtext" 386fi 387