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