[libvirt] [PATCH v2 0/3] Add support for vCPU and I/O thread scheduler setting

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1178986 v2: - No dependency on sched.h unless really needed - Docs fixed according to John - RNG schema matches parsing - Possibility to specify one element for whole mask of vcpus/iothreads - leaks fixed (VIR_FREE(nodes);) O:-) - not accepting "other" as a scheduler when parsing - Rebased, of course Martin Kletzander (3): util: Add virProcessSetScheduler() function for scheduler settings docs, schema, conf: Add support for setting scheduler parameters of guest threads qemu: Add support for setting vCPU and I/O thread scheduler setting configure.ac | 4 +- docs/formatdomain.html.in | 16 ++ docs/schemas/domaincommon.rng | 44 +++++ src/conf/domain_conf.c | 183 ++++++++++++++++++++- src/conf/domain_conf.h | 24 +++ src/libvirt_private.syms | 1 + src/qemu/qemu_driver.c | 5 + src/qemu/qemu_process.c | 57 ++++++- src/qemu/qemu_process.h | 5 +- src/util/virprocess.c | 104 +++++++++++- src/util/virprocess.h | 20 ++- .../qemuxml2argv-cputune-iothreadsched-toomuch.xml | 38 +++++ .../qemuxml2argv-cputune-iothreadsched.xml | 39 +++++ .../qemuxml2argv-cputune-vcpusched-overlap.xml | 38 +++++ tests/qemuxml2argvtest.c | 2 + .../qemuxml2xmlout-cputune-iothreadsched.xml | 39 +++++ tests/qemuxml2xmltest.c | 1 + 17 files changed, 612 insertions(+), 8 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cputune-iothreadsched-toomuch.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cputune-iothreadsched.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cputune-vcpusched-overlap.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-cputune-iothreadsched.xml -- 2.3.0

