Seite wählen

Wenn das MacBook zu heiß ist – cpulimit.sh

von | Sep 19, 2011 | Linux, Team, Development, Mac, Betriebssysteme

Ich mag laute Hardware nicht. Und ich fand es gut, dass mein iBook mit 600MHz PowerPC G3 Prozessor aus dem Jahr 2001 nur im absoluten Notfall den Lüfter eingeschaltet hat. Auch mein MacBook Pro mit 2,4GHz Intel Core 2 Duo Prozessor war im Normalfall nicht zu hören.
Aber mein neues MacBook Pro mit 2,2GHz Intel Core i7 erdreistet sich, bei verschiedenen Gelegenheiten, in den „Jet-mode“ zu gehen. Die Ursache ist dann gern mal der Indexer für Spotlight (metadata server – mds) oder ein Video Player (video lan client – vlc). Beide brauchen eigentlich nicht mit voller Power zu laufen um meinen Ansprüchen gerecht zu werden. Ausserdem braucht man meist auch die dedizierte Grafikkarte nicht. Die kann man aber Dank gfxCardStatus einfach abschalten. Achtung, nicht vergessen wieder anzuschalten, wenn man den Beamer dranhängt!
Apple hat leider keine Möglichkeit vorgesehen die CPU zu drosseln um weniger Strom zu verbrauchen und somit den Akku und das Gehör zu schonen. Todtraurig!
Nice ist auch keine Lösung, weil ja dennoch die Power genutzt wird die zur Verfügung steht.
Aber ich habe etwas gefunden was an dieser Stelle weiterhelfen kann: cpulimit. Das ließ sich aber unter Lion nicht compilieren. Es gibt da aber noch diese Variation davon.
An der Shell Variante habe ich ein wenig gefeilt. Nun bekommt man eine Liste der CPU hungrigen Prozesse zur Auswahl und den Erstplatzierten als Vorauswahl.
Das Ergebnis sieht dann so aus:

$ sudo ~/bin/cpulimit.sh
Password:
  This script will throttle a chosen process as you like it.
  Therefore your cpu runs cooler - hopefully.
Chose which process to throttle:
 PPID   PID USER            %CPU %MEM STARTED      TIME     STIME COMMAND
    1    66 root            25,5  5,1 Do08am   73:25.42  32:24.31 mds
  273   436 bschmidt        23,1  0,1 Do08am    1:20.18   0:13.72 Folder Actions Dispatcher
    1 19304 root            15,3  0,1 Sa03pm   62:40.11  51:14.03 activitymonitord
  273 91519 bschmidt        14,6  0,3  7:57pm   0:06.47   0:02.17 mdworker
    1    12 _mdnsresponder  12,6  0,0 Do08am   26:20.00  19:02.96 mDNSResponder
  273 91189 bschmidt        11,6  0,4  7:55pm   0:06.54   0:02.21 mdworker
  273 91520 bschmidt        11,3  0,3  7:57pm   0:06.48   0:02.17 mdworker
  273 91518 bschmidt         9,2  0,3  7:57pm   0:06.36   0:02.14 mdworker
  273 13471 bschmidt         8,7  3,6 Fr02pm  101:01.25  22:25.71 Google Chrome
Which process ID (PID) [guess: 66]?
Chosen:
  PID USER  %CPU %MEM STARTED      TIME COMMAND
   66 root  21,9  5,1 Do08am   73:26.43 /System/Library/Frameworks/CoreServices.framework/Frameworks/Metadata.framework/Support/mds
Sleep time in seconds (e.g 0.5 or 1 …) [default: 0.5]?
Run time in seconds (e.g 0.5 or 1 …) or percent [default: .5000 = 50%]?
OK. I will throttle PID 66 now and dislay processinfo every 20 seconds …
  PID USER  %CPU %MEM STARTED      TIME COMMAND
   66 root  40,5  4,7 Do08am   73:34.02 /System/Library/Frameworks/CoreServices.framework/Frameworks/Metadata.framework/Support/mds
  PID USER  %CPU %MEM STARTED      TIME COMMAND
   66 root  32,7  4,8 Do08am   73:34.91 /System/Library/Frameworks/CoreServices.framework/Frameworks/Metadata.framework/Support/mds
  PID USER  %CPU %MEM STARTED      TIME COMMAND
   66 root   0,0  4,8 Do08am   73:35.15 /System/Library/Frameworks/CoreServices.framework/Frameworks/Metadata.framework/Support/mds
^C
*** Ouch! Stop throtteling of PID 66. Exiting ***

Mit diesem Script ist es ein Leichtes, Prozesse ausser Rand und Band wieder einzufangen. Erstaunlicher Weise sogar den Video Player, wenn man nur die sleep time kurz genug wählt.
Da das Script nicht lang ist, stell ich es hier einfach mal rein:

