#!/bin/sh # # Tool for running a suspend/resume on android # Copyright (c) 2014, Intel Corporation. # # This program is free software; you can redistribute it and/or modify it # under the terms and conditions of the GNU General Public License, # version 2, as published by the Free Software Foundation. # # This program is distributed in the hope it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. # # You should have received a copy of the GNU General Public License along with # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. # # Authors: # Todd Brandt # KVERSION="" MODES="" MODE="mem" RTCPATH="" TPATH="/sys/kernel/debug/tracing" EPATH="/sys/kernel/debug/tracing/events/power" FTRACECHECK="yes" TRACEEVENTS="yes" HEADER="" FTRACE="ftrace.txt" DMESG="dmesg.txt" LOGFILE="log.txt" WAKETIME="" DISPLAY="" checkDisplay() { SCRSTAT=`dumpsys power 2>&1 | grep mScreenOn` if [ -n "$SCRSTAT" ]; then for i in $SCRSTAT; do break; done if [ $i = "mScreenOn=false" ]; then DISPLAY="OFF" else DISPLAY="ON" fi fi } checkFileRead() { if [ ! -e $1 ]; then onError "$1 not found" fi if [ ! -r $1 ]; then onError "$1 not readable" fi } checkFileWrite() { if [ ! -e $1 ]; then onError "$1 not found" fi if [ ! -w $1 ]; then onError "$1 not writeable" fi } writeToSysFile() { if [ ! -e $1 ]; then onError "$1 not found" fi if [ ! -w $1 ]; then onError "$1 not writeable" fi echo "$2" > "$1" logEntry "$1 = \"$2\"" } checkStatus() { CHECK="no" for m in $MODES; do if [ $m = "$MODE" ]; then CHECK="yes" fi done if [ $CHECK != "yes" ]; then onError "mode ($MODE) is not supported" fi if [ $FTRACECHECK != "yes" ]; then echo " ERROR: ftrace is unsupported {" echo " Please rebuild the kernel with these config options:" echo " CONFIG_FTRACE=y" echo " CONFIG_FUNCTION_TRACER=y" echo " CONFIG_FUNCTION_GRAPH_TRACER=y" echo " }" exit fi if [ $TRACEEVENTS != "yes" ]; then echo " ERROR: trace events missing {" echo " Please rebuild the kernel with the proper config patches" echo " https://github.com/intel/pm-graph/tree/master/config" echo " }" exit fi if [ -n "$WAKETIME" -a -z "$RTCPATH" ]; then onError "rtcwake isn't available" fi if [ ! -w $PWD ]; then onError "read-only permissions for this folder" fi } printStatus() { echo "host : $HOSTNAME" echo "kernel : $KVERSION" echo "modes : $MODES" checkDisplay if [ -n "$DISPLAY" ]; then echo "display : $DISPLAY" fi if [ -n "$RTCPATH" ]; then echo "rtcwake : SUPPORTED" else echo "rtcwake : NOT SUPPORTED (no rtc wakealarm found)" fi if [ $FTRACECHECK != "yes" ]; then echo " ftrace: NOT SUPPORTED (this is bad) {" echo " Please rebuild the kernel with these config options:" echo " CONFIG_FTRACE=y" echo " CONFIG_FUNCTION_TRACER=y" echo " CONFIG_FUNCTION_GRAPH_TRACER=y" echo " }" else echo "ftrace : SUPPORTED" echo "trace events {" files="suspend_resume device_pm_callback_end device_pm_callback_start" for f in $files; do if [ -e "$EPATH/$f" ]; then echo " $f: FOUND" else echo " $f: MISSING" fi done if [ $TRACEEVENTS != "yes" ]; then echo "" echo " one or more trace events missing!" echo " Please rebuild the kernel with the proper config patches" echo " https://github.com/intel/pm-graph/tree/master/config" fi echo "}" fi if [ $FTRACECHECK = "yes" -a $TRACEEVENTS = "yes" ]; then echo "status : GOOD (you can test suspend/resume)" else echo "status : BAD (system needs to be reconfigured for suspend/resume)" fi } init() { if [ -z "$HOSTNAME" ]; then HOSTNAME=`hostname 2>/dev/null` fi checkFileRead "/proc/version" # sometimes awk and sed are missing for i in `cat /proc/version`; do if [ $i != "Linux" -a $i != "version" ]; then KVERSION=$i break fi done checkFileRead "/sys/power/state" MODES=`cat /sys/power/state` RTCPATH="/sys/class/rtc/rtc0" if [ -e "$RTCPATH" ]; then if [ ! -e "$RTCPATH" -o ! -e "$RTCPATH/since_epoch" -o \ ! -e "$RTCPATH/wakealarm" ]; then RTCPATH="" fi fi files="buffer_size_kb current_tracer trace trace_clock trace_marker \ trace_options tracing_on available_filter_functions \ set_ftrace_filter set_graph_function" for f in $files; do if [ ! -e "$TPATH/$f" ]; then FTRACECHECK="no" fi done files="suspend_resume device_pm_callback_end device_pm_callback_start" for f in $files; do if [ ! -e "$EPATH/$f" ]; then TRACEEVENTS="no" fi done STAMP=`date "+suspend-%m%d%y-%H%M%S"` HEADER="# $STAMP $HOSTNAME $MODE $KVERSION" } setAlarm() { if [ -z "$WAKETIME" ]; then return fi checkFileRead "$RTCPATH/since_epoch" writeToSysFile "$RTCPATH/wakealarm" "0" NOW=`cat $RTCPATH/since_epoch` FUTURE=$(($NOW+$WAKETIME)) writeToSysFile "$RTCPATH/wakealarm" "$FUTURE" } printHeader() { echo "" echo "------------------------------------" echo " Suspend/Resume timing test " echo "------------------------------------" echo "hostname : $HOSTNAME" echo "kernel : $KVERSION" echo "mode : $MODE" echo "ftrace out : $PWD/$FTRACE" echo "dmesg out : $PWD/$DMESG" echo "log file : $PWD/$LOGFILE" echo "------------------------------------" } printHelp() { echo "" echo "USAGE: android.sh command " echo "" echo "COMMANDS:" echo "" echo " help" echo " print this help text" echo "" echo " status" echo " check that the system is configured properly" echo "" echo " capture-start" echo " prepare the system to capture data on the next suspend/resume" echo " the user should then initiate a normal suspend/resume" echo "" echo " capture-end" echo " collect the data that's been captured in ftrace" echo " the data can then be processed by analyze_suspend" echo "" echo " suspend [waketime]" echo " force a suspend/resume and gather ftrace/dmesg data" echo " - mode : suspend mode (required)" echo " - waketime : wakeup alarm time in seconds (optional)" echo "" } onError() { echo "ERROR: $1" exit } logStart() { echo "------------------------------------" > $LOGFILE echo "hostname : $HOSTNAME" >> $LOGFILE echo "kernel : $KVERSION" >> $LOGFILE echo "mode : $MODE" >> $LOGFILE echo "ftrace out : $PWD/$FTRACE" >> $LOGFILE echo "dmesg out : $PWD/$DMESG" >> $LOGFILE echo "log file : $PWD/$LOGFILE" >> $LOGFILE echo "------------------------------------" >> $LOGFILE date "+%T: logging started" >> $LOGFILE } logEnd() { date "+%T: logging finished" >> $LOGFILE } logEntry() { LINE=`date "+%T: $1"` echo "$LINE" >> $LOGFILE if [ "$2" = "show" ]; then echo "$LINE" fi } suspendPrepare() { printHeader checkDisplay if [ "$DISPLAY" = "OFF" ]; then logEntry "waking up the display" "show" input keyevent 26 fi logEntry "ftrace setup start" "show" rm -f $DMESG rm -f $FTRACE echo -n `date "+%T: ftrace is being configured"` writeToSysFile "$TPATH/tracing_on" "0" echo -n "." writeToSysFile "$TPATH/trace_clock" "global" echo -n "." writeToSysFile "$TPATH/current_tracer" "nop" echo -n "." writeToSysFile "$TPATH/buffer_size_kb" "1000" echo -n "." writeToSysFile "$EPATH/suspend_resume/enable" "1" echo -n "." writeToSysFile "$EPATH/device_pm_callback_end/enable" "1" echo -n "." writeToSysFile "$EPATH/device_pm_callback_start/enable" "1" echo -n "." writeToSysFile "$TPATH/trace" "" echo -n "." dmesg -c > /dev/null echo "done" logEntry "ftrace setup complete" "show" writeToSysFile "$TPATH/tracing_on" "1" logEntry "ftrace is ON" logEntry "waiting to capture suspend/resume data..." "show" } suspendComplete() { echo "" logEntry "checking for suspend/resume data..." "show" logEntry "ftrace is OFF" checkFileRead "$TPATH/trace" writeToSysFile "$TPATH/tracing_on" "0" logEntry "capturing $FTRACE" "show" echo $HEADER > $FTRACE cat $TPATH/trace >> $FTRACE logEntry "flushing the ftrace buffer" writeToSysFile "$TPATH/trace" "" logEntry "capturing $DMESG" "show" echo $HEADER >> $DMESG logEntry "flushing the dmesg buffer" dmesg -c > $DMESG n=0 while read -r line do n=$(($n+1)) if [ $n -gt 12 ]; then break; fi done < $FTRACE if [ $n -le 12 ]; then logEntry "NO FTRACE DATA FOUND" "show" echo "" echo "There's been no PM activity since capture-start was called" echo "" else logEntry "FTRACE DATA IS AVAILABLE" "show" echo "" echo "You can retrieve the data with adb" echo "adb pull $PWD/$FTRACE" echo "adb pull $PWD/$DMESG" echo "adb pull $PWD/$LOGFILE" echo "" echo "Run analyze_suspend on the ftrace data to produce an output.html" echo "analyze_suspend.py -ftrace ftrace.txt" echo "" fi } forceSuspend() { checkFileWrite "/sys/power/state" checkFileWrite "$TPATH/trace_marker" suspendPrepare NOW=`date "+%T"` if [ -z "$WAKETIME" ]; then echo "SUSPEND START @ $NOW (press a key to resume)" else echo "SUSPEND START @ $NOW (rtcwake in $WAKETIME seconds)" setAlarm fi echo "" writeToSysFile "$TPATH/trace_marker" "SUSPEND START" logEntry "suspend start" # execution will pause here writeToSysFile "/sys/power/state" "$MODE" logEntry "resume end" writeToSysFile "$TPATH/trace_marker" "RESUME COMPLETE" suspendComplete } if [ $# -lt 1 ]; then printHelp exit fi COMMAND=$1 shift case "$COMMAND" in help) printHelp ;; status) init printStatus ;; capture-start) init checkStatus logStart suspendPrepare echo "" echo "READY TO GO!" echo "" echo "1) exit adb shell" echo "2) disconnect the usb cable" echo "3) allow the device to suspend by timing out" echo "4) wake the device back up" echo "5) reconnect and run 'sh android.sh capture-end'" echo "" ;; capture-end) init checkStatus suspendComplete logEnd ;; suspend) if [ $# -lt 1 ]; then printHelp echo "" onError "suspend requires a mode (i.e. mem)" fi MODE=$1 if [ $# -gt 1 ]; then WAKETIME=$2 CHECK=$((0+$WAKETIME)) if [ $CHECK -le 0 ]; then onError "$WAKETIME is not a valid positive integer" fi fi logStart init checkStatus forceSuspend logEnd ;; *) printHelp echo "" onError "Invalid command ($COMMAND)" ;; esac