This function uses sched_setscheduler() function so it works with processes and threads as well (even threads not created by us, which is what we'll need in the future). Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- configure.ac | 4 +- src/libvirt_private.syms | 1 + src/util/virprocess.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++- src/util/virprocess.h | 20 ++++++++- 4 files changed, 124 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 99a2283..b3e99e7 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. -dnl Copyright (C) 2005-2014 Red Hat, Inc. +dnl Copyright (C) 2005-2015 Red Hat, Inc. dnl dnl This library is free software; you can redistribute it and/or dnl modify it under the terms of the GNU Lesser General Public @@ -275,7 +275,7 @@ dnl and various less common threadsafe functions AC_CHECK_FUNCS_ONCE([cfmakeraw fallocate geteuid getgid getgrnam_r \ getmntent_r getpwuid_r getuid kill mmap newlocale posix_fallocate \ posix_memalign prlimit regexec sched_getaffinity setgroups setns \ - setrlimit symlink sysctlbyname getifaddrs]) + setrlimit symlink sysctlbyname getifaddrs sched_setscheduler]) dnl Availability of pthread functions. Because of $LIB_PTHREAD, we dnl cannot use AC_CHECK_FUNCS_ONCE. LIB_PTHREAD and LIBMULTITHREAD diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 376c69b..79fc14f 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1915,6 +1915,7 @@ virProcessSetMaxFiles; virProcessSetMaxMemLock; virProcessSetMaxProcesses; virProcessSetNamespaces; +virProcessSetScheduler; virProcessTranslateStatus; virProcessWait; diff --git a/src/util/virprocess.c b/src/util/virprocess.c index d0a1500..c030d74 100644 --- a/src/util/virprocess.c +++ b/src/util/virprocess.c @@ -1,7 +1,7 @@ /* * virprocess.c: interaction with processes * - * Copyright (C) 2010-2014 Red Hat, Inc. + * Copyright (C) 2010-2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -32,7 +32,9 @@ # include <sys/time.h> # include <sys/resource.h> #endif -#include <sched.h> +#if HAVE_SCHED_SETSCHEDULER +# include <sched.h> +#endif #if defined(__FreeBSD__) || HAVE_BSD_CPU_AFFINITY # include <sys/param.h> @@ -104,6 +106,13 @@ static inline int setns(int fd ATTRIBUTE_UNUSED, int nstype ATTRIBUTE_UNUSED) } #endif +VIR_ENUM_IMPL(virProcessSchedPolicy, VIR_PROC_POLICY_LAST, + "none", + "batch", + "idle", + "fifo", + "rr"); + /** * virProcessTranslateStatus: * @status: child exit status to translate @@ -1052,3 +1061,94 @@ virProcessExitWithStatus(int status) } exit(value); } + +#if HAVE_SCHED_SETSCHEDULER + +static int +virProcessSchedTranslatePolicy(virProcessSchedPolicy policy) +{ + switch (policy) { + case VIR_PROC_POLICY_NONE: + return SCHED_OTHER; + + case VIR_PROC_POLICY_BATCH: + return SCHED_BATCH; + + case VIR_PROC_POLICY_IDLE: + return SCHED_IDLE; + + case VIR_PROC_POLICY_FIFO: + return SCHED_FIFO; + + case VIR_PROC_POLICY_RR: + return SCHED_RR; + + case VIR_PROC_POLICY_LAST: + /* nada */ + break; + } + + return -1; +} + +int +virProcessSetScheduler(pid_t pid, virProcessSchedPolicy policy, int priority) +{ + struct sched_param param = {0}; + int pol = virProcessSchedTranslatePolicy(policy); + + VIR_DEBUG("pid=%d, policy=%d, priority=%u", pid, policy, priority); + + if (!policy) + return 0; + + if (pol == SCHED_FIFO || pol == SCHED_RR) { + int min = 0; + int max = 0; + + if ((min = sched_get_priority_min(pol)) < 0) { + virReportSystemError(errno, "%s", + _("Cannot get minimum scheduler " + "priority value")); + return -1; + } + + if ((max = sched_get_priority_max(pol)) < 0) { + virReportSystemError(errno, "%s", + _("Cannot get maximum scheduler " + "priority value")); + return -1; + } + + if (priority < min || priority > max) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Scheduler priority %d out of range [%d, %d]"), + priority, min, max); + return -1; + } + + param.sched_priority = priority; + } + + if (sched_setscheduler(pid, pol, ¶m) < 0) { + virReportSystemError(errno, + _("Cannot set scheduler parameters for pid %d"), + pid); + return -1; + } + + return 0; +} + +#else /* ! HAVE_SCHED_SETSCHEDULER */ + +int +virProcessSetScheduler(pid_t pid, int policy, int priority) +{ + virReportSystemError(ENOSYS, "%s", + _("Process CPU scheduling is not supported " + "on this platform")); + return -1; +} + +#endif /* !HAVE_SCHED_SETSCHEDULER */ diff --git a/src/util/virprocess.h b/src/util/virprocess.h index bcaede5..8b95560 100644 --- a/src/util/virprocess.h +++ b/src/util/virprocess.h @@ -1,7 +1,7 @@ /* * virprocess.h: interaction with processes * - * Copyright (C) 2010-2014 Red Hat, Inc. + * Copyright (C) 2010-2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -26,6 +26,19 @@ # include "internal.h" # include "virbitmap.h" +# include "virutil.h" + +typedef enum { + VIR_PROC_POLICY_NONE, + VIR_PROC_POLICY_BATCH, + VIR_PROC_POLICY_IDLE, + VIR_PROC_POLICY_FIFO, + VIR_PROC_POLICY_RR, + + VIR_PROC_POLICY_LAST +} virProcessSchedPolicy; + +VIR_ENUM_DECL(virProcessSchedPolicy); char * virProcessTranslateStatus(int status); @@ -73,4 +86,9 @@ typedef int (*virProcessNamespaceCallback)(pid_t pid, void *opaque); int virProcessRunInMountNamespace(pid_t pid, virProcessNamespaceCallback cb, void *opaque); + +int virProcessSetScheduler(pid_t pid, + virProcessSchedPolicy policy, + int priority); + #endif /* __VIR_PROCESS_H__ */ -- 2.3.0

On 10.02.2015 16:35, Martin Kletzander wrote:
This function uses sched_setscheduler() function so it works with processes and threads as well (even threads not created by us, which is what we'll need in the future).
Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- configure.ac | 4 +- src/libvirt_private.syms | 1 + src/util/virprocess.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++- src/util/virprocess.h | 20 ++++++++- 4 files changed, 124 insertions(+), 5 deletions(-)
diff --git a/configure.ac b/configure.ac index 99a2283..b3e99e7 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script.
-dnl Copyright (C) 2005-2014 Red Hat, Inc. +dnl Copyright (C) 2005-2015 Red Hat, Inc. dnl dnl This library is free software; you can redistribute it and/or dnl modify it under the terms of the GNU Lesser General Public @@ -275,7 +275,7 @@ dnl and various less common threadsafe functions AC_CHECK_FUNCS_ONCE([cfmakeraw fallocate geteuid getgid getgrnam_r \ getmntent_r getpwuid_r getuid kill mmap newlocale posix_fallocate \ posix_memalign prlimit regexec sched_getaffinity setgroups setns \ - setrlimit symlink sysctlbyname getifaddrs]) + setrlimit symlink sysctlbyname getifaddrs sched_setscheduler])
dnl Availability of pthread functions. Because of $LIB_PTHREAD, we dnl cannot use AC_CHECK_FUNCS_ONCE. LIB_PTHREAD and LIBMULTITHREAD diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 376c69b..79fc14f 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1915,6 +1915,7 @@ virProcessSetMaxFiles; virProcessSetMaxMemLock; virProcessSetMaxProcesses; virProcessSetNamespaces; +virProcessSetScheduler; virProcessTranslateStatus; virProcessWait;
diff --git a/src/util/virprocess.c b/src/util/virprocess.c index d0a1500..c030d74 100644 --- a/src/util/virprocess.c +++ b/src/util/virprocess.c @@ -1,7 +1,7 @@ /* * virprocess.c: interaction with processes * - * Copyright (C) 2010-2014 Red Hat, Inc. + * Copyright (C) 2010-2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -32,7 +32,9 @@ # include <sys/time.h> # include <sys/resource.h> #endif -#include <sched.h> +#if HAVE_SCHED_SETSCHEDULER +# include <sched.h> +#endif
#if defined(__FreeBSD__) || HAVE_BSD_CPU_AFFINITY # include <sys/param.h> @@ -104,6 +106,13 @@ static inline int setns(int fd ATTRIBUTE_UNUSED, int nstype ATTRIBUTE_UNUSED) } #endif
+VIR_ENUM_IMPL(virProcessSchedPolicy, VIR_PROC_POLICY_LAST, + "none", + "batch", + "idle", + "fifo", + "rr"); + /** * virProcessTranslateStatus: * @status: child exit status to translate @@ -1052,3 +1061,94 @@ virProcessExitWithStatus(int status) } exit(value); } + +#if HAVE_SCHED_SETSCHEDULER + +static int +virProcessSchedTranslatePolicy(virProcessSchedPolicy policy) +{ + switch (policy) { + case VIR_PROC_POLICY_NONE: + return SCHED_OTHER; + + case VIR_PROC_POLICY_BATCH: + return SCHED_BATCH; + + case VIR_PROC_POLICY_IDLE: + return SCHED_IDLE; + + case VIR_PROC_POLICY_FIFO: + return SCHED_FIFO; + + case VIR_PROC_POLICY_RR: + return SCHED_RR; + + case VIR_PROC_POLICY_LAST: + /* nada */ + break; + } + + return -1; +} + +int +virProcessSetScheduler(pid_t pid, virProcessSchedPolicy policy, int priority) +{ + struct sched_param param = {0}; + int pol = virProcessSchedTranslatePolicy(policy); + + VIR_DEBUG("pid=%d, policy=%d, priority=%u", pid, policy, priority); + + if (!policy) + return 0;
In order to do this, you have to make sure enum has a zero value element. I think compilers don't guarantee enum values <-> integer mapping unless told so.
+ + if (pol == SCHED_FIFO || pol == SCHED_RR) { + int min = 0; + int max = 0; + + if ((min = sched_get_priority_min(pol)) < 0) { + virReportSystemError(errno, "%s", + _("Cannot get minimum scheduler " + "priority value")); + return -1; + } + + if ((max = sched_get_priority_max(pol)) < 0) { + virReportSystemError(errno, "%s", + _("Cannot get maximum scheduler " + "priority value")); + return -1; + } + + if (priority < min || priority > max) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Scheduler priority %d out of range [%d, %d]"), + priority, min, max);
CONFIG? I'd say ARGUMENT, but we have the mess in error codes anyway and this doesn't make situation any worse :)
+ return -1; + } + + param.sched_priority = priority; + } + + if (sched_setscheduler(pid, pol, ¶m) < 0) { + virReportSystemError(errno, + _("Cannot set scheduler parameters for pid %d"), + pid); + return -1; + } + + return 0; +} + +#else /* ! HAVE_SCHED_SETSCHEDULER */ + +int +virProcessSetScheduler(pid_t pid, int policy, int priority)
ATTRIBUTE_UNUSED for arguments ^^. Although, would it be worth to copy the check I've pointed out in here too? That is, even if sched_setscheduler() is not available, and virProcessSetScheduler(pid, 0, prio); is called, return success instead of error (of course return error for any other policy than VIR_PROC_POLICY_NONE).
+{ + virReportSystemError(ENOSYS, "%s", + _("Process CPU scheduling is not supported " + "on this platform")); + return -1; +} + +#endif /* !HAVE_SCHED_SETSCHEDULER */ diff --git a/src/util/virprocess.h b/src/util/virprocess.h index bcaede5..8b95560 100644 --- a/src/util/virprocess.h +++ b/src/util/virprocess.h @@ -1,7 +1,7 @@ /* * virprocess.h: interaction with processes * - * Copyright (C) 2010-2014 Red Hat, Inc. + * Copyright (C) 2010-2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -26,6 +26,19 @@
# include "internal.h" # include "virbitmap.h" +# include "virutil.h" + +typedef enum { + VIR_PROC_POLICY_NONE, + VIR_PROC_POLICY_BATCH, + VIR_PROC_POLICY_IDLE, + VIR_PROC_POLICY_FIFO, + VIR_PROC_POLICY_RR, + + VIR_PROC_POLICY_LAST +} virProcessSchedPolicy; + +VIR_ENUM_DECL(virProcessSchedPolicy);
This ^^ introduces virProcessSchedPolicyType{From,To}String(). However, I don't see the symbols exported.
char * virProcessTranslateStatus(int status); @@ -73,4 +86,9 @@ typedef int (*virProcessNamespaceCallback)(pid_t pid, void *opaque); int virProcessRunInMountNamespace(pid_t pid, virProcessNamespaceCallback cb, void *opaque); + +int virProcessSetScheduler(pid_t pid, + virProcessSchedPolicy policy, + int priority); + #endif /* __VIR_PROCESS_H__ */
ACK with all of that fixed. Michal

