1
62
marcus.erl
How to conserve battery power using laptop-mode
2
-----------------------------------------------
3
4
Document Author: Bart Samwel (bart@samwel.tk)
5
Date created: January 2, 2004
6
Last modified: December 06, 2004
7
8
Introduction
9
------------
10
11
Laptop mode is used to minimize the time that the hard disk needs to be spun up,
12
to conserve battery power on laptops. It has been reported to cause significant
13
power savings.
14
15
Contents
16
--------
17
18
* Introduction
19
* Installation
20
* Caveats
21
* The Details
22
* Tips & Tricks
23
* Control script
24
* ACPI integration
25
* Monitoring tool
26
27
28
Installation
29
------------
30
31
To use laptop mode, you don't need to set any kernel configuration options
32
or anything. Simply install all the files included in this document, and
33
laptop mode will automatically be started when you're on battery. For
34
your convenience, a tarball containing an installer can be downloaded at:
35
36
http://www.samwel.tk/laptop_mode/laptop_mode/
37
38
To configure laptop mode, you need to edit the configuration file, which is
39
located in /etc/default/laptop-mode on Debian-based systems, or in
40
/etc/sysconfig/laptop-mode on other systems.
41
42
Unfortunately, automatic enabling of laptop mode does not work for
43
laptops that don't have ACPI. On those laptops, you need to start laptop
44
mode manually. To start laptop mode, run "laptop_mode start", and to
45
stop it, run "laptop_mode stop". (Note: The laptop mode tools package now
46
has experimental support for APM, you might want to try that first.)
47
48
49
Caveats
50
-------
51
52
* The downside of laptop mode is that you have a chance of losing up to 10
53
minutes of work. If you cannot afford this, don't use it! The supplied ACPI
54
scripts automatically turn off laptop mode when the battery almost runs out,
55
so that you won't lose any data at the end of your battery life.
56
57
* Most desktop hard drives have a very limited lifetime measured in spindown
58
cycles, typically about 50.000 times (it's usually listed on the spec sheet).
59
Check your drive's rating, and don't wear down your drive's lifetime if you
60
don't need to.
61
62
* If you mount some of your ext3/reiserfs filesystems with the -n option, then
63
the control script will not be able to remount them correctly. You must set
64
DO_REMOUNTS=0 in the control script, otherwise it will remount them with the
65
wrong options -- or it will fail because it cannot write to /etc/mtab.
66
67
* If you have your filesystems listed as type "auto" in fstab, like I did, then
68
the control script will not recognize them as filesystems that need remounting.
69
You must list the filesystems with their true type instead.
70
71
* It has been reported that some versions of the mutt mail client use file access
72
times to determine whether a folder contains new mail. If you use mutt and
73
experience this, you must disable the noatime remounting by setting the option
74
DO_REMOUNT_NOATIME to 0 in the configuration file.
75
76
77
The Details
78
-----------
79
80
Laptop mode is controlled by the knob /proc/sys/vm/laptop_mode. This knob is
81
present for all kernels that have the laptop mode patch, regardless of any
82
configuration options. When the knob is set, any physical disk I/O (that might
83
have caused the hard disk to spin up) causes Linux to flush all dirty blocks. The
84
result of this is that after a disk has spun down, it will not be spun up
85
anymore to write dirty blocks, because those blocks had already been written
86
immediately after the most recent read operation. The value of the laptop_mode
87
knob determines the time between the occurrence of disk I/O and when the flush
88
is triggered. A sensible value for the knob is 5 seconds. Setting the knob to
89
90
91
To increase the effectiveness of the laptop_mode strategy, the laptop_mode
92
control script increases dirty_expire_centisecs and dirty_writeback_centisecs in
93
/proc/sys/vm to about 10 minutes (by default), which means that pages that are
94
dirtied are not forced to be written to disk as often. The control script also
95
changes the dirty background ratio, so that background writeback of dirty pages
96
is not done anymore. Combined with a higher commit value (also 10 minutes) for
97
ext3 or ReiserFS filesystems (also done automatically by the control script),
98
this results in concentration of disk activity in a small time interval which
99
occurs only once every 10 minutes, or whenever the disk is forced to spin up by
100
a cache miss. The disk can then be spun down in the periods of inactivity.
101
102
If you want to find out which process caused the disk to spin up, you can
103
gather information by setting the flag /proc/sys/vm/block_dump. When this flag
104
is set, Linux reports all disk read and write operations that take place, and
105
all block dirtyings done to files. This makes it possible to debug why a disk
106
needs to spin up, and to increase battery life even more. The output of
107
block_dump is written to the kernel output, and it can be retrieved using
108
"dmesg". When you use block_dump and your kernel logging level also includes
109
kernel debugging messages, you probably want to turn off klogd, otherwise
110
the output of block_dump will be logged, causing disk activity that is not
111
normally there.
112
113
114
Configuration
115
-------------
116
117
The laptop mode configuration file is located in /etc/default/laptop-mode on
118
Debian-based systems, or in /etc/sysconfig/laptop-mode on other systems. It
119
contains the following options:
120
121
MAX_AGE:
122
123
Maximum time, in seconds, of hard drive spindown time that you are
124
comfortable with. Worst case, it's possible that you could lose this
125
amount of work if your battery fails while you're in laptop mode.
126
127
MINIMUM_BATTERY_MINUTES:
128
129
Automatically disable laptop mode if the remaining number of minutes of
130
battery power is less than this value. Default is 10 minutes.
131
132
AC_HD/BATT_HD:
133
134
The idle timeout that should be set on your hard drive when laptop mode
135
is active (BATT_HD) and when it is not active (AC_HD). The defaults are
136
20 seconds (value 4) for BATT_HD and 2 hours (value 244) for AC_HD. The
137
possible values are those listed in the manual page for "hdparm" for the
138
"-S" option.
139
140
HD:
141
142
The devices for which the spindown timeout should be adjusted by laptop mode.
143
Default is /dev/hda. If you specify multiple devices, separate them by a space.
144
145
READAHEAD:
146
147
Disk readahead, in 512-byte sectors, while laptop mode is active. A large
148
readahead can prevent disk accesses for things like executable pages (which are
149
loaded on demand while the application executes) and sequentially accessed data
150
(MP3s).
151
152
DO_REMOUNTS:
153
154
The control script automatically remounts any mounted journaled filesystems
155
with appropriate commit interval options. When this option is set to 0, this
156
feature is disabled.
157
158
DO_REMOUNT_NOATIME:
159
160
When remounting, should the filesystems be remounted with the noatime option?
161
Normally, this is set to "1" (enabled), but there may be programs that require
162
access time recording.
163
164
DIRTY_RATIO:
165
166
The percentage of memory that is allowed to contain "dirty" or unsaved data
167
before a writeback is forced, while laptop mode is active. Corresponds to
168
the /proc/sys/vm/dirty_ratio sysctl.
169
170
DIRTY_BACKGROUND_RATIO:
171
172
The percentage of memory that is allowed to contain "dirty" or unsaved data
173
after a forced writeback is done due to an exceeding of DIRTY_RATIO. Set
174
this nice and low. This corresponds to the /proc/sys/vm/dirty_background_ratio
175
sysctl.
176
177
Note that the behaviour of dirty_background_ratio is quite different
178
when laptop mode is active and when it isn't. When laptop mode is inactive,
179
dirty_background_ratio is the threshold percentage at which background writeouts
180
start taking place. When laptop mode is active, however, background writeouts
181
are disabled, and the dirty_background_ratio only determines how much writeback
182
is done when dirty_ratio is reached.
183
184
DO_CPU:
185
186
Enable CPU frequency scaling when in laptop mode. (Requires CPUFreq to be setup.
187
See Documentation/cpu-freq/user-guide.txt for more info. Disabled by default.)
188
189
CPU_MAXFREQ:
190
191
When on battery, what is the maximum CPU speed that the system should use? Legal
192
values are "slowest" for the slowest speed that your CPU is able to operate at,
193
or a value listed in /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies.
194
195
196
Tips & Tricks
197
-------------
198
199
* Bartek Kania reports getting up to 50 minutes of extra battery life (on top
200
of his regular 3 to 3.5 hours) using a spindown time of 5 seconds (BATT_HD=1).
201
202
* You can spin down the disk while playing MP3, by setting disk readahead
203
to 8MB (READAHEAD=16384). Effectively, the disk will read a complete MP3 at
204
once, and will then spin down while the MP3 is playing. (Thanks to Bartek
205
Kania.)
206
207
* Drew Scott Daniels observed: "I don't know why, but when I decrease the number
208
of colours that my display uses it consumes less battery power. I've seen
209
this on powerbooks too. I hope that this is a piece of information that
210
might be useful to the Laptop Mode patch or it's users."
211
212
* In syslog.conf, you can prefix entries with a dash ``-'' to omit syncing the
213
file after every logging. When you're using laptop-mode and your disk doesn't
214
spin down, this is a likely culprit.
215
216
* Richard Atterer observed that laptop mode does not work well with noflushd
217
(http://noflushd.sourceforge.net/), it seems that noflushd prevents laptop-mode
218
from doing its thing.
219
220
* If you're worried about your data, you might want to consider using a USB
221
memory stick or something like that as a "working area". (Be aware though
222
that flash memory can only handle a limited number of writes, and overuse
223
may wear out your memory stick pretty quickly. Do _not_ use journalling
224
filesystems on flash memory sticks.)
225
226
227
Configuration file for control and ACPI battery scripts
228
-------------------------------------------------------
229
230
This allows the tunables to be changed for the scripts via an external
231
configuration file
232
233
It should be installed as /etc/default/laptop-mode on Debian, and as
234
/etc/sysconfig/laptop-mode on Red Hat, SUSE, Mandrake, and other work-alikes.
235
236
--------------------CONFIG FILE BEGIN-------------------------------------------
237
# Maximum time, in seconds, of hard drive spindown time that you are
238
# comfortable with. Worst case, it's possible that you could lose this
239
# amount of work if your battery fails you while in laptop mode.
240
#MAX_AGE=600
241
242
# Automatically disable laptop mode when the number of minutes of battery
243
# that you have left goes below this threshold.
244
MINIMUM_BATTERY_MINUTES=10
245
246
# Read-ahead, in 512-byte sectors. You can spin down the disk while playing MP3/OGG
247
# by setting the disk readahead to 8MB (READAHEAD=16384). Effectively, the disk
248
# will read a complete MP3 at once, and will then spin down while the MP3/OGG is
249
# playing.
250
#READAHEAD=4096
251
252
# Shall we remount journaled fs. with appropriate commit interval? (1=yes)
253
#DO_REMOUNTS=1
254
255
# And shall we add the "noatime" option to that as well? (1=yes)
256
#DO_REMOUNT_NOATIME=1
257
258
# Dirty synchronous ratio. At this percentage of dirty pages the process
259
# which
260
# calls write() does its own writeback
261
#DIRTY_RATIO=40
262
263
#
264
# Allowed dirty background ratio, in percent. Once DIRTY_RATIO has been
265
# exceeded, the kernel will wake pdflush which will then reduce the amount
266
# of dirty memory to dirty_background_ratio. Set this nice and low, so once
267
# some writeout has commenced, we do a lot of it.
268
#
269
#DIRTY_BACKGROUND_RATIO=5
270
271
# kernel default dirty buffer age
272
#DEF_AGE=30
273
#DEF_UPDATE=5
274
#DEF_DIRTY_BACKGROUND_RATIO=10
275
#DEF_DIRTY_RATIO=40
276
#DEF_XFS_AGE_BUFFER=15
277
#DEF_XFS_SYNC_INTERVAL=30
278
#DEF_XFS_BUFD_INTERVAL=1
279
280
# This must be adjusted manually to the value of HZ in the running kernel
281
# on 2.4, until the XFS people change their 2.4 external interfaces to work in
282
# centisecs. This can be automated, but it's a work in progress that still
283
# needs# some fixes. On 2.6 kernels, XFS uses USER_HZ instead of HZ for
284
# external interfaces, and that is currently always set to 100. So you don't
285
# need to change this on 2.6.
286
#XFS_HZ=100
287
288
# Should the maximum CPU frequency be adjusted down while on battery?
289
# Requires CPUFreq to be setup.
290
# See Documentation/cpu-freq/user-guide.txt for more info
291
#DO_CPU=0
292
293
# When on battery what is the maximum CPU speed that the system should
294
# use? Legal values are "slowest" for the slowest speed that your
295
# CPU is able to operate at, or a value listed in:
296
# /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies
297
# Only applicable if DO_CPU=1.
298
#CPU_MAXFREQ=slowest
299
300
# Idle timeout for your hard drive (man hdparm for valid values, -S option)
301
# Default is 2 hours on AC (AC_HD=244) and 20 seconds for battery (BATT_HD=4).
302
#AC_HD=244
303
#BATT_HD=4
304
305
# The drives for which to adjust the idle timeout. Separate them by a space,
306
# e.g. HD="/dev/hda /dev/hdb".
307
#HD="/dev/hda"
308
309
# Set the spindown timeout on a hard drive?
310
#DO_HD=1
311
312
--------------------CONFIG FILE END---------------------------------------------
313
314
315
Control script
316
--------------
317
318
Please note that this control script works for the Linux 2.4 and 2.6 series (thanks
319
to Kiko Piris).
320
321
--------------------CONTROL SCRIPT BEGIN----------------------------------------
322
#!/bin/bash
323
324
# start or stop laptop_mode, best run by a power management daemon when
325
# ac gets connected/disconnected from a laptop
326
#
327
# install as /sbin/laptop_mode
328
#
329
# Contributors to this script: Kiko Piris
330
# Bart Samwel
331
# Micha Feigin
332
# Andrew Morton
333
# Herve Eychenne
334
# Dax Kelson
335
#
336
# Original Linux 2.4 version by: Jens Axboe
337
338
#############################################################################
339
340
# Source config
341
if [ -f /etc/default/laptop-mode ] ; then
342
# Debian
343
. /etc/default/laptop-mode
344
elif [ -f /etc/sysconfig/laptop-mode ] ; then
345
# Others
346
. /etc/sysconfig/laptop-mode
347
fi
348
349
# Don't raise an error if the config file is incomplete
350
# set defaults instead:
351
352
# Maximum time, in seconds, of hard drive spindown time that you are
353
# comfortable with. Worst case, it's possible that you could lose this
354
# amount of work if your battery fails you while in laptop mode.
355
MAX_AGE=${MAX_AGE:-'600'}
356
357
# Read-ahead, in kilobytes
358
READAHEAD=${READAHEAD:-'4096'}
359
360
# Shall we remount journaled fs. with appropriate commit interval? (1=yes)
361
DO_REMOUNTS=${DO_REMOUNTS:-'1'}
362
363
# And shall we add the "noatime" option to that as well? (1=yes)
364
DO_REMOUNT_NOATIME=${DO_REMOUNT_NOATIME:-'1'}
365
366
# Shall we adjust the idle timeout on a hard drive?
367
DO_HD=${DO_HD:-'1'}
368
369
# Adjust idle timeout on which hard drive?
370
HD="${HD:-'/dev/hda'}"
371
372
# spindown time for HD (hdparm -S values)
373
AC_HD=${AC_HD:-'244'}
374
BATT_HD=${BATT_HD:-'4'}
375
376
# Dirty synchronous ratio. At this percentage of dirty pages the process which
377
# calls write() does its own writeback
378
DIRTY_RATIO=${DIRTY_RATIO:-'40'}
379
380
# cpu frequency scaling
381
# See Documentation/cpu-freq/user-guide.txt for more info
382
DO_CPU=${CPU_MANAGE:-'0'}
383
CPU_MAXFREQ=${CPU_MAXFREQ:-'slowest'}
384
385
#
386
# Allowed dirty background ratio, in percent. Once DIRTY_RATIO has been
387
# exceeded, the kernel will wake pdflush which will then reduce the amount
388
# of dirty memory to dirty_background_ratio. Set this nice and low, so once
389
# some writeout has commenced, we do a lot of it.
390
#
391
DIRTY_BACKGROUND_RATIO=${DIRTY_BACKGROUND_RATIO:-'5'}
392
393
# kernel default dirty buffer age
394
DEF_AGE=${DEF_AGE:-'30'}
395
DEF_UPDATE=${DEF_UPDATE:-'5'}
396
DEF_DIRTY_BACKGROUND_RATIO=${DEF_DIRTY_BACKGROUND_RATIO:-'10'}
397
DEF_DIRTY_RATIO=${DEF_DIRTY_RATIO:-'40'}
398
DEF_XFS_AGE_BUFFER=${DEF_XFS_AGE_BUFFER:-'15'}
399
DEF_XFS_SYNC_INTERVAL=${DEF_XFS_SYNC_INTERVAL:-'30'}
400
DEF_XFS_BUFD_INTERVAL=${DEF_XFS_BUFD_INTERVAL:-'1'}
401
402
# This must be adjusted manually to the value of HZ in the running kernel
403
# on 2.4, until the XFS people change their 2.4 external interfaces to work in
404
# centisecs. This can be automated, but it's a work in progress that still needs
405
# some fixes. On 2.6 kernels, XFS uses USER_HZ instead of HZ for external
406
# interfaces, and that is currently always set to 100. So you don't need to
407
# change this on 2.6.
408
XFS_HZ=${XFS_HZ:-'100'}
409
410
#############################################################################
411
412
KLEVEL="$(uname -r |
413
{
414
IFS='.' read a b c
415
echo $a.$b
416
}
417
)"
418
case "$KLEVEL" in
419
"2.4"|"2.6")
420
;;
421
*)
422
echo "Unhandled kernel version: $KLEVEL ('uname -r' = '$(uname -r)')" >&2
423
exit 1
424
;;
425
esac
426
427
if [ ! -e /proc/sys/vm/laptop_mode ] ; then
428
echo "Kernel is not patched with laptop_mode patch." >&2
429
exit 1
430
fi
431
432
if [ ! -w /proc/sys/vm/laptop_mode ] ; then
433
echo "You do not have enough privileges to enable laptop_mode." >&2
434
exit 1
435
fi
436
437
# Remove an option (the first parameter) of the form option= from
438
# a mount options string (the rest of the parameters).
439
parse_mount_opts () {
440
OPT="$1"
441
shift
442
echo ",$*," | sed \
443
-e 's/,'"$OPT"'=[0-9]*,/,/g' \
444
-e 's/,,*/,/g' \
445
-e 's/^,//' \
446
-e 's/,$//'
447
}
448
449
# Remove an option (the first parameter) without any arguments from
450
# a mount option string (the rest of the parameters).
451
parse_nonumber_mount_opts () {
452
OPT="$1"
453
shift
454
echo ",$*," | sed \
455
-e 's/,'"$OPT"',/,/g' \
456
-e 's/,,*/,/g' \
457
-e 's/^,//' \
458
-e 's/,$//'
459
}
460
461
# Find out the state of a yes/no option (e.g. "atime"/"noatime") in
462
# fstab for a given filesystem, and use this state to replace the
463
# value of the option in another mount options string. The device
464
# is the first argument, the option name the second, and the default
465
# value the third. The remainder is the mount options string.
466
#
467
# Example:
468
# parse_yesno_opts_wfstab /dev/hda1 atime atime defaults,noatime
469
#
470
# If fstab contains, say, "rw" for this filesystem, then the result
471
# will be "defaults,atime".
472
parse_yesno_opts_wfstab () {
473
L_DEV="$1"
474
OPT="$2"
475
DEF_OPT="$3"
476
shift 3
477
L_OPTS="$*"
478
PARSEDOPTS1="$(parse_nonumber_mount_opts $OPT $L_OPTS)"
479
PARSEDOPTS1="$(parse_nonumber_mount_opts no$OPT $PARSEDOPTS1)"
480
# Watch for a default atime in fstab
481
FSTAB_OPTS="$(awk '$1 == "'$L_DEV'" { print $4 }' /etc/fstab)"
482
if echo "$FSTAB_OPTS" | grep "$OPT" > /dev/null ; then
483
# option specified in fstab: extract the value and use it
484
if echo "$FSTAB_OPTS" | grep "no$OPT" > /dev/null ; then
485
echo "$PARSEDOPTS1,no$OPT"
486
else
487
# no$OPT not found -- so we must have $OPT.
488
echo "$PARSEDOPTS1,$OPT"
489
fi
490
else
491
# option not specified in fstab -- choose the default.
492
echo "$PARSEDOPTS1,$DEF_OPT"
493
fi
494
}
495
496
# Find out the state of a numbered option (e.g. "commit=NNN") in
497
# fstab for a given filesystem, and use this state to replace the
498
# value of the option in another mount options string. The device
499
# is the first argument, and the option name the second. The
500
# remainder is the mount options string in which the replacement
501
# must be done.
502
#
503
# Example:
504
# parse_mount_opts_wfstab /dev/hda1 commit defaults,commit=7
505
#
506
# If fstab contains, say, "commit=3,rw" for this filesystem, then the
507
# result will be "rw,commit=3".
508
parse_mount_opts_wfstab () {
509
L_DEV="$1"
510
OPT="$2"
511
shift 2
512
L_OPTS="$*"
513
PARSEDOPTS1="$(parse_mount_opts $OPT $L_OPTS)"
514
# Watch for a default commit in fstab
515
FSTAB_OPTS="$(awk '$1 == "'$L_DEV'" { print $4 }' /etc/fstab)"
516
if echo "$FSTAB_OPTS" | grep "$OPT=" > /dev/null ; then
517
# option specified in fstab: extract the value, and use it
518
echo -n "$PARSEDOPTS1,$OPT="
519
echo ",$FSTAB_OPTS," | sed \
520
-e 's/.*,'"$OPT"'=//' \
521
-e 's/,.*//'
522
else
523
# option not specified in fstab: set it to 0
524
echo "$PARSEDOPTS1,$OPT=0"
525
fi
526
}
527
528
deduce_fstype () {
529
MP="$1"
530
# My root filesystem unfortunately has
531
# type "unknown" in /etc/mtab. If we encounter
532
# "unknown", we try to get the type from fstab.
533
cat /etc/fstab |
534
grep -v '^#' |
535
while read FSTAB_DEV FSTAB_MP FSTAB_FST FSTAB_OPTS FSTAB_DUMP FSTAB_DUMP ; do
536
if [ "$FSTAB_MP" = "$MP" ]; then
537
echo $FSTAB_FST
538
exit 0
539
fi
540
done
541
}
542
543
if [ $DO_REMOUNT_NOATIME -eq 1 ] ; then
544
NOATIME_OPT=",noatime"
545
fi
546
547
case "$1" in
548
start)
549
AGE=$((100*$MAX_AGE))
550
XFS_AGE=$(($XFS_HZ*$MAX_AGE))
551
echo -n "Starting laptop_mode"
552
553
if [ -d /proc/sys/vm/pagebuf ] ; then
554
# (For 2.4 and early 2.6.)
555
# This only needs to be set, not reset -- it is only used when
556
# laptop mode is enabled.
557
echo $XFS_AGE > /proc/sys/vm/pagebuf/lm_flush_age
558
echo $XFS_AGE > /proc/sys/fs/xfs/lm_sync_interval
559
elif [ -f /proc/sys/fs/xfs/lm_age_buffer ] ; then
560
# (A couple of early 2.6 laptop mode patches had these.)
561
# The same goes for these.
562
echo $XFS_AGE > /proc/sys/fs/xfs/lm_age_buffer
563
echo $XFS_AGE > /proc/sys/fs/xfs/lm_sync_interval
564
elif [ -f /proc/sys/fs/xfs/age_buffer ] ; then
565
# (2.6.6)
566
# But not for these -- they are also used in normal
567
# operation.
568
echo $XFS_AGE > /proc/sys/fs/xfs/age_buffer
569
echo $XFS_AGE > /proc/sys/fs/xfs/sync_interval
570
elif [ -f /proc/sys/fs/xfs/age_buffer_centisecs ] ; then
571
# (2.6.7 upwards)
572
# And not for these either. These are in centisecs,
573
# not USER_HZ, so we have to use $AGE, not $XFS_AGE.
574
echo $AGE > /proc/sys/fs/xfs/age_buffer_centisecs
575
echo $AGE > /proc/sys/fs/xfs/xfssyncd_centisecs
576
echo 3000 > /proc/sys/fs/xfs/xfsbufd_centisecs
577
fi
578
579
case "$KLEVEL" in
580
"2.4")
581
echo 1 > /proc/sys/vm/laptop_mode
582
echo "30 500 0 0 $AGE $AGE 60 20 0" > /proc/sys/vm/bdflush
583
;;
584
"2.6")
585
echo 5 > /proc/sys/vm/laptop_mode
586
echo "$AGE" > /proc/sys/vm/dirty_writeback_centisecs
587
echo "$AGE" > /proc/sys/vm/dirty_expire_centisecs
588
echo "$DIRTY_RATIO" > /proc/sys/vm/dirty_ratio
589
echo "$DIRTY_BACKGROUND_RATIO" > /proc/sys/vm/dirty_background_ratio
590
;;
591
esac
592
if [ $DO_REMOUNTS -eq 1 ]; then
593
cat /etc/mtab | while read DEV MP FST OPTS DUMP PASS ; do
594
PARSEDOPTS="$(parse_mount_opts "$OPTS")"
595
if [ "$FST" = 'unknown' ]; then
596
FST=$(deduce_fstype $MP)
597
fi
598
case "$FST" in
599
"ext3"|"reiserfs")
600
PARSEDOPTS="$(parse_mount_opts commit "$OPTS")"
601
mount $DEV -t $FST $MP -o remount,$PARSEDOPTS,commit=$MAX_AGE$NOATIME_OPT
602
;;
603
"xfs")
604
mount $DEV -t $FST $MP -o remount,$OPTS$NOATIME_OPT
605
;;
606
esac
607
if [ -b $DEV ] ; then
608
blockdev --setra $(($READAHEAD * 2)) $DEV
609
fi
610
done
611
fi
612
if [ $DO_HD -eq 1 ] ; then
613
for THISHD in $HD ; do
614
/sbin/hdparm -S $BATT_HD $THISHD > /dev/null 2>&1
615
/sbin/hdparm -B 1 $THISHD > /dev/null 2>&1
616
done
617
fi
618
if [ $DO_CPU -eq 1 -a -e /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq ]; then
619
if [ $CPU_MAXFREQ = 'slowest' ]; then
620
CPU_MAXFREQ=`cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq`
621
fi
622
echo $CPU_MAXFREQ > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
623
fi
624
echo "."
625
;;
626
stop)
627
U_AGE=$((100*$DEF_UPDATE))
628
B_AGE=$((100*$DEF_AGE))
629
echo -n "Stopping laptop_mode"
630
echo 0 > /proc/sys/vm/laptop_mode
631
if [ -f /proc/sys/fs/xfs/age_buffer -a ! -f /proc/sys/fs/xfs/lm_age_buffer ] ; then
632
# These need to be restored, if there are no lm_*.
633
echo $(($XFS_HZ*$DEF_XFS_AGE_BUFFER)) > /proc/sys/fs/xfs/age_buffer
634
echo $(($XFS_HZ*$DEF_XFS_SYNC_INTERVAL)) > /proc/sys/fs/xfs/sync_interval
635
elif [ -f /proc/sys/fs/xfs/age_buffer_centisecs ] ; then
636
# These need to be restored as well.
637
echo $((100*$DEF_XFS_AGE_BUFFER)) > /proc/sys/fs/xfs/age_buffer_centisecs
638
echo $((100*$DEF_XFS_SYNC_INTERVAL)) > /proc/sys/fs/xfs/xfssyncd_centisecs
639
echo $((100*$DEF_XFS_BUFD_INTERVAL)) > /proc/sys/fs/xfs/xfsbufd_centisecs
640
fi
641
case "$KLEVEL" in
642
"2.4")
643
echo "30 500 0 0 $U_AGE $B_AGE 60 20 0" > /proc/sys/vm/bdflush
644
;;
645
"2.6")
646
echo "$U_AGE" > /proc/sys/vm/dirty_writeback_centisecs
647
echo "$B_AGE" > /proc/sys/vm/dirty_expire_centisecs
648
echo "$DEF_DIRTY_RATIO" > /proc/sys/vm/dirty_ratio
649
echo "$DEF_DIRTY_BACKGROUND_RATIO" > /proc/sys/vm/dirty_background_ratio
650
;;
651
esac
652
if [ $DO_REMOUNTS -eq 1 ] ; then
653
cat /etc/mtab | while read DEV MP FST OPTS DUMP PASS ; do
654
# Reset commit and atime options to defaults.
655
if [ "$FST" = 'unknown' ]; then
656
FST=$(deduce_fstype $MP)
657
fi
658
case "$FST" in
659
"ext3"|"reiserfs")
660
PARSEDOPTS="$(parse_mount_opts_wfstab $DEV commit $OPTS)"
661
PARSEDOPTS="$(parse_yesno_opts_wfstab $DEV atime atime $PARSEDOPTS)"
662
mount $DEV -t $FST $MP -o remount,$PARSEDOPTS
663
;;
664
"xfs")
665
PARSEDOPTS="$(parse_yesno_opts_wfstab $DEV atime atime $OPTS)"
666
mount $DEV -t $FST $MP -o remount,$PARSEDOPTS
667
;;
668
esac
669
if [ -b $DEV ] ; then
670
blockdev --setra 256 $DEV
671
fi
672
done
673
fi
674
if [ $DO_HD -eq 1 ] ; then
675
for THISHD in $HD ; do
676
/sbin/hdparm -S $AC_HD $THISHD > /dev/null 2>&1
677
/sbin/hdparm -B 255 $THISHD > /dev/null 2>&1
678
done
679
fi
680
if [ $DO_CPU -eq 1 -a -e /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq ]; then
681
echo `cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq` > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
682
fi
683
echo "."
684
;;
685
*)
686
echo "Usage: $0 {start|stop}" 2>&1
687
exit 1
688
;;
689
690
esac
691
692
exit 0
693
--------------------CONTROL SCRIPT END------------------------------------------
694
695
696
ACPI integration
697
----------------
698
699
Dax Kelson submitted this so that the ACPI acpid daemon will
700
kick off the laptop_mode script and run hdparm. The part that
701
automatically disables laptop mode when the battery is low was
702
written by Jan Topinski.
703
704
-----------------/etc/acpi/events/ac_adapter BEGIN------------------------------
705
event=ac_adapter
706
action=/etc/acpi/actions/ac.sh %e
707
----------------/etc/acpi/events/ac_adapter END---------------------------------
708
709
710
-----------------/etc/acpi/events/battery BEGIN---------------------------------
711
event=battery.*
712
action=/etc/acpi/actions/battery.sh %e
713
----------------/etc/acpi/events/battery END------------------------------------
714
715
716
----------------/etc/acpi/actions/ac.sh BEGIN-----------------------------------
717
#!/bin/bash
718
719
# ac on/offline event handler
720
721
status=`awk '/^state: / { print $2 }' /proc/acpi/ac_adapter/$2/state`
722
723
case $status in
724
"on-line")
725
/sbin/laptop_mode stop
726
exit 0
727
;;
728
"off-line")
729
/sbin/laptop_mode start
730
exit 0
731
;;
732
esac
733
---------------------------/etc/acpi/actions/ac.sh END--------------------------
734
735
736
---------------------------/etc/acpi/actions/battery.sh BEGIN-------------------
737
#! /bin/bash
738
739
# Automatically disable laptop mode when the battery almost runs out.
740
741
BATT_INFO=/proc/acpi/battery/$2/state
742
743
if [[ -f /proc/sys/vm/laptop_mode ]]
744
then
745
LM=`cat /proc/sys/vm/laptop_mode`
746
if [[ $LM -gt 0 ]]
747
then
748
if [[ -f $BATT_INFO ]]
749
then
750
# Source the config file only now that we know we need
751
if [ -f /etc/default/laptop-mode ] ; then
752
# Debian
753
. /etc/default/laptop-mode
754
elif [ -f /etc/sysconfig/laptop-mode ] ; then
755
# Others
756
. /etc/sysconfig/laptop-mode
757
fi
758
MINIMUM_BATTERY_MINUTES=${MINIMUM_BATTERY_MINUTES:-'10'}
759
760
ACTION="`cat $BATT_INFO | grep charging | cut -c 26-`"
761
if [[ ACTION -eq "discharging" ]]
762
then
763
PRESENT_RATE=`cat $BATT_INFO | grep "present rate:" | sed "s/.* \([0-9][0-9]* \).*/\1/" `
764
REMAINING=`cat $BATT_INFO | grep "remaining capacity:" | sed "s/.* \([0-9][0-9]* \).*/\1/" `
765
fi
766
if (($REMAINING * 60 / $PRESENT_RATE < $MINIMUM_BATTERY_MINUTES))
767
then
768
/sbin/laptop_mode stop
769
fi
770
else
771
logger -p daemon.warning "You are using laptop mode and your battery interface $BATT_INFO is missing. This may lead to loss of data when the battery runs out. Check kernel ACPI support and /proc/acpi/battery folder, and edit /etc/acpi/battery.sh to set BATT_INFO to the correct path."
772
fi
773
fi
774
fi
775
---------------------------/etc/acpi/actions/battery.sh END--------------------
776
777
778
Monitoring tool
779
---------------
780
781
Bartek Kania submitted this, it can be used to measure how much time your disk
782
spends spun up/down.
783
784
---------------------------dslm.c BEGIN-----------------------------------------
785
/*
786
* Simple Disk Sleep Monitor
787
* by Bartek Kania
788
* Licenced under the GPL
789
*/
790
#include
791
#include
792
#include
793
#include
794
#include
795
#include
796
#include
797
#include
798
#include
799
#include
800
801
#ifdef DEBUG
802
#define D(x) x
803
#else
804
#define D(x)
805
#endif
806
807
int endit = 0;
808
809
/* Check if the disk is in powersave-mode
810
* Most of the code is stolen from hdparm.
811
* 1 = active, 0 = standby/sleep, -1 = unknown */
812
int check_powermode(int fd)
813
{
814
unsigned char args[4] = {WIN_CHECKPOWERMODE1,0,0,0};
815
int state;
816
817
if (ioctl(fd, HDIO_DRIVE_CMD, &args)
818
&& (args[0] = WIN_CHECKPOWERMODE2) /* try again with 0x98 */
819
&& ioctl(fd, HDIO_DRIVE_CMD, &args)) {
820
if (errno != EIO || args[0] != 0 || args[1] != 0) {
821
state = -1; /* "unknown"; */
822
} else
823
state = 0; /* "sleeping"; */
824
} else {
825
state = (args[2] == 255) ? 1 : 0;
826
}
827
D(printf(" drive state is: %d\n", state));
828
829
return state;
830
}
831
832
char *state_name(int i)
833
{
834
if (i == -1) return "unknown";
835
if (i == 0) return "sleeping";
836
if (i == 1) return "active";
837
838
return "internal error";
839
}
840
841
char *myctime(time_t time)
842
{
843
char *ts = ctime(&time);
844
ts[strlen(ts) - 1] = 0;
845
846
return ts;
847
}
848
849
void measure(int fd)
850
{
851
time_t start_time;
852
int last_state;
853
time_t last_time;
854
int curr_state;
855
time_t curr_time = 0;
856
time_t time_diff;
857
time_t active_time = 0;
858
time_t sleep_time = 0;
859
time_t unknown_time = 0;
860
time_t total_time = 0;
861
int changes = 0;
862
float tmp;
863
864
printf("Starting measurements\n");
865
866
last_state = check_powermode(fd);
867
start_time = last_time = time(0);
868
printf(" System is in state %s\n\n", state_name(last_state));
869
870
while(!endit) {
871
sleep(1);
872
curr_state = check_powermode(fd);
873
874
if (curr_state != last_state || endit) {
875
changes++;
876
curr_time = time(0);
877
time_diff = curr_time - last_time;
878
879
if (last_state == 1) active_time += time_diff;
880
else if (last_state == 0) sleep_time += time_diff;
881
else unknown_time += time_diff;
882
883
last_state = curr_state;
884
last_time = curr_time;
885
886
printf("%s: State-change to %s\n", myctime(curr_time),
887
state_name(curr_state));
888
}
889
}
890
changes--; /* Compensate for SIGINT */
891
892
total_time = time(0) - start_time;
893
printf("\nTotal running time: %lus\n", curr_time - start_time);
894
printf(" State changed %d times\n", changes);
895
896
tmp = (float)sleep_time / (float)total_time * 100;
897
printf(" Time in sleep state: %lus (%.2f%%)\n", sleep_time, tmp);
898
tmp = (float)active_time / (float)total_time * 100;
899
printf(" Time in active state: %lus (%.2f%%)\n", active_time, tmp);
900
tmp = (float)unknown_time / (float)total_time * 100;
901
printf(" Time in unknown state: %lus (%.2f%%)\n", unknown_time, tmp);
902
}
903
904
void ender(int s)
905
{
906
endit = 1;
907
}
908
909
void usage()
910
{
911
puts("usage: dslm [-w ] ");
912
exit(0);
913
}
914
915
int main(int argc, char **argv)
916
{
917
int fd;
918
char *disk = 0;
919
int settle_time = 60;
920
921
/* Parse the simple command-line */
922
if (argc == 2)
923
disk = argv[1];
924
else if (argc == 4) {
925
settle_time = atoi(argv[2]);
926
disk = argv[3];
927
} else
928
usage();
929
930
if (!(fd = open(disk, O_RDONLY|O_NONBLOCK))) {
931
printf("Can't open %s, because: %s\n", disk, strerror(errno));
932
exit(-1);
933
}
934
935
if (settle_time) {
936
printf("Waiting %d seconds for the system to settle down to "
937
"'normal'\n", settle_time);
938
sleep(settle_time);
939
} else
940
puts("Not waiting for system to settle down");
941
942
signal(SIGINT, ender);
943
944
measure(fd);
945
946
close(fd);
947
948
return 0;
949
}
950
---------------------------dslm.c END-------------------------------------------