/usr/sbin/lm-profiler is in laptop-mode-tools 1.68-3ubuntu1.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 | #! /bin/sh
# This script assists you in achieving very high power savings on laptops.
# It can detect programs that perform regular, non-bursty disk operations,
# and network services that listen on external addresses. When started,
# lm-profiler will run for 10 minutes (or a configured number of minutes),
# after which it will provide a series of recommendations.
#
# It will try to find init scripts for any programs that it recommends for
# stopping, and it will ask if you want to place links to those scripts in
# /etc/laptop-mode/batt-stop, so that laptop mode tools will automatically
# stop those daemons when battery mode is detected.
#
#
# This script is a part of Laptop Mode Tools.
#
# Configuration options for this script can be found in
# /etc/laptop-mode/lm-profiler.conf.
#
# Maintainer: Bart Samwel (bart@samwel.tk)
# Adapted from initial version written by Jan Polacek (jerome@ucw.cz).
#
# Read configuration.
#
# Defaults
PROFILE_RUN_LENGTH=600
ACTIVITY_INTERVAL_MAX=150
ACTIVITY_INTERVAL_MIN=5
RECOMMEND_DEFAULT_SERVICES=1
DEFAULT_SERVICES="anacron cron atd"
DEF_IGNORE_PROGRAMS="pdflush journald flush- XFree86 acpid apmd lm-profiler dmesg syslogd awk sed grep mc bc xfs cat diff uniq vi mv sort sleep"
IGNORE_PROGRAMS="$DEF_IGNORE_PROGRAMS"
RECOMMEND_NETWORK_SERVICES=1
DEF_IGNORE_NETWORK_SERVICES="perl" # Some daemons run on perl, not very informative
IGNORE_NETWORK_SERVICES="$DEF_IGNORE_NETWORK_SERVICES"
VERBOSE_OUTPUT=0
if [ -f /etc/laptop-mode/lm-profiler.conf ] ; then
. /etc/laptop-mode/lm-profiler.conf
fi
#
# Internal variables
#
DEBUG=0
######################################################################
if [ $DEBUG -eq 1 ]; then
set -eux
fi
if [ "$VERBOSE_OUTPUT" -eq 1 ] ; then
OUTPUT="/dev/stdout"
else
OUTPUT="/dev/null"
fi
if [ ! `id -u` -eq 0 ]; then
echo "Only root can run profiler."
exit 0
fi
WORKDIR=`mktemp -d -t lm-profiler.XXXXXX`
start_profiling(){
# Turn on disk access profilling
if [ -f /proc/sys/vm/block_dump ]; then
echo "1" > /proc/sys/vm/block_dump
else
echo "/proc/sys/vm/block_dump does not exist, exiting."
exit 1
fi
}
stop_profiling(){
# Turn off disk access profilling
echo "0" > /proc/sys/vm/block_dump
}
# Create a commandline for grep, checking for the presence of all
# strings in a space-separated list passed as the first parameter.
format_params(){
for PARAM in $1 ; do
echo -n "-e $PARAM "
done
}
# Detect all processes that have accessed the disk since the last
# invocation of dmesg. The results are written to files called
# "write_accesses_N" and "read_accesses_N", where N is the first
# parameter of this function.
process_dmesg_diff(){
LEFT="$WORKDIR/dmesg_prev"
RIGHT="$WORKDIR/dmesg_next"
dmesg > $RIGHT
if [ -s $LEFT ] && [ -s $RIGHT ]; then
# The following command is long and complicated. It does
# the following things, separately for READ and WRITE
# accesses:
# 1. Retrieve only new lines, using diff.
# 2. Drop the first line -- it is probably a truncated
# version of an earlier line.
# 3. Parse out the name of the process.
# 4. Filter out IGNORE_PROGRAMS.
# 5. Write process name to output.
diff -u $LEFT $RIGHT \
|grep '^+' \
|grep -o '[^[:space:]]*([0-9]*): WRITE' \
|sed '1d' \
|awk -v FS="(" '{print $1}' \
|grep -v `format_params "$IGNORE_PROGRAMS"` \
|sort \
|uniq \
> $WORKDIR/write_accesses_$1
diff -u $LEFT $RIGHT \
|grep '^+' \
|grep -o '[^[:space:]]*([0-9]*): READ' \
|sed '1d' \
|awk -v FS="(" '{print $1}' \
|grep -v `format_params "$IGNORE_PROGRAMS"` \
|sort \
|uniq \
> $WORKDIR/read_accesses_$1
mv $RIGHT $LEFT
WRITE_ACCESSES_FOUND=0
for ACCESS in $(cat $WORKDIR/write_accesses_$1) ; do
if [ $WRITE_ACCESSES_FOUND -eq 0 ] ; then
printf '\r \rWrite accesses at %d/%d in lm-profiler run:' "$1" "$PROFILE_RUN_LENGTH"
WRITE_ACCESSES_FOUND=1
fi
echo -n " $ACCESS"
done
if [ $WRITE_ACCESSES_FOUND -ne 0 ] ; then
echo ""
fi
READ_ACCESSES_FOUND=0
for ACCESS in $(cat $WORKDIR/read_accesses_$1) ; do
if [ $READ_ACCESSES_FOUND -eq 0 ] ; then
printf '\r \rRead accesses at %d/%d in lm-profiler run:' "$1" "$PROFILE_RUN_LENGTH"
READ_ACCESSES_FOUND=1
fi
echo -n " $ACCESS"
done
if [ $READ_ACCESSES_FOUND -ne 0 ] ; then
echo ""
fi
else
echo "No dmesg data found to profile, exiting."
exit 1
fi
}
# Attempt to find an init script for ithe process given as an argument
findinit(){
INITDIR=
if [ -d /etc/init.d ] ; then
INITDIR=/etc/init.d
elif [ -d /etc/rc.d/init.d ] ; then
INITDIR=/etc/rc.d/init.d
fi
if [ "$INITDIR" != "" ] ; then
INIT=`ls $INITDIR/ |grep ^$1$ |head -n 1`
if [ -z "$INIT" ]; then
INIT=`grep $1 $INITDIR/* |sed s/:.*// |head -n 1`
else
INIT="$INITDIR/$INIT"
fi
if [ ! -z "$INIT" ] && [ -x $INIT ]; then
echo "$INIT"
fi
fi
}
# Look for names of running network services
profilenet(){
netstat -anp |grep ^tcp.*LISTEN |grep -v "Program name" |awk -v FS="/" '{print $2}' |sort |uniq |\
tr -d ['(',')','[',']']
}
#
# PROFILING RUN
#
# Disable profiling if the script gets interrupted.
trap "stop_profiling; echo; exit 10" EXIT HUP INT ABRT QUIT SEGV TERM
SECONDS_DONE=
echo "Profiling run started."
dmesg > $WORKDIR/dmesg_prev
start_profiling
echo > $WORKDIR/write_accesses_$SECONDS_DONE
echo > $WORKDIR/read_accesses_$SECONDS_DONE
SECONDS_DONE=0
while [ $SECONDS_DONE -le $PROFILE_RUN_LENGTH ] ; do
printf '\r%d seconds elapsed, %d remaining. \b\b\b\b\b\b\b\b\b' "$SECONDS_DONE" "$(($PROFILE_RUN_LENGTH - $SECONDS_DONE))"
sleep 1
SECONDS_DONE=$(($SECONDS_DONE + 1))
process_dmesg_diff $SECONDS_DONE
done
printf '\r \r'
stop_profiling
echo "Write frequency : "; cat $WORKDIR/write_accesses_* | sed -e 's/^[ \t]*//;s/[ \t]*$//' -e '/^$/ d' | sort | uniq -c | sort -n
echo "Read frequency : "; cat $WORKDIR/read_accesses_* | sed -e 's/^[ \t]*//;s/[ \t]*$//' -e '/^$/ d' | sort | uniq -c | sort -n
echo;
NETPROFILE=`profilenet`
echo "Profiling run completed."
#
# OUTPUT
#
ALREADY_SEEN=
if [ "$RECOMMEND_DEFAULT_SERVICES" -ne 0 ] ; then
for SERVICE in $DEFAULT_SERVICES ; do
echo
echo "Program: \"$SERVICE\""
echo "Reason: standard recommendation (program may not be running)"
INIT=`findinit $SERVICE`
if [ "$INIT" = "" ] ; then
echo "Init script: none"
echo "If you want to disable this program, you should do so manually."
else
echo "Init script: $INIT (GUESSED)"
echo
echo -n "Do you want to disable this service in battery mode? [y/N]: "
read ANSWER
if ( echo "$ANSWER" | grep -i ^y > /dev/null ) ; then
ln -fs $INIT /etc/laptop-mode/batt-stop/`echo $INIT | sed 's/.*\///g'`
fi
fi
ALREADY_SEEN="$ALREADY_SEEN $SERVICE"
done
fi
if [ "$RECOMMEND_NETWORK_SERVICES" -ne 0 ] ; then
for SERVICE in $NETPROFILE ; do
if ( echo " $IGNORE_NETWORK_SERVICES " | grep -v " $SERVICE " > /dev/null ) ; then
echo
echo "Program: \"$SERVICE\""
echo "Reason: listens on network, may not be needed offline."
INIT=`findinit $SERVICE`
if [ "$INIT" = "" ] ; then
echo "Init script: none"
echo "If you want to disable this program, you should do so manually."
else
echo "Init script: $INIT (GUESSED)"
echo
echo -n "Do you want to disable this service in battery mode? [y/N]: "
read ANSWER
if ( echo "$ANSWER" | grep -i ^y > /dev/null ) ; then
ln -fs $INIT /etc/laptop-mode/batt-stop/`echo $INIT | sed 's/.*\///g'`
fi
fi
ALREADY_SEEN="$ALREADY_SEEN $SERVICE"
fi
done
fi
SECONDS_LEFT=$PROFILE_RUN_LENGTH
while [ $SECONDS_LEFT -gt 0 ] ; do
for SERVICE in `cat $WORKDIR/*_accesses_$SECONDS_LEFT` ; do
if ( echo " $ALREADY_SEEN " | grep -v " $SERVICE " > /dev/null ) ; then
CUR_COMPARE_SECONDS=$(($SECONDS_LEFT - $ACTIVITY_INTERVAL_MIN))
while [ $CUR_COMPARE_SECONDS -gt $(($SECONDS_LEFT - $ACTIVITY_INTERVAL_MAX)) -a $CUR_COMPARE_SECONDS -gt 0 ] ; do
if ( grep "^$SERVICE$" $WORKDIR/*_accesses_$CUR_COMPARE_SECONDS > /dev/null ) ; then
if ( echo " $ALREADY_SEEN " | grep -v " $SERVICE " > /dev/null ) ; then
echo
echo "Program: \"$SERVICE\""
echo "Reason: disk access."
INIT=`findinit $SERVICE`
if [ "$INIT" = "" ] ; then
echo "Init script: none"
echo "If you want to disable this program, you should do so manually."
else
echo "Init script: $INIT (GUESSED)"
echo
echo -n "Do you want to disable this service in battery mode? [y/N]: "
fi
read ANSWER
if ( echo "$ANSWER" | grep -i ^y > /dev/null ) ; then
if [ -e $INIT ] ; then
ln -fs $INIT /etc/laptop-mode/batt-stop/`echo $INIT | sed 's/.*\///g'`
fi
fi
ALREADY_SEEN="$ALREADY_SEEN $SERVICE"
fi
fi
CUR_COMPARE_SECONDS=$(($CUR_COMPARE_SECONDS - 1))
done
fi
done
SECONDS_LEFT=$(($SECONDS_LEFT - 1))
done
|