On 02/11/2015 07:04 AM, Michal Privoznik wrote:
On 10.02.2015 16:35, Martin Kletzander wrote:
This function uses sched_setscheduler() function so it works with processes and threads as well (even threads not created by us, which is what we'll need in the future).
+VIR_ENUM_IMPL(virProcessSchedPolicy, VIR_PROC_POLICY_LAST, + "none", + "batch", + "idle", + "fifo", + "rr"); + /**
+int +virProcessSetScheduler(pid_t pid, virProcessSchedPolicy policy, int priority) +{ + struct sched_param param = {0}; + int pol = virProcessSchedTranslatePolicy(policy); + + VIR_DEBUG("pid=%d, policy=%d, priority=%u", pid, policy, priority); + + if (!policy) + return 0;
In order to do this, you have to make sure enum has a zero value element. I think compilers don't guarantee enum values <-> integer mapping unless told so.
+ +typedef enum { + VIR_PROC_POLICY_NONE, + VIR_PROC_POLICY_BATCH, + VIR_PROC_POLICY_IDLE, + VIR_PROC_POLICY_FIFO, + VIR_PROC_POLICY_RR, + + VIR_PROC_POLICY_LAST +} virProcessSchedPolicy;
The C language guarantees that VIR_PROC_POLICY_NONE == 0, and that VIR_PROC_POLICY_BATCH == (VIR_PROC_POLICY_NONE + 1). That is, C guarantees that an initial enum not otherwise initialized is 0, and that all subsequent enums not otherwise initialized are one more than the previous value (whether or not the previous value was explicitly initialized). So the code you questioned is safe as-is. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 11.02.2015 18:34, Eric Blake wrote:
On 02/11/2015 07:04 AM, Michal Privoznik wrote:
On 10.02.2015 16:35, Martin Kletzander wrote:
<snip/> + +typedef enum { + VIR_PROC_POLICY_NONE, + VIR_PROC_POLICY_BATCH, + VIR_PROC_POLICY_IDLE, + VIR_PROC_POLICY_FIFO, + VIR_PROC_POLICY_RR, + + VIR_PROC_POLICY_LAST +} virProcessSchedPolicy;
The C language guarantees that VIR_PROC_POLICY_NONE == 0, and that VIR_PROC_POLICY_BATCH == (VIR_PROC_POLICY_NONE + 1). That is, C guarantees that an initial enum not otherwise initialized is 0, and that all subsequent enums not otherwise initialized are one more than the previous value (whether or not the previous value was explicitly initialized). So the code you questioned is safe as-is.
So in other words, we don't need zero 'initialization' in enums? So for instance the following (taken from daemon/libvirtd.c:122): enum { VIR_DAEMON_ERR_NONE = 0, /* snip */ }; is the same as enum { VIR_DAEMON_ERR_NONE, /* snip */ }; If it is so, is it worth bothering with cleanup patch(es)? There's roughly 250 occurrences in the code: $ git grep "[A-Z]\+ = 0" | wc -l 268 Michal

On Thu, Feb 12, 2015 at 09:14:29 +0100, Michal Privoznik wrote:
On 11.02.2015 18:34, Eric Blake wrote:
On 02/11/2015 07:04 AM, Michal Privoznik wrote:
On 10.02.2015 16:35, Martin Kletzander wrote:
...
If it is so, is it worth bothering with cleanup patch(es)? There's
Worth? I don't think so ...
roughly 250 occurrences in the code:
$ git grep "[A-Z]\+ = 0" | wc -l
4 bytes (" = 0") removed in 250 instances would save you 1 KiB of space. That's probably less than what I wasted writing this mail.
268
Michal
Peter

On Tue, Feb 10, 2015 at 16:35:19 +0100, Martin Kletzander wrote:
This function uses sched_setscheduler() function so it works with processes and threads as well (even threads not created by us, which is what we'll need in the future).
Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- configure.ac | 4 +- src/libvirt_private.syms | 1 + src/util/virprocess.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++- src/util/virprocess.h | 20 ++++++++- 4 files changed, 124 insertions(+), 5 deletions(-)
...
+#if HAVE_SCHED_SETSCHEDULER + +static int +virProcessSchedTranslatePolicy(virProcessSchedPolicy policy) +{ + switch (policy) { + case VIR_PROC_POLICY_NONE: + return SCHED_OTHER; + + case VIR_PROC_POLICY_BATCH: + return SCHED_BATCH; + + case VIR_PROC_POLICY_IDLE: + return SCHED_IDLE; + + case VIR_PROC_POLICY_FIFO: + return SCHED_FIFO; + + case VIR_PROC_POLICY_RR: + return SCHED_RR; + + case VIR_PROC_POLICY_LAST: + /* nada */
I know I'm late with this comment, but: I don't think the _LAST case is so obscure that we would need to comment it with such an insightful comment.
+ break; + } + + return -1; +} +
Peter