#! /bin/bash
# Description:
#
# If you want to decrease the CPU demands for an application
# you can use this very simple and ugly "hack".
# I use it when I convert videos on my MacBook Pro
# to prevent it from getting to warm. Even if the CPU is IDLE this hack
# will prevent the application to use the CPU during Sleep Time
# (in contrast to renice/nice commands which will take all IDLE time).
# This means the conversions will take longer time, but I
# don't care because I run it at night.
#
# There is similar c program for Linux called cpulimit, but it wont
# compile on my Mac.
#
# Usage:  sudo ./cpulimit.sh
#
#################################
# config
sleeptime_default=0.5   # in seconds
runtimep_default=50     # in percent (50 = same as sleeptime)
reporttime=30           # report every x seconds while running
# PROCESSLISTformat: pid has to be on the second position
PROCESSLISTformat="ppid,pid,user,%cpu,%mem,start,cputime,stime,command"
#PROCESSLISTformat="ppid,pid,user,%cpu,%mem,start,cputime,stime,rss,vsz,cpu,re,wq,wqr,stat,nsigs,command"
#################################
# dont change anything below here
pid=""
scriptuser=$(id -u)
# run if user hits control-c
control_c()
{
  echo ""
  if [ "$pid" != "" ]; then
    echo -en "\n*** Ouch! Stop throtteling of PID $pid. Exiting ***\n"
    kill -SIGCONT $pid
  fi
  echo ""
  exit $?
}
# trap keyboard interrupt (control-c)
trap control_c SIGINT
pidstring()
{
  # takes pid as argument
  ps -p $1 -w -o pid,user,%cpu,%mem,start,cputime,command 2>/dev/null
}
isnumber()
{
  if [[ "$1" =~ ^[0-9]*([.][0-9]+)?$ ]] ; then
    return 0
  else
    return 1
  fi
}
#################################
# main
cat << EOF
  This script will throttle a chosen process as you like it.
  Therefore your cpu runs cooler - hopefully.
EOF
if [ "$scriptuser" != "0" ]; then
cat << EOF
  You're not root!
  If you want to controll processes that you dont own,
  please run via sudo.
EOF
fi
PIDSTRING=""
until [ "$PIDSTRING" != "" ]; do
  #PROCESSLIST=$(ps -r -A -f -S | head)
  if [ "$scriptuser" != "0" ]; then
    PROCESSLIST=$(ps -r -u $scriptuser -S -c -o $PROCESSLISTformat 2>/dev/null)
  else
    PROCESSLIST=$(ps -r -A -S -c -o $PROCESSLISTformat 2>/dev/null)
  fi
  if [ "$PROCESSLIST" = "" ]; then
    echo -en "\n*** Sorry, ps dont work as expected on $(uname). Exiting ***\n\n"
    exit 1
  else
    PROCESSLIST=$(echo "$PROCESSLIST" | head)
  fi
  echo -en "\nChose which process to throttle:\n$PROCESSLIST\n"
  PID_GUESS=$(echo "$PROCESSLIST" | head -2 | tail -1 | awk '{print $2}')
  echo -n "Which process ID (PID) [guess: $PID_GUESS]? "
  read pid
  if [ "$pid" = "" ]; then
      pid=$PID_GUESS
  fi
  # test if $pid is valid
  PIDSTRING=$(pidstring $pid)
  if [ "$?" -eq "0"  ]; then
    echo -en "\nChosen:\n$PIDSTRING\n"
  else
    echo -en "\n$pid is not a valid PID for a running process.\n"
    pid=""
  fi
  echo -en "\n"
done
sleeptime=""
until [ "$sleeptime" != "" ]; do
  echo -n "Sleep time in seconds (e.g 0.5 or 1 …) [default: $sleeptime_default]? "
  read sleeptime
  if [ "$sleeptime" = "" ]; then
    sleeptime=$sleeptime_default
  fi
  isnumber $sleeptime || sleeptime=""
done
#echo "sleeptime $sleeptime"
runtime=""
until [ "$runtime" != "" ]; do
  runtime_default=$(echo "scale=4;$sleeptime*$runtimep_default/(100-$runtimep_default)"|bc)
  echo -n "Run time in seconds (e.g 0.5 or 1 …) or percent [default: $runtime_default = $runtimep_default%]? "
  read runtime
  if [[ "$runtime" =~ ^([0-9]*([.][0-9]+)?)%$ ]] ; then
    runtimep_default=${BASH_REMATCH[1]}
  fi
  if [ "$runtime" = "" ]; then
    runtime=$runtime_default
  fi
  isnumber $runtime || runtime=""
done
#echo "runtime $runtime"
# now begin throttle
throttletime=1000000
looptime=$(awk "BEGIN { printf \"%.0f\\n\", ($sleeptime+$runtime)*100 }")
echo "OK. I will throttle PID $pid now and dislay processinfo every $reporttime seconds … "
((reporttime=$reporttime*100))
while true
do
  if [ $throttletime -ge 500 ]; then
    throttletime=0
    PIDSTRING=$(pidstring $pid)
    echo "$PIDSTRING"
  fi
  kill -SIGSTOP $pid || control_c
  sleep $sleeptime
  kill -SIGCONT $pid || control_c
  sleep $runtime
  throttletime=$(($looptime+$throttletime))
done

2 Kommentare

  1. Rüdiger Kaatz

    This is a very handy script, works perfect for me. Thanx a million.

    Antworten
  2. Cpt.Proton

    Hallo,
    ich habe es tatsächlich geschafft, das Script auszuführen. Ich habe dabei aber eine Frage. Dort wird nach der Sleeptime gefragt. Ich möchte Handbrake ein bisschen drosseln und es eigentlich nicht schlafenlegen. Ist das dennoch richtig so?
    Viele Grüße

    Antworten

Trackbacks/Pingbacks

  1. Weekly Snap: CPU Limit, MOTP, Typed Arrays & Training Courses in 2012 « NETWAYS Blog - [...] began the week with his discovery of cpulimit.sh, a tool to cool down his over active MacBook Pro. With…

Einen Kommentar abschicken

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Mehr Beiträge zum Thema Linux | Team | Development | Mac | Betriebssysteme