Blame SOURCES/ksmtuned

4a2fec
#!/bin/bash
4a2fec
#
4a2fec
# Copyright 2009 Red Hat, Inc. and/or its affiliates.
4a2fec
# Released under the GPL
4a2fec
#
4a2fec
# Author:      Dan Kenigsberg <danken@redhat.com>
4a2fec
#
4a2fec
# ksmtuned - a simple script that controls whether (and with what vigor) ksm
4a2fec
# should search for duplicated pages.
4a2fec
#
4a2fec
# starts ksm when memory commited to qemu processes exceeds a threshold, and
4a2fec
# make ksm work harder and harder untill memory load falls below that
4a2fec
# threshold.
4a2fec
#
4a2fec
# send SIGUSR1 to this process right after a new qemu process is started, or
4a2fec
# following its death, to retune ksm accordingly
4a2fec
#
4a2fec
# needs testing and ironing. contact danken@redhat.com if something breaks.
4a2fec
4a2fec
if [ -f /etc/ksmtuned.conf ]; then
4a2fec
    . /etc/ksmtuned.conf
4a2fec
fi
4a2fec
4a2fec
debug() {
4a2fec
    if [ -n "$DEBUG" ]; then
4a2fec
        s="`/bin/date`: $*"
4a2fec
        [ -n "$LOGFILE" ] && echo "$s" >> "$LOGFILE" || echo "$s"
4a2fec
    fi
4a2fec
}
4a2fec
4a2fec
4a2fec
KSM_MONITOR_INTERVAL=${KSM_MONITOR_INTERVAL:-60}
4a2fec
KSM_NPAGES_BOOST=${KSM_NPAGES_BOOST:-300}
4a2fec
KSM_NPAGES_DECAY=${KSM_NPAGES_DECAY:--50}
4a2fec
4a2fec
KSM_NPAGES_MIN=${KSM_NPAGES_MIN:-64}
4a2fec
KSM_NPAGES_MAX=${KSM_NPAGES_MAX:-1250}
4a2fec
# millisecond sleep between ksm scans for 16Gb server. Smaller servers sleep
4a2fec
# more, bigger sleep less.
4a2fec
KSM_SLEEP_MSEC=${KSM_SLEEP_MSEC:-10}
4a2fec
4a2fec
KSM_THRES_COEF=${KSM_THRES_COEF:-20}
4a2fec
KSM_THRES_CONST=${KSM_THRES_CONST:-2048}
4a2fec
4a2fec
total=`awk '/^MemTotal:/ {print $2}' /proc/meminfo`
4a2fec
debug total $total
4a2fec
4a2fec
npages=0
4a2fec
sleep=$[KSM_SLEEP_MSEC * 16 * 1024 * 1024 / total]
4a2fec
[ $sleep -le 10 ] && sleep=10
4a2fec
debug sleep $sleep
4a2fec
thres=$[total * KSM_THRES_COEF / 100]
4a2fec
if [ $KSM_THRES_CONST -gt $thres ]; then
4a2fec
    thres=$KSM_THRES_CONST
4a2fec
fi
4a2fec
debug thres $thres
4a2fec
4a2fec
KSMCTL () {
4a2fec
    case x$1 in
4a2fec
        xstop)
4a2fec
            echo 0 > /sys/kernel/mm/ksm/run
4a2fec
            ;;
4a2fec
        xstart)
4a2fec
            echo $2 > /sys/kernel/mm/ksm/pages_to_scan
4a2fec
            echo $3 > /sys/kernel/mm/ksm/sleep_millisecs
4a2fec
            echo 1 > /sys/kernel/mm/ksm/run
4a2fec
            ;;
4a2fec
    esac
4a2fec
}
4a2fec
4a2fec
committed_memory () {
4a2fec
    local pidlist
4a2fec
    pidlist=$(pgrep -d ' ' -- '^qemu(-kvm|:.{1,11})$')
4a2fec
    if [ -n "$pidlist" ]; then
4a2fec
        ps -p "$pidlist" -o rsz=
4a2fec
    fi | awk '{ sum += $1 }; END { print 0+sum }'
4a2fec
}
4a2fec
4a2fec
free_memory () {
4a2fec
    awk '/^(MemFree|Buffers|Cached):/ {free += $2}; END {print free}' \
4a2fec
                /proc/meminfo
4a2fec
}
4a2fec
4a2fec
increase_npages() {
4a2fec
    local delta
4a2fec
    delta=${1:-0}
4a2fec
    npages=$[npages + delta]
4a2fec
    if [ $npages -lt $KSM_NPAGES_MIN ]; then
4a2fec
        npages=$KSM_NPAGES_MIN
4a2fec
    elif [ $npages -gt $KSM_NPAGES_MAX ]; then
4a2fec
        npages=$KSM_NPAGES_MAX
4a2fec
    fi
4a2fec
    echo $npages
4a2fec
}
4a2fec
4a2fec
4a2fec
adjust () {
4a2fec
    local free committed
4a2fec
    free=`free_memory`
4a2fec
    committed=`committed_memory`
4a2fec
    debug committed $committed free $free
4a2fec
    if [ $[committed + thres] -lt $total -a $free -gt $thres ]; then
4a2fec
        KSMCTL stop
4a2fec
        debug "$[committed + thres] < $total and free > $thres, stop ksm"
4a2fec
        return 1
4a2fec
    fi
4a2fec
    debug "$[committed + thres] > $total, start ksm"
4a2fec
    if [ $free -lt $thres ]; then
4a2fec
        npages=`increase_npages $KSM_NPAGES_BOOST`
4a2fec
        debug "$free < $thres, boost"
4a2fec
    else
4a2fec
        npages=`increase_npages $KSM_NPAGES_DECAY`
4a2fec
        debug "$free > $thres, decay"
4a2fec
    fi
4a2fec
    KSMCTL start $npages $sleep
4a2fec
    debug "KSMCTL start $npages $sleep"
4a2fec
    return 0
4a2fec
}
4a2fec
4a2fec
function nothing () {
4a2fec
    :
4a2fec
}
4a2fec
4a2fec
loop () {
4a2fec
    trap nothing SIGUSR1
4a2fec
    while true
4a2fec
    do
4a2fec
        sleep $KSM_MONITOR_INTERVAL &
4a2fec
        wait $!
4a2fec
        adjust
4a2fec
    done
4a2fec
}
4a2fec
4a2fec
PIDFILE=${PIDFILE-/var/run/ksmtune.pid}
4a2fec
if touch "$PIDFILE"; then
4a2fec
  loop &
4a2fec
  echo $! > "$PIDFILE"
4a2fec
fi