In order for QEMU vCPU (and other) threads to run with RT scheduler, libvirt needs to take care of that so QEMU doesn't have to run privileged. Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1178986 Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- docs/formatdomain.html.in | 16 ++ docs/schemas/domaincommon.rng | 44 +++++ src/conf/domain_conf.c | 183 ++++++++++++++++++++- src/conf/domain_conf.h | 24 +++ .../qemuxml2argv-cputune-iothreadsched-toomuch.xml | 38 +++++ .../qemuxml2argv-cputune-iothreadsched.xml | 39 +++++ .../qemuxml2argv-cputune-vcpusched-overlap.xml | 38 +++++ tests/qemuxml2argvtest.c | 2 + .../qemuxml2xmlout-cputune-iothreadsched.xml | 39 +++++ tests/qemuxml2xmltest.c | 1 + 10 files changed, 423 insertions(+), 1 deletion(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cputune-iothreadsched-toomuch.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cputune-iothreadsched.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cputune-vcpusched-overlap.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-cputune-iothreadsched.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index d8144ea..3381dfe 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -550,6 +550,8 @@ <quota>-1</quota> <emulator_period>1000000</emulator_period> <emulator_quota>-1</emulator_quota> + <vcpusched vcpus='0-4,^3' scheduler='fifo' priority='1'/> + <iothreadsched iothreads='2' scheduler='batch'/> </cputune> ... </domain> @@ -652,6 +654,20 @@ <span class="since">Only QEMU driver support since 0.10.0</span> </dd> + <dt><code>vcpusched</code> and <code>iothreadsched</code></dt> + <dd> + The optional <code>vcpusched</code> elements specifie the scheduler + (values <code>batch</code>, <code>idle</code>, <code>fifo</code>, + <code>rr</code>) for particular vCPU/IOThread threads (based on + <code>vcpus</code> and <code>iothreads</code>, leaving out + <code>vcpus</code>/<code>iothreads</code> sets the default). + For real-time schedulers (<code>fifo</code>, <code>rr</code>), + priority must be specified as well (and is ignored for + non-real-time ones). The value range for the priority depends + on the host kernel (usually 1-99). + <span class="since">Since 1.2.12</span> + </dd> + </dl> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index d467dce..98766dc 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -815,10 +815,54 @@ </attribute> </element> </zeroOrMore> + <zeroOrMore> + <element name="vcpusched"> + <optional> + <attribute name="vcpus"> + <ref name='cpuset'/> + </attribute> + </optional> + <ref name="schedparam"/> + </element> + </zeroOrMore> + <zeroOrMore> + <element name="iothreadsched"> + <optional> + <attribute name="iothreads"> + <ref name='cpuset'/> + </attribute> + </optional> + <ref name="schedparam"/> + </element> + </zeroOrMore> </interleave> </element> </define> + <define name="schedparam"> + <choice> + <group> + <attribute name="scheduler"> + <choice> + <value>batch</value> + <value>idle</value> + </choice> + </attribute> + </group> + <group> + <attribute name="scheduler"> + <choice> + <value>fifo</value> + <value>rr</value> + </choice> + </attribute> + <attribute name="priority"> + <ref name="unsignedShort"/> + </attribute> + </group> + </choice> + </define> + <!-- All the NUMA related tunables would go in the numatune --> <define name="numatune"> <element name="numatune"> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 77319dc..3fb68b3 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -772,6 +772,13 @@ VIR_ENUM_IMPL(virDomainLoader, "rom", "pflash") +VIR_ENUM_IMPL(virDomainThreadSched, VIR_DOMAIN_THREAD_SCHED_LAST, + "other", /* default */ + "batch", + "idle", + "fifo", + "rr") + /* Internal mapping: subset of block job types that can be present in * <mirror> XML (remaining types are not two-phase). */ VIR_ENUM_DECL(virDomainBlockJob) @@ -2234,6 +2241,14 @@ void virDomainDefFree(virDomainDefPtr def) virDomainVcpuPinDefArrayFree(def->cputune.iothreadspin, def->cputune.niothreadspin); + for (i = 0; i < def->cputune.nvcpusched; i++) + virBitmapFree(def->cputune.vcpusched[i].ids); + VIR_FREE(def->cputune.vcpusched); + + for (i = 0; i < def->cputune.niothreadsched; i++) + virBitmapFree(def->cputune.iothreadsched[i].ids); + VIR_FREE(def->cputune.iothreadsched); + virDomainNumatuneFree(def->numatune); virSysinfoDefFree(def->sysinfo); @@ -12595,6 +12610,70 @@ virDomainLoaderDefParseXML(xmlNodePtr node, return ret; } +static int +virDomainThreadSchedParse(xmlNodePtr node, + unsigned int minid, + unsigned int maxid, + const char *name, + virDomainThreadSchedParamPtr sp) +{ + char *tmp = NULL; + int sched = 0; + + tmp = virXMLPropString(node, name); + if (!tmp) { + virReportError(VIR_ERR_XML_ERROR, + _("Missing attribute '%s' in element '%sched'"), + name, name); + goto error; + } + + if (!virBitmapParse(tmp, 0, &sp->ids, + VIR_DOMAIN_CPUMASK_LEN) || + virBitmapIsAllClear(sp->ids) || + virBitmapNextSetBit(sp->ids, -1) < minid || + virBitmapLastSetBit(sp->ids) > maxid) { + + virReportError(VIR_ERR_XML_ERROR, + _("Invalid value of '%s': %s"), + name, tmp); + goto error; + } + VIR_FREE(tmp); + + tmp = virXMLPropString(node, "scheduler"); + if (tmp) { + if ((sched = virDomainThreadSchedTypeFromString(tmp)) <= 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid scheduler attribute: '%s'"), + tmp); + goto error; + } + sp->scheduler = sched; + + VIR_FREE(tmp); + if (sp->scheduler >= VIR_DOMAIN_THREAD_SCHED_FIFO) { + tmp = virXMLPropString(node, "priority"); + if (!tmp) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("Missing scheduler priority")); + goto error; + } + if (virStrToLong_i(tmp, NULL, 10, &sp->priority) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("Invalid value for element priority")); + goto error; + } + VIR_FREE(tmp); + } + } + + return 0; + + error: + VIR_FREE(tmp); + return -1; +} static virDomainDefPtr virDomainDefParseXML(xmlDocPtr xml, @@ -13139,6 +13218,77 @@ virDomainDefParseXML(xmlDocPtr xml, } VIR_FREE(nodes); + if ((n = virXPathNodeSet("./cputune/vcpusched", ctxt, &nodes)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot extract vcpusched nodes")); + goto error; + } + if (n) { + if (n > def->maxvcpus) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("too many vcpusched nodes in cputune")); + goto error; + } + + if (VIR_ALLOC_N(def->cputune.vcpusched, n) < 0) + goto error; + def->cputune.nvcpusched = n; + + for (i = 0; i < def->cputune.nvcpusched; i++) { + if (virDomainThreadSchedParse(nodes[i], + 0, def->maxvcpus - 1, + "vcpus", + &def->cputune.vcpusched[i]) < 0) + goto error; + + for (j = 0; j < i; j++) { + if (virBitmapOverlaps(def->cputune.vcpusched[i].ids, + def->cputune.vcpusched[j].ids)) { + virReportError(VIR_ERR_XML_DETAIL, "%s", + _("vcpusched attributes 'vcpus' " + "must not overlap")); + goto error; + } + } + } + } + VIR_FREE(nodes); + + if ((n = virXPathNodeSet("./cputune/iothreadsched", ctxt, &nodes)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot extract iothreadsched nodes")); + goto error; + } + if (n) { + if (n > def->iothreads) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("too many iothreadsched nodes in cputune")); + goto error; + } + + if (VIR_ALLOC_N(def->cputune.iothreadsched, n) < 0) + goto error; + def->cputune.niothreadsched = n; + + for (i = 0; i < def->cputune.niothreadsched; i++) { + if (virDomainThreadSchedParse(nodes[i], + 1, def->iothreads, + "iothreads", + &def->cputune.iothreadsched[i]) < 0) + goto error; + + for (j = 0; j < i; j++) { + if (virBitmapOverlaps(def->cputune.iothreadsched[i].ids, + def->cputune.iothreadsched[j].ids)) { + virReportError(VIR_ERR_XML_DETAIL, "%s", + _("iothreadsched attributes 'iothreads' " + "must not overlap")); + goto error; + } + } + } + } + VIR_FREE(nodes); /* analysis of cpu handling */ if ((node = virXPathNode("./cpu[1]", ctxt)) != NULL) { @@ -19434,7 +19584,8 @@ virDomainDefFormatInternal(virDomainDefPtr def, def->cputune.period || def->cputune.quota || def->cputune.emulatorpin || def->cputune.emulator_period || def->cputune.emulator_quota || - def->cputune.niothreadspin) { + def->cputune.niothreadspin || + def->cputune.vcpusched || def->cputune.iothreadsched) { virBufferAddLit(buf, "<cputune>\n"); cputune = true; } @@ -19503,6 +19654,36 @@ virDomainDefFormatInternal(virDomainDefPtr def, VIR_FREE(cpumask); } + for (i = 0; i < def->cputune.nvcpusched; i++) { + virDomainThreadSchedParamPtr sp = &def->cputune.vcpusched[i]; + char *ids = NULL; + + if (!(ids = virBitmapFormat(sp->ids))) + goto error; + virBufferAsprintf(buf, "<vcpusched vcpus='%s' scheduler='%s'", + ids, virDomainThreadSchedTypeToString(sp->scheduler)); + VIR_FREE(ids); + + if (sp->priority) + virBufferAsprintf(buf, " priority='%d'", sp->priority); + virBufferAddLit(buf, "/>\n"); + } + + for (i = 0; i < def->cputune.niothreadsched; i++) { + virDomainThreadSchedParamPtr sp = &def->cputune.iothreadsched[i]; + char *ids = NULL; + + if (!(ids = virBitmapFormat(sp->ids))) + goto error; + virBufferAsprintf(buf, "<iothreadsched iothreads='%s' scheduler='%s'", + ids, virDomainThreadSchedTypeToString(sp->scheduler)); + VIR_FREE(ids); + + if (sp->priority) + virBufferAsprintf(buf, " priority='%d'", sp->priority); + virBufferAddLit(buf, "/>\n"); + } + virBufferAdjustIndent(buf, -2); if (cputune) virBufferAddLit(buf, "</cputune>\n"); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 93f2314..6be70bf 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1810,6 +1810,24 @@ typedef enum { VIR_DOMAIN_CPU_PLACEMENT_MODE_LAST } virDomainCpuPlacementMode; +typedef enum { + VIR_DOMAIN_THREAD_SCHED_OTHER = 0, + VIR_DOMAIN_THREAD_SCHED_BATCH, + VIR_DOMAIN_THREAD_SCHED_IDLE, + VIR_DOMAIN_THREAD_SCHED_FIFO, + VIR_DOMAIN_THREAD_SCHED_RR, + + VIR_DOMAIN_THREAD_SCHED_LAST +} virDomainThreadSched; + +typedef struct _virDomainThreadSchedParam virDomainThreadSchedParam; +typedef virDomainThreadSchedParam *virDomainThreadSchedParamPtr; +struct _virDomainThreadSchedParam { + virBitmapPtr ids; + virDomainThreadSched scheduler; + int priority; +}; + typedef struct _virDomainTimerCatchupDef virDomainTimerCatchupDef; typedef virDomainTimerCatchupDef *virDomainTimerCatchupDefPtr; struct _virDomainTimerCatchupDef { @@ -1997,6 +2015,11 @@ struct _virDomainCputune { virDomainVcpuPinDefPtr emulatorpin; size_t niothreadspin; virDomainVcpuPinDefPtr *iothreadspin; + + size_t nvcpusched; + virDomainThreadSchedParamPtr vcpusched; + size_t niothreadsched; + virDomainThreadSchedParamPtr iothreadsched; }; typedef struct _virDomainBlkiotune virDomainBlkiotune; @@ -2844,6 +2867,7 @@ VIR_ENUM_DECL(virDomainRNGModel) VIR_ENUM_DECL(virDomainRNGBackend) VIR_ENUM_DECL(virDomainTPMModel) VIR_ENUM_DECL(virDomainTPMBackend) +VIR_ENUM_DECL(virDomainThreadSched) /* from libvirt.h */ VIR_ENUM_DECL(virDomainState) VIR_ENUM_DECL(virDomainNostateReason) diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cputune-iothreadsched-toomuch.xml b/tests/qemuxml2argvdata/qemuxml2argv-cputune-iothreadsched-toomuch.xml new file mode 100644 index 0000000..1540969 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-cputune-iothreadsched-toomuch.xml @@ -0,0 +1,38 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>2</vcpu> + <iothreads>1</iothreads> + <cputune> + <shares>2048</shares> + <period>1000000</period> + <quota>-1</quota> + <vcpupin vcpu='0' cpuset='0'/> + <vcpupin vcpu='1' cpuset='1'/> + <emulatorpin cpuset='1'/> + <vcpusched vcpus='0-1' scheduler='fifo' priority='1'/> + <iothreadsched iothreads='2' scheduler='batch'/> + </cputune> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <controller type='pci' index='0' model='pci-root'/> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cputune-iothreadsched.xml b/tests/qemuxml2argvdata/qemuxml2argv-cputune-iothreadsched.xml new file mode 100644 index 0000000..0a3ffc7 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-cputune-iothreadsched.xml @@ -0,0 +1,39 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>2</vcpu> + <iothreads>4</iothreads> + <cputune> + <shares>2048</shares> + <period>1000000</period> + <quota>-1</quota> + <vcpupin vcpu='0' cpuset='0'/> + <vcpupin vcpu='1' cpuset='1'/> + <emulatorpin cpuset='1'/> + <vcpusched vcpus='0-1' scheduler='fifo' priority='1'/> + <iothreadsched iothreads='1-3,^2' scheduler='batch'/> + <iothreadsched iothreads='2' scheduler='batch'/> + </cputune> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <controller type='pci' index='0' model='pci-root'/> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cputune-vcpusched-overlap.xml b/tests/qemuxml2argvdata/qemuxml2argv-cputune-vcpusched-overlap.xml new file mode 100644 index 0000000..cbbe7dc --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-cputune-vcpusched-overlap.xml @@ -0,0 +1,38 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>4</vcpu> + <iothreads>1</iothreads> + <cputune> + <shares>2048</shares> + <period>1000000</period> + <quota>-1</quota> + <vcpupin vcpu='0' cpuset='0'/> + <vcpupin vcpu='1' cpuset='1'/> + <emulatorpin cpuset='1'/> + <vcpusched vcpus='0-1' scheduler='fifo' priority='1'/> + <vcpusched vcpus='1-2' scheduler='fifo' priority='1'/> + </cputune> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <controller type='pci' index='0' model='pci-root'/> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index f864c2a..253428a 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1253,6 +1253,8 @@ mymain(void) DO_TEST("blkiotune-device", QEMU_CAPS_NAME); DO_TEST("cputune", QEMU_CAPS_NAME); DO_TEST("cputune-zero-shares", QEMU_CAPS_NAME); + DO_TEST_PARSE_ERROR("cputune-iothreadsched-toomuch", QEMU_CAPS_NAME); + DO_TEST_PARSE_ERROR("cputune-vcpusched-overlap", QEMU_CAPS_NAME); DO_TEST("numatune-memory", NONE); DO_TEST_PARSE_ERROR("numatune-memory-invalid-nodeset", NONE); diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-cputune-iothreadsched.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-cputune-iothreadsched.xml new file mode 100644 index 0000000..9f61336 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-cputune-iothreadsched.xml @@ -0,0 +1,39 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>2</vcpu> + <iothreads>4</iothreads> + <cputune> + <shares>2048</shares> + <period>1000000</period> + <quota>-1</quota> + <vcpupin vcpu='0' cpuset='0'/> + <vcpupin vcpu='1' cpuset='1'/> + <emulatorpin cpuset='1'/> + <vcpusched vcpus='0-1' scheduler='fifo' priority='1'/> + <iothreadsched iothreads='1,3' scheduler='batch'/> + <iothreadsched iothreads='2' scheduler='batch'/> + </cputune> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <controller type='pci' index='0' model='pci-root'/> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index d3dfd9e..915ef54 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -310,6 +310,7 @@ mymain(void) DO_TEST("blkiotune-device"); DO_TEST("cputune"); DO_TEST("cputune-zero-shares"); + DO_TEST_DIFFERENT("cputune-iothreadsched"); DO_TEST("cputune-numatune"); DO_TEST("vcpu-placement-static"); -- 2.3.0

