3
# Script to automate suspend / resume
5
# Copyright (C) 2008-2009 Canonical Ltd.
8
# Michael Frey <michael.frey@canonical.com>
9
# Andy Whitcroft <apw@canonical.com>
11
# This program is free software: you can redistribute it and/or modify
12
# it under the terms of the GNU General Public License version 2,
13
# as published by the Free Software Foundation.
15
# This program is distributed in the hope that it will be useful,
16
# but WITHOUT ANY WARRANTY; without even the implied warranty of
17
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
# GNU General Public License for more details.
20
# You should have received a copy of the GNU General Public License
21
# along with this program. If not, see <http://www.gnu.org/licenses/>.
24
# Script to automate suspend / resume
26
# We set a RTC alarm that wakes the system back up and then sleep
27
# for seconds before we go back to sleep.
32
# - add a new suspend battery drain test
33
# - track batteries disabling tests which require them automatically
34
# - disable dbus tests when we have no primary user
35
# - include the new power drain test in --full
36
# - handle AC transitions better
37
# - use minutes in messages where appropriate
38
# - report AC transition failures
39
# - only mention AC when we have batteries
40
# - report results at the bottom for easy posting
43
# - add a --dry-run mode to simplify developement
44
# - add a automation mode for checkbox integration
45
# - add a new pm-suspend test
46
# - record and restore timer_delay around the variable time test.
49
# - move an --enable/--disable interface for tests
50
# - add --set to allow setting of approved parameters
51
# - fix up prompting for interactive and non-interactive tests
52
# - supply a sensible default for testing on servers (apw, kirkland)
55
# - send dbus messages as the original user
56
# - stop clearing the dmesg as we go
57
# - stop using trace generally as this affects the wakeups
58
# - do a single dbus test then move to pm-suspend to avoid screensaver
59
# - timeout waiting for a suspend to complete catching failure to go down
62
# - update the help output
63
# - add --comprehensive to do AC related tests
64
# - add --extensive to do a range of time related tests
65
# - add --full to enable all harder tests
66
# - add fallback to pm-suspend for Kbuntu
67
# - collect dmesg output
68
# - remove hwclock update
71
# - fix typo in fallback acpi interface
72
# - when recording the RTC clock do not go direct
73
# - pmi is now deprecated suspend using dbus
76
# - support newer rtc sysfs wakealarm interface
77
# - move to using pmi action suspend
78
# - allow the user to specify the number of iterations
79
# - ensure we are running as root
80
# - report the iterations to the user
81
# - clean up the output and put it in a standard logfile
82
# - add a descriptive warning and allow user cancel
83
# - add tracing enable/disable
84
# - fix logfile location
85
# - add a failure cleanup mode
86
# - make time sleep time and delay time configurable
87
# - ensure the log directory exists
88
# - clock will be fixed automatically on network connect
89
# - default sleep before wakeup to 20s
90
# - do not use dates after we have corrupted the clock
91
# - sort out the copyright information
92
# - we do not have any failure cleanup currently
95
# - add the suspend test scripts
99
LOGDIR='/var/lib/pm-utils'
100
LOGFILE="$LOGDIR/stress.log"
102
setup_wakeup_timer ()
107
# Request wakeup from the RTC or ACPI alarm timers. Set the timeout
108
# at 'now' + $timeout seconds.
110
ctl='/sys/class/rtc/rtc0/wakealarm'
111
if [ -f "$ctl" ]; then
112
# Cancel any outstanding timers.
114
# rtcN/wakealarm can use relative time in seconds
115
echo "+$timeout" >"$ctl"
118
ctl='/proc/acpi/alarm'
119
if [ -f "$ctl" ]; then
120
echo `date '+%F %H:%M:%S' -d '+ '$timeout' seconds'` >"$ctl"
124
echo "no method to awaken machine automatically" 1>&2
130
if [ "$dry" -eq 1 ]; then
131
echo "DRY-RUN: suspend machine for $timer_sleep"
136
setup_wakeup_timer "$timer_sleep"
138
dmesg >"$LOGFILE.dmesg.A"
140
# Send a dbus message to initiate Suspend.
141
if [ "$suspend_dbus" -eq 1 ]; then
142
sudo -u $SUDO_USER dbus-send --session --type=method_call \
143
--dest=org.freedesktop.PowerManagement \
144
/org/freedesktop/PowerManagement \
145
org.freedesktop.PowerManagement.Suspend \
147
ECHO "FAILED: dbus suspend failed"
151
pm-suspend >> "$LOGFILE"
154
# Wait on the machine coming back up -- pulling the dmesg over.
155
echo "v---" >>"$LOGFILE"
157
while [ "$retry" -gt 0 ]; do
160
# Accumulate the dmesg delta.
161
dmesg >"$LOGFILE.dmesg.B"
162
diff "$LOGFILE.dmesg.A" "$LOGFILE.dmesg.B" | \
163
grep '^>' >"$LOGFILE.dmesg"
164
mv "$LOGFILE.dmesg.B" "$LOGFILE.dmesg.A"
166
echo "Waiting for suspend to complete $retry to go ..." \
168
cat "$LOGFILE.dmesg" >> "$LOGFILE"
170
if [ "`grep -c 'Back to C!' $LOGFILE.dmesg`" -ne 0 ]; then
175
echo "^---" >>"$LOGFILE"
176
rm -f "$LOGFILE.dmesg"*
177
if [ "$retry" -eq 0 ]; then
178
ECHO "SUSPEND FAILED, did not go to sleep"
184
if [ "$dry" -eq 1 ]; then
185
echo "DRY-RUN: stay awake for $timer_delay"
191
# wait for $timer_delay seconds after system resume from S3
193
ECHO "wait for $timer_delay seconds"
199
echo "$@" | tee -a "$LOGFILE"
206
ECHO "Suspend Test starting on $(date '+%F %H:%M:%S') ($TOTAL cycles)"
207
while [ "$CNT" -le "$TOTAL" ]
209
ECHO "Suspend iteration $CNT of $TOTAL"
211
suspend_system "$START"
216
ECHO "Suspend Test completed"
221
echo 1 > '/sys/power/pm_trace'
226
echo 0 > '/sys/power/pm_trace'
232
cat /proc/acpi/battery/*/state 2>/dev/null | \
235
/present:.*yes/ { total += 1 }
241
cat /proc/acpi/battery/*/state 2>/dev/null | \
244
/remaining capacity:/ { total += $3 }
254
Usage: $P [<options>]
256
--sleep <seconds> - how long the machine wait before waking
257
--delay <seconds> - default delay between iterations
259
--enable <test> - enable a specific test
260
--disable <test> - disable a specific test
261
--set <test>.<var>=<val> - set a test specific variable
262
dbus - perform a suspend via dbus
263
ac - perform tests involving removing ac power
264
timed - perform a variable timing test
265
repeat - perform a longer repeat test
266
.iterations - the number of iterations in the repeat
267
power - perform a battery consumption test
268
.sleep - how long to sleep
270
--full - run a basic set of tests
271
--server - run those test appropriate for a server
275
# We need TEMP as the `eval set --' would nuke the return value of getopt.
276
TEMP=`getopt -o '' -l dry-run,auto,,sleep:,delay:,enable:,disable:,set:,full,desktop,server -n "$P" -- "$@"`
277
if [ $? != 0 ] ; then
282
# Note the quotes around `$TEMP': they are essential!
288
if ! declare -p "test_$1" 2>/dev/null 1>&2; then
289
echo "$P: $1: test unknown" 1>&2
295
stmt=`echo "$1" | sed -e 's/\./_/g'`
301
if ! declare -p "args_$var" 2>/dev/null 1>&2; then
302
echo "$P: $var: test variable unknown" 1>&2
311
if [ "$val" != "$num" ]; then
312
name=`echo "$1" | sed -e 's/args_//' -e 's/_/./'`
313
echo "$P: $name: $val: non-numeric value" 1>&2
329
args_repeat_iterations=10
331
args_power_sleep=1200
336
--dry-run) dry=1; shift 1 ;;
337
--auto) auto=1; shift 1 ;;
338
--sleep) timer_sleep="$2"; shift 2 ;;
339
--delay) timer_delay="$2"; shift 2 ;;
340
--disable) chk_test "$2"; declare "test_$1=0"; shift 2 ;;
341
--enable) chk_test "$2"; declare "test_$2=1"; shift 2 ;;
342
--set) handle_set "$2"; declare "$RET"; shift 2 ;;
343
--desktop|--full) test_dbus=1; test_ac=1; test_timed=1;
344
test_power=1; shift 1 ;;
345
--server) test_timed=1; shift 1 ;;
347
*) echo "$1: ERROR"; exit 1 ;;
351
chk_number "args_repeat_iterations"
352
chk_number "args_power_sleep"
354
tests=`set | grep ^test_ | grep -c =1`
356
if [ "$#" -gt 1 ]; then
360
if [ "$tests" -eq 0 ]; then
362
echo "$P: no tests selected" 1>&2
366
battery_count=`battery_count`
372
# Check we are running as root as we are going to fiddle with the clock
373
# and use the rtc wakeups.
375
if [ "$id" -ne 0 ]; then
376
echo "ERROR: must be run as root to perform this test, use sudo:" 1>&2
377
echo " sudo $0 $@" 1>&2
400
cat /proc/acpi/ac_adapter/*/state 2>/dev/null | \
402
BEGIN { online = 0; offline = 0 }
403
/on-line/ { online = 1 }
404
/off-line/ { offline = 1 }
408
} else if (offline) {
418
typeset ac_current=`ac_online`
420
if [ "$ac_becomes" -ne -1 -a "$ac_current" -ne -1 -a \
421
"$ac_current" -ne "$ac_becomes" ]; then
422
ECHO "*** WARNING: AC power not in expected state" \
423
"($ac_becomes) after test"
438
echo "*** TEST $phase -- $1"
444
if [ "$battery_count" -ne 0 -a "$ac_needed" -ne "$ac_is" ]; then
446
0) echo "*** please ensure your AC cord is detached" ;;
447
1) echo "*** please ensure your AC cord is attached" ;;
452
if [ "$timer_sleep" -gt 60 ]; then
453
let sleep="$timer_sleep / 60"
454
sleep="$sleep minutes"
456
sleep="$timer_sleep seconds"
458
echo "*** machine will suspend for $sleep"
460
if [ "$auto" -eq 1 ]; then
463
elif [ "$phase_interactive" -eq 1 ]; then
464
echo "*** press return when ready"
467
elif [ "$phase_first" -eq 1 ]; then
468
echo "*** NOTE: there will be no further user interaction from this point"
469
echo "*** press return when ready"
476
[ "$auto" -eq 0 ] && cat - <<EOM
477
This script will attempt to suspend and resume your computer a number of times.
478
Should the machine fail to resume, first attempt to manually resume it. If
479
that fails power your system off and on which will generate an apport bug
480
report automatically.
482
Press CTRL-C now to abort testing ...
485
# Ensure the log directory exists.
489
if [ "$test_dbus" -eq 1 -a \
490
\( "$SUDO_USER" = "" -o "$SUDO_USER" = "root" \) ]; then
491
ECHO "*** no primary user (via sudo) dbus tests skipped ..."
492
elif [ "$test_dbus" -eq 1 ]; then
495
phase "suspend triggered via dbus message"
499
if [ "$test_pmsuspend" -eq 1 ]; then
501
phase "suspend triggered via pm-suspend"
504
if [ "$test_ac" -eq 1 -a "$battery_count" -eq 0 ]; then
505
ECHO "*** no BATTERY detected ac tests skipped ..."
506
elif [ "$test_ac" -eq 1 ]; then
508
phase "suspend with AC disconnected"
512
phase "suspend with AC connected"
516
phase "loss of AC while suspended" \
517
"please remove the AC cord while the machine is suspended"
521
phase "return of AC while suspended" \
522
"please insert the AC cord while the machine is suspended"
525
if [ "$test_power" -eq 1 -a "$battery_count" -eq 0 ]; then
526
ECHO "*** no BATTERY detected power test skipped ..."
527
elif [ "$test_power" -eq 1 ]; then
528
save_timer_sleep="$timer_sleep"
529
let timer_sleep="$args_power_sleep"
532
phase "battery drain during suspend" \
533
"calculates overall power drain during a long-term suspend"
536
date_before=`date +%s`
537
bat_before=`battery_capacity`
543
date_after=`date +%s`
544
bat_after=`battery_capacity`
546
# do the calculations
547
let consumed="$bat_before - $bat_after"
548
let elapsed="$date_after - $date_before"
549
let usage="($consumed * 60*60) / $elapsed"
552
ECHO "before: $bat_before mWh"
553
ECHO "after: $bat_after mWh"
554
ECHO "consumed: $consumed mW"
555
ECHO "sleep seconds: $elapsed sec"
556
ECHO "overall usage: $usage mW"
558
report_battery="$usage mW"
560
if [ $elapsed -lt 1200 ]
562
ECHO "WARNING: the suspend was less than 20 minutes"
563
ECHO " to get reliable numbers increase the sleep time"
564
report_battery="$report_battery (unreliable)"
567
timer_sleep="$save_timer_sleep"
571
if [ "$test_timed" -eq 1 ]; then
572
save_timer_delay="$timer_delay"
576
phase "30 iteration variable delay suspend/resume stress test"
577
while [ "$timer_delay" -gt 0 ]; do
578
echo "delay $timer_delay ..."
581
let timer_delay="$timer_delay - 2"
583
timer_delay="$save_timer_delay"
585
if [ "$test_repeat" -eq 1 ]; then
587
phase "basic $args_repeat_iterations iteration suspend/resume stress test"
588
run_suspend "$args_repeat_iterations"
594
# REPORT: final report stage.
598
if [ "$2" != "" ]; then
602
if [ "$auto" -eq 0 ]; then
604
echo "*** Please report your results on the Ubuntu WIKI:"
605
echo " https://wiki.ubuntu.com/KernelTeam/SuspendResumeTesting"
607
report_this "Battery Consumption:" "$report_battery"
610
# All suceessful, clean up.