[packages/qemu] - added Kernel Samepage Merging support from qemu-kvm

baggins baggins at pld-linux.org
Sun Nov 3 21:29:57 CET 2013


commit 9fdf235e6d4ae8b6170a046be35c62ead7e1bb2c
Author: Jan Rękorajski <baggins at pld-linux.org>
Date:   Sun Nov 3 21:01:25 2013 +0100

    - added Kernel Samepage Merging support from qemu-kvm

 ksm.service      |  13 ++++++
 ksm.sysconfig    |   4 ++
 ksmctl.c         |  77 ++++++++++++++++++++++++++++++++
 ksmtuned         | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ksmtuned.conf    |  21 +++++++++
 ksmtuned.service |  12 +++++
 qemu.spec        |  30 +++++++++++++
 7 files changed, 290 insertions(+)
---
diff --git a/qemu.spec b/qemu.spec
index 2d6ca3f..9d10c0b 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -23,6 +23,13 @@ License:	GPL v2+
 Group:		Applications/Emulators
 Source0:	http://wiki.qemu-project.org/download/%{name}-%{version}.tar.bz2
 # Source0-md5:	3a897d722457c5a895cd6ac79a28fda0
+# KSM control scripts
+Source5:	ksm.service
+Source6:	ksm.sysconfig
+Source7:	ksmctl.c
+Source8:	ksmtuned.service
+Source9:	ksmtuned
+Source10:	ksmtuned.conf
 Source11:	qemu-guest-agent.service
 Source12:	99-qemu-guest-agent.rules
 Patch0:		%{name}-cflags.patch
@@ -625,6 +632,8 @@ ln -s ../error.h qapi/error.h
 # rebuild patched vesa tables with additional widescreen modes.
 %{__make} -C roms/vgabios stdvga-bios
 
+%{__cc} %{SOURCE7} %{rpmcflags} -o ksmctl
+
 %install
 rm -rf $RPM_BUILD_ROOT
 install -d $RPM_BUILD_ROOT{%{systemdunitdir},/usr/lib/binfmt.d} \
@@ -641,6 +650,14 @@ cat <<'EOF' > $RPM_BUILD_ROOT%{_sysconfdir}/qemu-ifup
 
 EOF
 
+install -p %{SOURCE5} $RPM_BUILD_ROOT%{systemdunitdir}/ksm.service
+install -p %{SOURCE6} $RPM_BUILD_ROOT/etc/sysconfig/ksm
+install -p ksmctl $RPM_BUILD_ROOT%{_sbindir}
+
+install -p %{SOURCE8} $RPM_BUILD_ROOT%{systemdunitdir}/ksmtuned.service
+install -p %{SOURCE9} $RPM_BUILD_ROOT%{_sbindir}/ksmtuned
+install -p %{SOURCE10} $RPM_BUILD_ROOT%{_sysconfdir}/ksmtuned.conf
+
 # For the qemu-guest-agent subpackage install the systemd
 # service and udev rules.
 install -p %{SOURCE11} $RPM_BUILD_ROOT%{systemdunitdir}
@@ -664,11 +681,24 @@ rm -rf $RPM_BUILD_ROOT
 %groupadd -g 276 qemu
 %useradd -u 276 -g qemu -c "QEMU User" qemu
 
+%post common
+%systemd_post ksm.service
+%systemd_post ksmtuned.service
+
+%preun common
+%systemd_preun ksm.service
+%systemd_preun ksmtuned.service
+
 %postun common
 if [ "$1" = "0" ]; then
 	%userremove qemu
 	%groupremove qemu
 fi
+%systemd_reload
+
+%triggerpostun common -- qemu-common < 1.6.1-4
+%systemd_trigger ksm.service
+%systemd_trigger ksmtuned.service
 
 %post guest-agent
 %systemd_reload
