Currently it is possible to set the CPU affinity and sched tunables for threads
running on a system. However, tuna does not permit to start a new application
with these parameters set.
This patch adds the ability to start a new process with its affinity and sched
tunable set before it starts to run.
To do so, two new parameters were added to tuna's command line. These parameters
are composed by a Modifier:
-T, --sched_tunable=[POLICY:]RTPRIO
Define scheduler tunables: POLICY and RTPRIO for an Action. POLICY
is one of OTHER, FIFO, RR, or BATCH.
And an Action:
-r, --run="COMMAND"
Run a command. If arguments are passed, the entire command line
must be provided inside "quotes". Modifiers -c and -T can be used to
set the affinity and scheduler tunables of the given command.
The option -T was needed because the current parameter to set the sched tunables
is an Action.
The option -r will fork a new process, set the sched tunables and affinity, and
execute the new application's binary.
Tuna will wait for the new process to return, and then continue its execution
That means that it is possible to execute many Actions after the creation of
a new process, including the start of many process in a single command line.
Example of use:
[***@kiron bristot]# tuna -c 2 -T fifo:2 -r httpd -t httpd -P
thread ctxt_switches
pid SCHED_ rtpri affinity voluntary nonvoluntary cmd
31624 FIFO 2 2 1 0 httpd
In this example, a new httpd process was started with affinity set to the
CPU 2, and with FIFO:2 sched. Then the new httpd process was printed by the
option -P.
Reviewed-by: Luis Claudio R. Goncalves <***@redhat.com>
Signed-off-by: Daniel Bristot de Oliveira <***@bristot.me>
---
tuna-cmd.py | 17 +++++++++++++++--
tuna/tuna.py | 59 ++++++++++++++++++++++++++++++++++++++++++++++-------------
2 files changed, 61 insertions(+), 15 deletions(-)
diff --git a/tuna-cmd.py b/tuna-cmd.py
index cc21656..24a667a 100755
--- a/tuna-cmd.py
+++ b/tuna-cmd.py
@@ -68,6 +68,8 @@ def usage():
print fmt % ('-Q, --show_irqs', _('Show IRQ list'))
print fmt % ('-q, --irqs=' + _('IRQ-LIST'), _('%(irqlist)s affected by commands') %
{"irqlist": _('IRQ-LIST')})
+ print fmt % ('-r, --run=' + _('COMMAND'), _('fork a new process and run the %(command)s') % \
+ {"command": _('COMMAND')})
print fmt % ('-s, --save=' + _('FILENAME'), _('Save kthreads sched tunables to %(filename)s') % \
{"filename": _('FILENAME')})
print fmt % ('-S, --sockets=' +
@@ -76,6 +78,10 @@ def usage():
print fmt % ('-t, --threads=' +
_('THREAD-LIST'), _('%(threadlist)s affected by commands') % \
{"threadlist": _('THREAD-LIST')})
+ print fmt % ('-T, --sched_tunables=[' +
+ _('POLICY') + ':]' +
+ _('RTPRIO'), _('Define scheduler tunables: %(policy)s and %(rtprio)s an Action') % \
+ {"policy": _('POLICY'), "rtprio": _('RTPRIO')})
print fmt % ('-U, --no_uthreads', _('Operations will not affect user threads'))
print fmt % ('-v, --version', _('Show version'))
print fmt % ('-W, --what_is', _('Provides help about selected entities'))
@@ -449,13 +455,14 @@ def main():
i18n_init()
try:
- short = "a:c:CfgGhiIKlmp:PQq:s:S:t:UvWx"
+ short = "a:c:CfgGhiIKlmp:PQq:r:s:S:t:T:UvWx"
long = ["cpus=", "affect_children", "filter", "gui", "help",
"isolate", "include", "no_kthreads", "move",
"show_sockets", "priority=", "show_threads",
"show_irqs", "irqs=",
"save=", "sockets=", "threads=", "no_uthreads",
- "version", "what_is", "spread","cgroup","config_file_apply=","config_file_list="]
+ "version", "what_is", "spread","cgroup","config_file_apply=","config_file_list=",
+ "run=", "sched_tunable="]
if have_inet_diag:
short += "n"
long.append("show_sockets")
@@ -472,6 +479,8 @@ def main():
cpu_list = None
irq_list = None
irq_list_str = None
+ rtprio = None
+ policy = None
thread_list = []
thread_list_str = None
filter = False
@@ -622,6 +631,10 @@ def main():
sys.exit(2)
for tid in thread_list:
thread_help(tid)
+ elif o in ("-T", "--sched_tunable"):
+ (policy, rtprio) = tuna.get_policy_and_rtprio(a)
+ elif o in ("-r", "--run"):
+ tuna.run_command(a, policy, rtprio, cpu_list)
if run_gui:
try:
diff --git a/tuna/tuna.py b/tuna/tuna.py
index 49c9eab..f562746 100755
--- a/tuna/tuna.py
+++ b/tuna/tuna.py
@@ -1,7 +1,7 @@
# -*- python -*-
# -*- coding: utf-8 -*-
-import copy, ethtool, os, procfs, re, schedutils
+import copy, ethtool, os, procfs, re, schedutils, sys, shlex
import help, fnmatch
try:
@@ -455,6 +455,22 @@ def get_irq_affinity_text(irqs, irq):
# needs root prio to read /proc/irq/<NUM>/smp_affinity
return ""
+def get_policy_and_rtprio(parm):
+ parms = parm.split(":")
+ rtprio = 0
+ policy = None
+ if parms[0].upper() in ["OTHER", "BATCH", "IDLE", "FIFO", "RR"]:
+ policy = schedutils.schedfromstr("SCHED_%s" % parms[0].upper())
+ if len(parms) > 1:
+ rtprio = int(parms[1])
+ elif parms[0].upper() in ["FIFO", "RR"]:
+ rtprio = 1
+ elif parms[0].isdigit():
+ rtprio = int(parms[0])
+ else:
+ raise ValueError
+ return (policy, rtprio)
+
def thread_filtered(tid, cpus_filtered, show_kthreads, show_uthreads):
if cpus_filtered:
try:
@@ -489,18 +505,9 @@ def thread_set_priority(tid, policy, rtprio):
schedutils.set_scheduler(tid, policy, rtprio)
def threads_set_priority(tids, parm, affect_children = False):
- parms = parm.split(":")
- rtprio = 0
- policy = None
- if parms[0].upper() in ["OTHER", "BATCH", "IDLE", "FIFO", "RR"]:
- policy = schedutils.schedfromstr("SCHED_%s" % parms[0].upper())
- if len(parms) > 1:
- rtprio = int(parms[1])
- elif parms[0].upper() in ["FIFO", "RR"]:
- rtprio = 1
- elif parms[0].isdigit():
- rtprio = int(parms[0])
- else:
+ try:
+ (policy, rtprio) = get_policy_and_rtprio(parm)
+ except ValueError:
print "tuna: " + _("\"%s\" is unsupported priority value!") % parms[0]
return
@@ -559,6 +566,32 @@ def get_kthread_sched_tunings(proc = None):
return kthreads
+def run_command(cmd, policy, rtprio, cpu_list):
+ newpid = os.fork()
+ if newpid == 0:
+ cmd_list = shlex.split(cmd)
+ pid = os.getpid()
+ if rtprio:
+ try:
+ thread_set_priority(pid, policy, rtprio)
+ except (SystemError, OSError) as err:
+ print "tuna: %s" % err
+ sys.exit(2)
+ if cpu_list:
+ try:
+ schedutils.set_affinity(pid, cpu_list)
+ except (SystemError, OSError) as err:
+ print "tuna: %s" % err
+ sys.exit(2)
+
+ try:
+ os.execvp(cmd_list[0], cmd_list)
+ except (SystemError, OSError) as err:
+ print "tuna: %s" % err
+ sys.exit(2)
+ else:
+ os.waitpid(newpid, 0);
+
def generate_rtgroups(filename, kthreads, nr_cpus):
f = file(filename, "w")
f.write('''# Generated by tuna
--
1.9.3