On 10.02.2015 16:35, Martin Kletzander wrote:
In order for QEMU vCPU (and other) threads to run with RT scheduler, libvirt needs to take care of that so QEMU doesn't have to run privileged.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1178986
Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- docs/formatdomain.html.in | 16 ++ docs/schemas/domaincommon.rng | 44 +++++ src/conf/domain_conf.c | 183 ++++++++++++++++++++- src/conf/domain_conf.h | 24 +++ .../qemuxml2argv-cputune-iothreadsched-toomuch.xml | 38 +++++ .../qemuxml2argv-cputune-iothreadsched.xml | 39 +++++ .../qemuxml2argv-cputune-vcpusched-overlap.xml | 38 +++++ tests/qemuxml2argvtest.c | 2 + .../qemuxml2xmlout-cputune-iothreadsched.xml | 39 +++++ tests/qemuxml2xmltest.c | 1 + 10 files changed, 423 insertions(+), 1 deletion(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cputune-iothreadsched-toomuch.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cputune-iothreadsched.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cputune-vcpusched-overlap.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-cputune-iothreadsched.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index d8144ea..3381dfe 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -550,6 +550,8 @@ <quota>-1</quota> <emulator_period>1000000</emulator_period> <emulator_quota>-1</emulator_quota> + <vcpusched vcpus='0-4,^3' scheduler='fifo' priority='1'/> + <iothreadsched iothreads='2' scheduler='batch'/> </cputune> ... </domain> @@ -652,6 +654,20 @@ <span class="since">Only QEMU driver support since 0.10.0</span> </dd>
+ <dt><code>vcpusched</code> and <code>iothreadsched</code></dt> + <dd> + The optional <code>vcpusched</code> elements specifie the scheduler
s/specifie/specifies/ And maybe s/scheduler/scheduler type/?
+ (values <code>batch</code>, <code>idle</code>, <code>fifo</code>, + <code>rr</code>) for particular vCPU/IOThread threads (based on + <code>vcpus</code> and <code>iothreads</code>, leaving out + <code>vcpus</code>/<code>iothreads</code> sets the default). + For real-time schedulers (<code>fifo</code>, <code>rr</code>), + priority must be specified as well (and is ignored for + non-real-time ones). The value range for the priority depends + on the host kernel (usually 1-99). + <span class="since">Since 1.2.12</span> + </dd> + </dl>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index d467dce..98766dc 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -815,10 +815,54 @@ </attribute> </element> </zeroOrMore> + <zeroOrMore> + <element name="vcpusched"> + <optional> + <attribute name="vcpus"> + <ref name='cpuset'/> + </attribute> + </optional> + <ref name="schedparam"/> + </element> + </zeroOrMore> + <zeroOrMore> + <element name="iothreadsched"> + <optional> + <attribute name="iothreads"> + <ref name='cpuset'/> + </attribute> + </optional> + <ref name="schedparam"/> + </element> + </zeroOrMore> </interleave> </element> </define>
+ <define name="schedparam"> + <choice> + <group> + <attribute name="scheduler"> + <choice> + <value>batch</value> + <value>idle</value> + </choice> + </attribute> + </group> + <group> + <attribute name="scheduler"> + <choice> + <value>fifo</value> + <value>rr</value> + </choice> + </attribute> + <attribute name="priority"> + <ref name="unsignedShort"/> + </attribute> + </group> + </choice> + </define> +
Have we returned to the rule where each new XML extension requires ACK from at least one of Daniels?
<!-- All the NUMA related tunables would go in the numatune --> <define name="numatune"> <element name="numatune"> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 77319dc..3fb68b3 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -772,6 +772,13 @@ VIR_ENUM_IMPL(virDomainLoader, "rom", "pflash")
+VIR_ENUM_IMPL(virDomainThreadSched, VIR_DOMAIN_THREAD_SCHED_LAST, + "other", /* default */ + "batch", + "idle", + "fifo", + "rr") + /* Internal mapping: subset of block job types that can be present in * <mirror> XML (remaining types are not two-phase). */ VIR_ENUM_DECL(virDomainBlockJob) @@ -2234,6 +2241,14 @@ void virDomainDefFree(virDomainDefPtr def) virDomainVcpuPinDefArrayFree(def->cputune.iothreadspin, def->cputune.niothreadspin);
+ for (i = 0; i < def->cputune.nvcpusched; i++) + virBitmapFree(def->cputune.vcpusched[i].ids); + VIR_FREE(def->cputune.vcpusched); + + for (i = 0; i < def->cputune.niothreadsched; i++) + virBitmapFree(def->cputune.iothreadsched[i].ids); + VIR_FREE(def->cputune.iothreadsched); + virDomainNumatuneFree(def->numatune);
virSysinfoDefFree(def->sysinfo); @@ -12595,6 +12610,70 @@ virDomainLoaderDefParseXML(xmlNodePtr node, return ret; }
+static int +virDomainThreadSchedParse(xmlNodePtr node, + unsigned int minid, + unsigned int maxid, + const char *name, + virDomainThreadSchedParamPtr sp) +{ + char *tmp = NULL; + int sched = 0; + + tmp = virXMLPropString(node, name); + if (!tmp) { + virReportError(VIR_ERR_XML_ERROR, + _("Missing attribute '%s' in element '%sched'"), + name, name); + goto error; + } + + if (!virBitmapParse(tmp, 0, &sp->ids, + VIR_DOMAIN_CPUMASK_LEN) || + virBitmapIsAllClear(sp->ids) || + virBitmapNextSetBit(sp->ids, -1) < minid || + virBitmapLastSetBit(sp->ids) > maxid) { + + virReportError(VIR_ERR_XML_ERROR, + _("Invalid value of '%s': %s"), + name, tmp); + goto error; + } + VIR_FREE(tmp); + + tmp = virXMLPropString(node, "scheduler"); + if (tmp) { + if ((sched = virDomainThreadSchedTypeFromString(tmp)) <= 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid scheduler attribute: '%s'"), + tmp); + goto error; + } + sp->scheduler = sched; + + VIR_FREE(tmp); + if (sp->scheduler >= VIR_DOMAIN_THREAD_SCHED_FIFO) { + tmp = virXMLPropString(node, "priority"); + if (!tmp) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("Missing scheduler priority")); + goto error; + } + if (virStrToLong_i(tmp, NULL, 10, &sp->priority) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("Invalid value for element priority")); + goto error; + } + VIR_FREE(tmp); + } + } + + return 0; + + error: + VIR_FREE(tmp); + return -1; +}
static virDomainDefPtr virDomainDefParseXML(xmlDocPtr xml, @@ -13139,6 +13218,77 @@ virDomainDefParseXML(xmlDocPtr xml, } VIR_FREE(nodes);
+ if ((n = virXPathNodeSet("./cputune/vcpusched", ctxt, &nodes)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot extract vcpusched nodes")); + goto error; + } + if (n) { + if (n > def->maxvcpus) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("too many vcpusched nodes in cputune")); + goto error; + } + + if (VIR_ALLOC_N(def->cputune.vcpusched, n) < 0) + goto error; + def->cputune.nvcpusched = n; + + for (i = 0; i < def->cputune.nvcpusched; i++) { + if (virDomainThreadSchedParse(nodes[i], + 0, def->maxvcpus - 1, + "vcpus", + &def->cputune.vcpusched[i]) < 0) + goto error; + + for (j = 0; j < i; j++) { + if (virBitmapOverlaps(def->cputune.vcpusched[i].ids, + def->cputune.vcpusched[j].ids)) { + virReportError(VIR_ERR_XML_DETAIL, "%s", + _("vcpusched attributes 'vcpus' " + "must not overlap")); + goto error; + } + } + } + } + VIR_FREE(nodes); + + if ((n = virXPathNodeSet("./cputune/iothreadsched", ctxt, &nodes)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot extract iothreadsched nodes")); + goto error; + } + if (n) { + if (n > def->iothreads) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("too many iothreadsched nodes in cputune")); + goto error; + } + + if (VIR_ALLOC_N(def->cputune.iothreadsched, n) < 0) + goto error; + def->cputune.niothreadsched = n; + + for (i = 0; i < def->cputune.niothreadsched; i++) { + if (virDomainThreadSchedParse(nodes[i], + 1, def->iothreads, + "iothreads", + &def->cputune.iothreadsched[i]) < 0) + goto error; + + for (j = 0; j < i; j++) { + if (virBitmapOverlaps(def->cputune.iothreadsched[i].ids, + def->cputune.iothreadsched[j].ids)) { + virReportError(VIR_ERR_XML_DETAIL, "%s", + _("iothreadsched attributes 'iothreads' " + "must not overlap")); + goto error; + } + } + } + } + VIR_FREE(nodes);
Once parsed, do we also need a check in virDomainDefCheckABIStability()? Or can the sched parameters change on migration? I guess they can, but seems like you dig more into this area than me recently.
/* analysis of cpu handling */ if ((node = virXPathNode("./cpu[1]", ctxt)) != NULL) { @@ -19434,7 +19584,8 @@ virDomainDefFormatInternal(virDomainDefPtr def, def->cputune.period || def->cputune.quota || def->cputune.emulatorpin || def->cputune.emulator_period || def->cputune.emulator_quota || - def->cputune.niothreadspin) { + def->cputune.niothreadspin || + def->cputune.vcpusched || def->cputune.iothreadsched) { virBufferAddLit(buf, "<cputune>\n"); cputune = true; } @@ -19503,6 +19654,36 @@ virDomainDefFormatInternal(virDomainDefPtr def, VIR_FREE(cpumask); }
+ for (i = 0; i < def->cputune.nvcpusched; i++) { + virDomainThreadSchedParamPtr sp = &def->cputune.vcpusched[i]; + char *ids = NULL; + + if (!(ids = virBitmapFormat(sp->ids))) + goto error; + virBufferAsprintf(buf, "<vcpusched vcpus='%s' scheduler='%s'", + ids, virDomainThreadSchedTypeToString(sp->scheduler)); + VIR_FREE(ids); + + if (sp->priority) + virBufferAsprintf(buf, " priority='%d'", sp->priority); + virBufferAddLit(buf, "/>\n"); + } + + for (i = 0; i < def->cputune.niothreadsched; i++) { + virDomainThreadSchedParamPtr sp = &def->cputune.iothreadsched[i]; + char *ids = NULL; + + if (!(ids = virBitmapFormat(sp->ids))) + goto error; + virBufferAsprintf(buf, "<iothreadsched iothreads='%s' scheduler='%s'", + ids, virDomainThreadSchedTypeToString(sp->scheduler)); + VIR_FREE(ids); + + if (sp->priority) + virBufferAsprintf(buf, " priority='%d'", sp->priority); + virBufferAddLit(buf, "/>\n"); + } + virBufferAdjustIndent(buf, -2); if (cputune) virBufferAddLit(buf, "</cputune>\n"); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 93f2314..6be70bf 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1810,6 +1810,24 @@ typedef enum { VIR_DOMAIN_CPU_PLACEMENT_MODE_LAST } virDomainCpuPlacementMode;
+typedef enum { + VIR_DOMAIN_THREAD_SCHED_OTHER = 0, + VIR_DOMAIN_THREAD_SCHED_BATCH, + VIR_DOMAIN_THREAD_SCHED_IDLE, + VIR_DOMAIN_THREAD_SCHED_FIFO, + VIR_DOMAIN_THREAD_SCHED_RR, + + VIR_DOMAIN_THREAD_SCHED_LAST +} virDomainThreadSched; + +typedef struct _virDomainThreadSchedParam virDomainThreadSchedParam; +typedef virDomainThreadSchedParam *virDomainThreadSchedParamPtr; +struct _virDomainThreadSchedParam { + virBitmapPtr ids; + virDomainThreadSched scheduler; + int priority; +}; + typedef struct _virDomainTimerCatchupDef virDomainTimerCatchupDef; typedef virDomainTimerCatchupDef *virDomainTimerCatchupDefPtr; struct _virDomainTimerCatchupDef { @@ -1997,6 +2015,11 @@ struct _virDomainCputune { virDomainVcpuPinDefPtr emulatorpin; size_t niothreadspin; virDomainVcpuPinDefPtr *iothreadspin; + + size_t nvcpusched; + virDomainThreadSchedParamPtr vcpusched; + size_t niothreadsched; + virDomainThreadSchedParamPtr iothreadsched; };
typedef struct _virDomainBlkiotune virDomainBlkiotune; @@ -2844,6 +2867,7 @@ VIR_ENUM_DECL(virDomainRNGModel) VIR_ENUM_DECL(virDomainRNGBackend) VIR_ENUM_DECL(virDomainTPMModel) VIR_ENUM_DECL(virDomainTPMBackend) +VIR_ENUM_DECL(virDomainThreadSched)
Yet another ENUM_DECL without corresponding libvirt_private.syms change.
/* from libvirt.h */ VIR_ENUM_DECL(virDomainState) VIR_ENUM_DECL(virDomainNostateReason)
ACK with all of that fixed. Michal

On Wed, Feb 11, 2015 at 03:04:34PM +0100, Michal Privoznik wrote:
On 10.02.2015 16:35, Martin Kletzander wrote:
In order for QEMU vCPU (and other) threads to run with RT scheduler, libvirt needs to take care of that so QEMU doesn't have to run privileged.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1178986
Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- docs/formatdomain.html.in | 16 ++ docs/schemas/domaincommon.rng | 44 +++++ src/conf/domain_conf.c | 183 ++++++++++++++++++++- src/conf/domain_conf.h | 24 +++ .../qemuxml2argv-cputune-iothreadsched-toomuch.xml | 38 +++++ .../qemuxml2argv-cputune-iothreadsched.xml | 39 +++++ .../qemuxml2argv-cputune-vcpusched-overlap.xml | 38 +++++ tests/qemuxml2argvtest.c | 2 + .../qemuxml2xmlout-cputune-iothreadsched.xml | 39 +++++ tests/qemuxml2xmltest.c | 1 + 10 files changed, 423 insertions(+), 1 deletion(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cputune-iothreadsched-toomuch.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cputune-iothreadsched.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cputune-vcpusched-overlap.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-cputune-iothreadsched.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index d8144ea..3381dfe 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -550,6 +550,8 @@ <quota>-1</quota> <emulator_period>1000000</emulator_period> <emulator_quota>-1</emulator_quota> + <vcpusched vcpus='0-4,^3' scheduler='fifo' priority='1'/> + <iothreadsched iothreads='2' scheduler='batch'/> </cputune> ... </domain> @@ -652,6 +654,20 @@ <span class="since">Only QEMU driver support since 0.10.0</span> </dd>
+ <dt><code>vcpusched</code> and <code>iothreadsched</code></dt> + <dd> + The optional <code>vcpusched</code> elements specifie the scheduler
s/specifie/specifies/
And maybe s/scheduler/scheduler type/?
I went with "scheduler type". [...]
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index d467dce..98766dc 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -815,10 +815,54 @@ </attribute> </element> </zeroOrMore> + <zeroOrMore> + <element name="vcpusched"> + <optional> + <attribute name="vcpus"> + <ref name='cpuset'/> + </attribute> + </optional> + <ref name="schedparam"/> + </element> + </zeroOrMore> + <zeroOrMore> + <element name="iothreadsched"> + <optional> + <attribute name="iothreads"> + <ref name='cpuset'/> + </attribute> + </optional> + <ref name="schedparam"/> + </element> + </zeroOrMore> </interleave> </element> </define>
+ <define name="schedparam"> + <choice> + <group> + <attribute name="scheduler"> + <choice> + <value>batch</value> + <value>idle</value> + </choice> + </attribute> + </group> + <group> + <attribute name="scheduler"> + <choice> + <value>fifo</value> + <value>rr</value> + </choice> + </attribute> + <attribute name="priority"> + <ref name="unsignedShort"/> + </attribute> + </group> + </choice> + </define> +
Have we returned to the rule where each new XML extension requires ACK from at least one of Daniels?
Not that I know of. Not that I know that there was such a rule. [...]
@@ -13139,6 +13218,77 @@ virDomainDefParseXML(xmlDocPtr xml, } VIR_FREE(nodes);
+ if ((n = virXPathNodeSet("./cputune/vcpusched", ctxt, &nodes)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot extract vcpusched nodes")); + goto error; + } + if (n) { + if (n > def->maxvcpus) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("too many vcpusched nodes in cputune")); + goto error; + } + + if (VIR_ALLOC_N(def->cputune.vcpusched, n) < 0) + goto error; + def->cputune.nvcpusched = n; + + for (i = 0; i < def->cputune.nvcpusched; i++) { + if (virDomainThreadSchedParse(nodes[i], + 0, def->maxvcpus - 1, + "vcpus", + &def->cputune.vcpusched[i]) < 0) + goto error; + + for (j = 0; j < i; j++) { + if (virBitmapOverlaps(def->cputune.vcpusched[i].ids, + def->cputune.vcpusched[j].ids)) { + virReportError(VIR_ERR_XML_DETAIL, "%s", + _("vcpusched attributes 'vcpus' " + "must not overlap")); + goto error; + } + } + } + } + VIR_FREE(nodes); + + if ((n = virXPathNodeSet("./cputune/iothreadsched", ctxt, &nodes)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot extract iothreadsched nodes")); + goto error; + } + if (n) { + if (n > def->iothreads) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("too many iothreadsched nodes in cputune")); + goto error; + } + + if (VIR_ALLOC_N(def->cputune.iothreadsched, n) < 0) + goto error; + def->cputune.niothreadsched = n; + + for (i = 0; i < def->cputune.niothreadsched; i++) { + if (virDomainThreadSchedParse(nodes[i], + 1, def->iothreads, + "iothreads", + &def->cputune.iothreadsched[i]) < 0) + goto error; + + for (j = 0; j < i; j++) { + if (virBitmapOverlaps(def->cputune.iothreadsched[i].ids, + def->cputune.iothreadsched[j].ids)) { + virReportError(VIR_ERR_XML_DETAIL, "%s", + _("iothreadsched attributes 'iothreads' " + "must not overlap")); + goto error; + } + } + } + } + VIR_FREE(nodes);
Once parsed, do we also need a check in virDomainDefCheckABIStability()? Or can the sched parameters change on migration? I guess they can, but seems like you dig more into this area than me recently.
No, this is something QEMU has no idea about and it's something users can change themselves (when having the right privilege, of course). [...]
@@ -2844,6 +2867,7 @@ VIR_ENUM_DECL(virDomainRNGModel) VIR_ENUM_DECL(virDomainRNGBackend) VIR_ENUM_DECL(virDomainTPMModel) VIR_ENUM_DECL(virDomainTPMBackend) +VIR_ENUM_DECL(virDomainThreadSched)
Yet another ENUM_DECL without corresponding libvirt_private.syms change.
Ouch!
/* from libvirt.h */ VIR_ENUM_DECL(virDomainState) VIR_ENUM_DECL(virDomainNostateReason)
ACK with all of that fixed.
Michal
Thanks.

On 02/10/2015 08:35 AM, Martin Kletzander wrote:
In order for QEMU vCPU (and other) threads to run with RT scheduler, libvirt needs to take care of that so QEMU doesn't have to run privileged.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1178986
Might be nice to also show a sample XML usage in the commit message.
Signed-off-by: Martin Kletzander <mkletzan@redhat.com> ---
+++ b/docs/formatdomain.html.in @@ -550,6 +550,8 @@ <quota>-1</quota> <emulator_period>1000000</emulator_period> <emulator_quota>-1</emulator_quota> + <vcpusched vcpus='0-4,^3' scheduler='fifo' priority='1'/> + <iothreadsched iothreads='2' scheduler='batch'/> </cputune> ... </domain> @@ -652,6 +654,20 @@ <span class="since">Only QEMU driver support since 0.10.0</span> </dd>
+ <dt><code>vcpusched</code> and <code>iothreadsched</code></dt> + <dd> + The optional <code>vcpusched</code> elements specifie the scheduler + (values <code>batch</code>, <code>idle</code>, <code>fifo</code>, + <code>rr</code>) for particular vCPU/IOThread threads (based on + <code>vcpus</code> and <code>iothreads</code>, leaving out + <code>vcpus</code>/<code>iothreads</code> sets the default). + For real-time schedulers (<code>fifo</code>, <code>rr</code>), + priority must be specified as well (and is ignored for + non-real-time ones). The value range for the priority depends + on the host kernel (usually 1-99). + <span class="since">Since 1.2.12</span>
1.2.13, actually. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On Wed, Feb 11, 2015 at 10:37:46AM -0700, Eric Blake wrote:
On 02/10/2015 08:35 AM, Martin Kletzander wrote:
In order for QEMU vCPU (and other) threads to run with RT scheduler, libvirt needs to take care of that so QEMU doesn't have to run privileged.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1178986
Might be nice to also show a sample XML usage in the commit message.
Oh, sorry for that, will do next time! [...]
@@ -652,6 +654,20 @@ <span class="since">Only QEMU driver support since 0.10.0</span> </dd>
+ <dt><code>vcpusched</code> and <code>iothreadsched</code></dt> + <dd> + The optional <code>vcpusched</code> elements specifie the scheduler + (values <code>batch</code>, <code>idle</code>, <code>fifo</code>, + <code>rr</code>) for particular vCPU/IOThread threads (based on + <code>vcpus</code> and <code>iothreads</code>, leaving out + <code>vcpus</code>/<code>iothreads</code> sets the default). + For real-time schedulers (<code>fifo</code>, <code>rr</code>), + priority must be specified as well (and is ignored for + non-real-time ones). The value range for the priority depends + on the host kernel (usually 1-99). + <span class="since">Since 1.2.12</span>
1.2.13, actually.
Fixed as a trivial with this commit: commit a0638ff21972fdbfdd11e56c271e85480aee7620 Author: Martin Kletzander <mkletzan@redhat.com> Date: Thu Feb 12 13:29:08 2015 +0100 docs: Fix version reference in vcpu/iothread scheduling Signed-off-by: Martin Kletzander <mkletzan@redhat.com> diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index fcf5984..873a1c7 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -664,7 +664,7 @@ real-time schedulers (<code>fifo</code>, <code>rr</code>), priority must be specified as well (and is ignored for non-real-time ones). The value range for the priority depends on the host kernel (usually 1-99). - <span class="since">Since 1.2.12</span> + <span class="since">Since 1.2.13</span> </dd> </dl> --

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1178986 Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- src/qemu/qemu_driver.c | 5 +++++ src/qemu/qemu_process.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++- src/qemu/qemu_process.h | 5 ++++- 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index cf351e6..087a69d 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4617,6 +4617,11 @@ static int qemuDomainHotplugVcpus(virQEMUDriverPtr driver, } virCgroupFree(&cgroup_vcpu); + + if (qemuProcessSetSchedParams(i, cpupids[i], + vm->def->cputune.nvcpusched, + vm->def->cputune.vcpusched) < 0) + goto cleanup; } } else { for (i = oldvcpus - 1; i >= nvcpus; i--) { diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index d5df60d..4773120 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -1,7 +1,7 @@ /* * qemu_process.c: QEMU process management * - * Copyright (C) 2006-2014 Red Hat, Inc. + * Copyright (C) 2006-2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -2574,6 +2574,57 @@ qemuProcessSetIOThreadsAffinity(virDomainObjPtr vm) return ret; } +/* Set Scheduler parameters for vCPU or I/O threads. */ +int +qemuProcessSetSchedParams(int id, + pid_t pid, + size_t nsp, + virDomainThreadSchedParamPtr sp) +{ + bool val = false; + size_t i = 0; + virDomainThreadSchedParamPtr s = NULL; + + for (i = 0; i < nsp; i++) { + if (virBitmapGetBit(sp[i].ids, id, &val) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot get bit from bitmap")); + } + if (val) { + s = &sp[i]; + break; + } + } + + if (!s) + return 0; + + return virProcessSetScheduler(pid, s->scheduler, s->priority); +} + +static int +qemuProcessSetSchedulers(virDomainObjPtr vm) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + size_t i = 0; + + for (i = 0; i < priv->nvcpupids; i++) { + if (qemuProcessSetSchedParams(i, priv->vcpupids[i], + vm->def->cputune.nvcpusched, + vm->def->cputune.vcpusched) < 0) + return -1; + } + + for (i = 0; i < priv->niothreadpids; i++) { + if (qemuProcessSetSchedParams(i + 1, priv->iothreadpids[i], + vm->def->cputune.niothreadsched, + vm->def->cputune.iothreadsched) < 0) + return -1; + } + + return 0; +} + static int qemuProcessInitPasswords(virConnectPtr conn, virQEMUDriverPtr driver, @@ -4869,6 +4920,10 @@ int qemuProcessStart(virConnectPtr conn, if (qemuProcessSetIOThreadsAffinity(vm) < 0) goto cleanup; + VIR_DEBUG("Setting scheduler parameters"); + if (qemuProcessSetSchedulers(vm) < 0) + goto cleanup; + VIR_DEBUG("Setting any required VM passwords"); if (qemuProcessInitPasswords(conn, driver, vm, asyncJob) < 0) goto cleanup; diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h index 5948ea4..2e1d393 100644 --- a/src/qemu/qemu_process.h +++ b/src/qemu/qemu_process.h @@ -1,7 +1,7 @@ /* * qemu_process.h: QEMU process management * - * Copyright (C) 2006-2012 Red Hat, Inc. + * Copyright (C) 2006-2012, 2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -104,4 +104,7 @@ virBitmapPtr qemuPrepareCpumap(virQEMUDriverPtr driver, int qemuProcessReadLog(int fd, char *buf, int buflen, int off, bool skipchar); +int qemuProcessSetSchedParams(int id, pid_t pid, size_t nsp, + virDomainThreadSchedParamPtr sp); + #endif /* __QEMU_PROCESS_H__ */ -- 2.3.0

On 10.02.2015 16:35, Martin Kletzander wrote:
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1178986
Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- src/qemu/qemu_driver.c | 5 +++++ src/qemu/qemu_process.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++- src/qemu/qemu_process.h | 5 ++++- 3 files changed, 65 insertions(+), 2 deletions(-)
ACK Michal
participants (4)
-
Eric Blake
-
Martin Kletzander
-
Michal Privoznik
-
Peter Krempa