diff --git a/ksm.service b/ksm.service
new file mode 100644
index 0000000..dbffa6e
--- /dev/null
+++ b/ksm.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Kernel Samepage Merging
+ConditionPathExists=/sys/kernel/mm/ksm
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+EnvironmentFile=-/etc/sysconfig/ksm
+ExecStart=/usr/sbin/ksmctl start
+ExecStop=/usr/sbin/ksmctl stop
+
+[Install]
+WantedBy=multi-user.target
diff --git a/ksm.sysconfig b/ksm.sysconfig
new file mode 100644
index 0000000..d99656d
--- /dev/null
+++ b/ksm.sysconfig
@@ -0,0 +1,4 @@
+# The maximum number of unswappable kernel pages
+# which may be allocated by ksm (0 for unlimited)
+# If unset, defaults to half of total memory
+# KSM_MAX_KERNEL_PAGES=
diff --git a/ksmctl.c b/ksmctl.c
new file mode 100644
index 0000000..af39591
--- /dev/null
+++ b/ksmctl.c
@@ -0,0 +1,77 @@
+/* Start/stop KSM, for systemd.
+ * Copyright (C) 2009, 2011 Red Hat, Inc.
+ * Written by Paolo Bonzini <pbonzini at redhat.com>.
+ * Based on the original sysvinit script by Dan Kenigsberg <danken at redhat.com>
+ * This file is distributed under the GNU General Public License, version 2
+ * or later.  */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define KSM_MAX_KERNEL_PAGES_FILE "/sys/kernel/mm/ksm/max_kernel_pages"
+#define KSM_RUN_FILE		  "/sys/kernel/mm/ksm/run"
+
+char *program_name;
+
+int usage(void)
+{
+	fprintf(stderr, "Usage: %s {start|stop}\n", program_name);
+	return 1;
+}
+
+int write_value(uint64_t value, char *filename)
+{
+	FILE *fp;
+	if (!(fp = fopen(filename, "w")) ||
+	    fprintf(fp, "%llu\n", (unsigned long long) value) == EOF ||
+	    fflush(fp) == EOF ||
+	    fclose(fp) == EOF)
+		return 1;
+
+	return 0;
+}
+
+uint64_t ksm_max_kernel_pages()
+{
+	char *var = getenv("KSM_MAX_KERNEL_PAGES");
+	char *endptr;
+	uint64_t value;
+	if (var && *var) {
+		value = strtoll(var, &endptr, 0);
+		if (value < LLONG_MAX && !*endptr)
+			return value;
+	}
+	/* Unless KSM_MAX_KERNEL_PAGES is set, let KSM munch up to half of
+	 * total memory.  */
+	return sysconf(_SC_PHYS_PAGES) / 2;
+}
+
+int start(void)
+{
+	if (access(KSM_MAX_KERNEL_PAGES_FILE, R_OK) >= 0)
+		write_value(ksm_max_kernel_pages(), KSM_MAX_KERNEL_PAGES_FILE);
+	return write_value(1, KSM_RUN_FILE);
+}
+
+int stop(void)
+{
+	return write_value(0, KSM_RUN_FILE);
+}
+
+int main(int argc, char **argv)
+{
+	program_name = argv[0];
+	if (argc < 2) {
+		return usage();
+	} else if (!strcmp(argv[1], "start")) {
+		return start();
+	} else if (!strcmp(argv[1], "stop")) {
+		return stop();
+	} else {
+		return usage();
+	}
+}
diff --git a/ksmtuned b/ksmtuned
new file mode 100644
index 0000000..19b5718
--- /dev/null
+++ b/ksmtuned
@@ -0,0 +1,133 @@
+#!/bin/sh
+#
+# Copyright 2009 Red Hat, Inc. and/or its affiliates.
+# Released under the GPL
+#
+# Author:      Dan Kenigsberg <danken at redhat.com>
+# un-bash-ed:  Jan Rękorajski <baggins at pld-linux.org>
+#
+# ksmtuned - a simple script that controls whether (and with what vigor) ksm
+# should search for duplicated pages.
+#
+# starts ksm when memory commited to qemu processes exceeds a threshold, and
+# make ksm work harder and harder untill memory load falls below that
+# threshold.
+#
+# send SIGUSR1 to this process right after a new qemu process is started, or
+# following its death, to retune ksm accordingly
+
+[ -f /etc/ksmtuned.conf ] && . /etc/ksmtuned.conf
+
+debug() {
+    if [ -n "$DEBUG" ]; then
+        s="`/bin/date`: $*"
+        [ -n "$LOGFILE" ] && echo "$s" >> "$LOGFILE" || echo "$s"
+    fi
+}
+
+KSM_MONITOR_INTERVAL=${KSM_MONITOR_INTERVAL:-60}
+KSM_NPAGES_BOOST=${KSM_NPAGES_BOOST:-300}
+KSM_NPAGES_DECAY=${KSM_NPAGES_DECAY:--50}
+
+KSM_NPAGES_MIN=${KSM_NPAGES_MIN:-64}
+KSM_NPAGES_MAX=${KSM_NPAGES_MAX:-1250}
+# millisecond sleep between ksm scans for 16Gb server. Smaller servers sleep
+# more, bigger sleep less.
+KSM_SLEEP_MSEC=${KSM_SLEEP_MSEC:-10}
+
+KSM_THRES_COEF=${KSM_THRES_COEF:-20}
+KSM_THRES_CONST=${KSM_THRES_CONST:-2048}
+
+total=`awk '/^MemTotal:/ {print $2}' /proc/meminfo`
+debug total $total
+
+npages=0
+sleep=$(( $KSM_SLEEP_MSEC * 16 * 1024 * 1024 / $total ))
+[ $sleep -le 10 ] && sleep=10
+debug sleep $sleep
+thres=$(( $total * $KSM_THRES_COEF / 100 ))
+if [ $KSM_THRES_CONST -gt $thres ]; then
+    thres=$KSM_THRES_CONST
+fi
+debug thres $thres
+
+KSMCTL () {
+    case x$1 in
+        xstop)
+            echo 0 > /sys/kernel/mm/ksm/run
+            ;;
+        xstart)
+            echo $2 > /sys/kernel/mm/ksm/pages_to_scan
+            echo $3 > /sys/kernel/mm/ksm/sleep_millisecs
+            echo 1 > /sys/kernel/mm/ksm/run
+            ;;
+    esac
+}
+
+committed_memory () {
+    # calculate how much memory is committed to running qemu processes
+    local progname
+    progname=${1:-qemu-kvm}
+    ps -C "$progname" -o rsz | awk '{ sum += $1 }; END { print sum }'
+}
+
+free_memory () {
+    awk '/^(MemFree|Buffers|Cached):/ {free += $2}; END {print free}' \
+                /proc/meminfo
+}
+
+increase_npages() {
+    local delta
+    delta=${1:-0}
+    npages=$(( $npages + $delta ))
+    if [ $npages -lt $KSM_NPAGES_MIN ]; then
+        npages=$KSM_NPAGES_MIN
+    elif [ $npages -gt $KSM_NPAGES_MAX ]; then
+        npages=$KSM_NPAGES_MAX
+    fi
+    echo $npages
+}
+
+
+adjust () {
+    local free committed
+    free=`free_memory`
+    committed=`committed_memory`
+    debug committed $committed free $free
+    if [ $(( $committed + $thres )) -lt $total -a $free -gt $thres ]; then
+        KSMCTL stop
+	debug "$(( $committed + $thres )) < $total and free > $thres, stop ksm"
+        return 1
+    fi
+    debug "$(( $committed + $thres )) > $total, start ksm"
+    if [ $free -lt $thres ]; then
+        npages=`increase_npages $KSM_NPAGES_BOOST`
+        debug "$free < $thres, boost"
+    else
+        npages=`increase_npages $KSM_NPAGES_DECAY`
+        debug "$free > $thres, decay"
+    fi
+    KSMCTL start $npages $sleep
+    debug "KSMCTL start $npages $sleep"
+    return 0
+}
+
+nothing () {
+    :
+}
+
+loop () {
+    trap nothing USR1
+    while true
+    do
+        sleep $KSM_MONITOR_INTERVAL &
+        wait $!
+        adjust
+    done
+}
+
+PIDFILE=${PIDFILE-/var/run/ksmtune.pid}
+if touch "$PIDFILE"; then
+    loop &
+    echo $! > "$PIDFILE"
+fi
diff --git a/ksmtuned.conf b/ksmtuned.conf
new file mode 100644
index 0000000..fc4518c
--- /dev/null
+++ b/ksmtuned.conf
@@ -0,0 +1,21 @@
+# Configuration file for ksmtuned.
+
+# How long ksmtuned should sleep between tuning adjustments
+# KSM_MONITOR_INTERVAL=60
+
+# Millisecond sleep between ksm scans for 16Gb server.
+# Smaller servers sleep more, bigger sleep less.
+# KSM_SLEEP_MSEC=10
+
+# KSM_NPAGES_BOOST=300
+# KSM_NPAGES_DECAY=-50
+# KSM_NPAGES_MIN=64
+# KSM_NPAGES_MAX=1250
+
+# KSM_THRES_COEF=20
+# KSM_THRES_CONST=2048
+
+# uncomment the following if you want ksmtuned debug info
+
+# LOGFILE=/var/log/ksmtuned
+# DEBUG=1
diff --git a/ksmtuned.service b/ksmtuned.service
new file mode 100644
index 0000000..39febcc
--- /dev/null
+++ b/ksmtuned.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=Kernel Samepage Merging (KSM) Tuning Daemon
+After=ksm.service
+Requires=ksm.service
+
+[Service]
+ExecStart=/usr/sbin/ksmtuned
+ExecReload=/bin/kill -USR1 $MAINPID
+Type=forking
+
+[Install]
+WantedBy=multi-user.target
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/qemu.git/commitdiff/18e669280f9110eed077132bcbd5a37101cc89bf



More information about the pld-cvs-commit mailing list