734 lines
32 KiB
Diff
734 lines
32 KiB
Diff
From eba1333c50f8a5eebb12b523c30faffac33681b3 Mon Sep 17 00:00:00 2001
|
|
From: Leah Leshchinsky <lleshchi@redhat.com>
|
|
Date: Thu, 4 Aug 2022 09:39:10 -0400
|
|
Subject: [PATCH 1/6] tuna: Update command-line interface
|
|
|
|
The current command-line interface allows for chaining of multiple
|
|
actions, which results in ambiguous user input, a need for maintaining
|
|
variable states (thread-list, cpu-list, etc.) in the program, and a need
|
|
to type check input after parsing. The help menu can also be
|
|
overwhelming.
|
|
|
|
Allow for the use of argparse rather than getopt to significantly
|
|
simplify the program.
|
|
Provide subcommands and clearer usage menus for the user,
|
|
introduce type checking at the parser level, and remove
|
|
ambiguity for user input.
|
|
|
|
Signed-off-by: Leah Leshchinsky <lleshchi@redhat.com>
|
|
Signed-off-by: John Kacur <jkacur@redhat.com>
|
|
|
|
diff --git a/tuna-cmd.py b/tuna-cmd.py
|
|
index bdaa70ffc156..f49cce4d84d4 100755
|
|
--- a/tuna-cmd.py
|
|
+++ b/tuna-cmd.py
|
|
@@ -14,8 +14,9 @@
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# General Public License for more details.
|
|
|
|
-""" tuna - Application Tuning GUI """
|
|
+""" tuna - Application Tuning Program"""
|
|
|
|
+import argparse
|
|
import os
|
|
import sys
|
|
import errno
|
|
@@ -37,7 +38,7 @@ def get_loglevel(level):
|
|
# logging built-in module levels:
|
|
# 0 - NOTSET
|
|
# 10 - DEBUG
|
|
- # 20 - INFO,
|
|
+ # 20 - INFO
|
|
# 30 - WARNING
|
|
# 40 - ERROR
|
|
return int(level) * 10
|
|
@@ -85,70 +86,138 @@ except:
|
|
nr_cpus = None
|
|
ps = None
|
|
irqs = None
|
|
-version = "0.18"
|
|
-
|
|
-
|
|
-def usage():
|
|
- print(_('Usage: tuna [OPTIONS]'))
|
|
- fmt = '\t%-40s %s'
|
|
- print(fmt % ('-h, --help', _('Give this help list')))
|
|
- print(fmt % ('-a, --config_file_apply=profilename',
|
|
- _('Apply changes described in profile')))
|
|
- print(fmt % ('-l, --config_file_list',
|
|
- _('List preloaded profiles')))
|
|
- print(fmt % ('-g, --gui', _('Start the GUI')))
|
|
- print(fmt % ('-G, --cgroup',
|
|
- _('Display the processes with the type of cgroups they are in')))
|
|
- print(fmt % ('-c, --cpus=' + _('CPU-LIST'), _('%(cpulist)s affected by commands') %
|
|
- {"cpulist": _('CPU-LIST')}))
|
|
- print(fmt % ('-C, --affect_children',
|
|
- _('Operation will affect children threads')))
|
|
- print(fmt % ('-d, --disable_perf',
|
|
- _('Explicitly disable usage of perf in GUI for process view')))
|
|
- print(fmt % ('-D, --debug', _('Print DEBUG level logging details to console')))
|
|
- print(fmt % ('-f, --filter',
|
|
- _('Display filter the selected entities')))
|
|
- print(fmt % ('-i, --isolate', _('Move all allowed threads and IRQs away from %(cpulist)s') %
|
|
- {"cpulist": _('CPU-LIST')}))
|
|
- print(fmt % ('-I, --include', _('Allow all allowed threads and IRQs to run on %(cpulist)s') %
|
|
- {"cpulist": _('CPU-LIST')}))
|
|
- print(fmt % ('-K, --no_kthreads',
|
|
- _('Operations will not affect kernel threads')))
|
|
- print(fmt % ('-L, --logging',
|
|
- _('Log application details to log file for given LOG-LEVEL')))
|
|
- print(fmt % ('-m, --move', _('Move selected entities to %(cpulist)s') %
|
|
- {"cpulist": _('CPU-LIST')}))
|
|
- print(fmt % ('-N, --nohz_full',
|
|
- _('CPUs in nohz_full= kernel command line will be affected by operations')))
|
|
+
|
|
+class HelpMessageParser(argparse.ArgumentParser):
|
|
+ def error(self, message):
|
|
+ sys.stderr.write('error: %s\n' % message)
|
|
+ self.print_help()
|
|
+ sys.exit(2)
|
|
+
|
|
+def gen_parser():
|
|
+
|
|
+
|
|
+ POS = {
|
|
+ "cpu_list": dict(metavar='CPU-LIST', type=tuna.cpustring_to_list, help="CPU-LIST affected by commands"),
|
|
+ "thread_list": dict(metavar='THREAD-LIST', type=threadstring_to_list, help="THREAD-LIST affected by commands"),
|
|
+ "filename": dict(metavar='FILENAME', type=str, help="Save kthreads sched tunables to this file"),
|
|
+ "profilename": dict(type=str, help="Apply changes described in this file"),
|
|
+ "run_command": dict(metavar='COMMAND', type=str, help="fork a new process and run the \"COMMAND\""),
|
|
+ "priority": dict(type=str, help="policy/priority help"),
|
|
+ }
|
|
+
|
|
+ MODS = {
|
|
+ "logging": dict(dest='loglevel', metavar='LOG-LEVEL', type=get_loglevel, help="Log application details to file for given LOG-LEVEL"),
|
|
+ "debug" : dict(action='store_true', dest='debug', help='Print DEBUG level logging details to console'),
|
|
+ "version": dict(action='version', version='0.18', help="show version"),
|
|
+ "threads": dict(dest='thread_list', default=[], metavar='THREAD-LIST', type=threadstring_to_list, help="THREAD-LIST affected by commands"),
|
|
+ "irqs": dict(dest='irq_list', default=[], metavar='IRQ-LIST', type=irqstring_to_list, help="IRQ-LIST affect by commands"),
|
|
+ "cpus": dict(dest='cpu_list', default=[], metavar='CPU-LIST', type=tuna.cpustring_to_list, help='CPU-LIST affected by commands'),
|
|
+ "sockets": dict(default=[], nargs='+', type=int, help="CPU-SOCKET-LIST affected by commands"),
|
|
+ "show_sockets": dict(action='store_true', help='Show network sockets in use by threads'),
|
|
+ "cgroups": dict(action='store_true', dest='cgroups', help='Display the processes with the type of cgroups they are in'),
|
|
+ "affect_children": dict(action='store_true', help="Operation will affect children threads"),
|
|
+ "nohz_full": dict(action='store_true', help="CPUs in nohz_full kernel command line will be affected by operations"),
|
|
+ "no_uthreads": dict(action='store_false', dest='uthreads', help="Operations will not affect user threads"),
|
|
+ "no_kthreads": dict(action='store_false', dest='kthreads', help="Operations will not affect kernel threads"),
|
|
+ "disable_perf": dict(action='store_true', help="Explicitly disable usage of perf in GUI for process view"),
|
|
+ "refresh": dict(default=2500, metavar='MSEC', type=int, help="Refresh the GUI every MSEC milliseconds"),
|
|
+ "priority": dict(default=(None, None), type=tuna.get_policy_and_rtprio, help="Set thread scheduler tunables: POLICY and RTPRIO"),
|
|
+ "background": dict(action='store_true', help="Run command as background task")
|
|
+ }
|
|
+
|
|
+ parser = HelpMessageParser(description="tuna - Application Tuning Program")
|
|
+
|
|
+ parser._positionals.title = "commands"
|
|
+ parser.add_argument('-v', '--version', **MODS['version'])
|
|
+ parser.add_argument('-L', '--logging', **MODS['logging'])
|
|
+ parser.add_argument('-D', '--debug', **MODS['debug'])
|
|
+
|
|
+ subparser = parser.add_subparsers(dest='command')
|
|
+
|
|
+ isolate = subparser.add_parser('isolate', description="Move all allowed threads and IRQs away from CPU-LIST",
|
|
+ help="Move all allowed threads and IRQs away from CPU-LIST")
|
|
+ include = subparser.add_parser('include', description="Allow all threads to run on CPU-LIST",
|
|
+ help="Allow all threads to run on CPU-LIST")
|
|
+ move = subparser.add_parser('move', description="Move selected entities to CPU-LIST",
|
|
+ help="Move selected entities to CPU-LIST")
|
|
+ spread = subparser.add_parser('spread', description="Move selected entities to CPU-LIST",
|
|
+ help="Spread selected entities over CPU-LIST")
|
|
+ priority = subparser.add_parser('priority', description="Set thread scheduler tunables: POLICY and RTPRIO",
|
|
+ help="Set thread scheduler tunables: POLICY and RTPRIO")
|
|
+ run = subparser.add_parser('run', description="Fork a new process and run the COMMAND",
|
|
+ help="Fork a new process and run the COMMAND")
|
|
+ save = subparser.add_parser('save', description="Save kthreads sched tunables to FILENAME",
|
|
+ help="Save kthreads sched tunables to FILENAME")
|
|
+ apply = subparser.add_parser('apply', description="Apply changes described in profile",
|
|
+ help="Apply changes described in profile")
|
|
+ show_threads = subparser.add_parser('show_threads', description='Show thread list', help='Show thread list')
|
|
+ show_irqs = subparser.add_parser('show_irqs', description='Show IRQ list', help='Show IRQ list')
|
|
+ show_configs = subparser.add_parser('show_configs', description='List preloaded profiles', help='List preloaded profiles')
|
|
+
|
|
+ what_is = subparser.add_parser('what_is', description='Provides help about selected entities', help='Provides help about selected entities')
|
|
+ gui = subparser.add_parser('gui', description="Start the GUI", help="Start the GUI")
|
|
+
|
|
+ isolate_group = isolate.add_mutually_exclusive_group(required=True)
|
|
+ isolate_group.add_argument('-c', '--cpus', **MODS['cpus'])
|
|
+ isolate_group.add_argument('-N', '--nohz_full', **MODS['nohz_full'])
|
|
+
|
|
+ include_group = include.add_mutually_exclusive_group(required=True)
|
|
+ include_group.add_argument('-c', '--cpus', **MODS['cpus'])
|
|
+ include_group.add_argument('-N', '--nohz_full', **MODS['nohz_full'])
|
|
+
|
|
+ move_group = move.add_mutually_exclusive_group(required=True)
|
|
+ move_group.add_argument('-c', '--cpus', **MODS['cpus'])
|
|
+ move_group.add_argument('-N', '--nohz_full', **MODS['nohz_full'])
|
|
+ move.add_argument('-t', '--threads', **MODS['threads'])
|
|
+ move.add_argument('-q', '--irqs', **MODS['irqs'])
|
|
+
|
|
+ spread_group = spread.add_mutually_exclusive_group(required=True)
|
|
+ spread_group.add_argument('-c', '--cpus', **MODS['cpus'])
|
|
+ spread_group.add_argument('-N', '--nohz_full', **MODS['nohz_full'])
|
|
+ spread.add_argument('-t', '--threads', **MODS['threads'])
|
|
+ spread.add_argument('-q', '--irqs', **MODS['irqs'])
|
|
+
|
|
+ priority.add_argument('priority', **POS['priority'])
|
|
+ priority.add_argument('-t', '--threads', **MODS['threads'], required=True)
|
|
+ priority.add_argument('-C', '--affect_children', **MODS['affect_children'])
|
|
+
|
|
+ run.add_argument('run_command', **POS['run_command'])
|
|
+ run.add_argument('-c', '--cpus', **MODS['cpus'])
|
|
+ run.add_argument('-p', '--priority', **MODS['priority'])
|
|
+ run.add_argument('-b', '--background', **MODS['background'])
|
|
+
|
|
+ save.add_argument('filename', **POS['filename'])
|
|
+ save.add_argument('-c', '--cpus', **MODS['cpus'])
|
|
+ save.add_argument('-t', '--threads', **MODS['threads'])
|
|
+
|
|
+ apply.add_argument('profilename', **POS['profilename'])
|
|
+
|
|
+ show_threads_group1 = show_threads.add_mutually_exclusive_group(required=False)
|
|
+ show_threads_group1.add_argument('-c', '--cpus', **MODS['cpus'])
|
|
+ show_threads_group1.add_argument('-N', '--nohz_full', **MODS['nohz_full'])
|
|
+ show_threads_group2 = show_threads.add_mutually_exclusive_group(required=False)
|
|
+ show_threads_group2.add_argument('-t', '--threads', **MODS['threads'])
|
|
+ show_threads_group2.add_argument('-q', '--irqs', **MODS['irqs'])
|
|
+ show_threads.add_argument('-U', '--no_uthreads', **MODS['no_uthreads'])
|
|
+ show_threads.add_argument('-K', '--no_kthreads', **MODS['no_kthreads'])
|
|
+ show_threads.add_argument('-C', '--affect_children', **MODS['affect_children'])
|
|
+
|
|
if have_inet_diag:
|
|
- print(fmt % ('-n, --show_sockets',
|
|
- _('Show network sockets in use by threads')))
|
|
- print(fmt % ('-p, --priority=[' +
|
|
- _('POLICY') + ':]' +
|
|
- _('RTPRIO'), _('Set thread scheduler tunables: %(policy)s and %(rtprio)s') %
|
|
- {"policy": _('POLICY'), "rtprio": _('RTPRIO')}))
|
|
- print(fmt % ('-P, --show_threads', _('Show thread list')))
|
|
- 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 % ('-R, --refresh=' + _('MSEC'), _('Refresh the GUI every MSEC milliseconds')))
|
|
- print(fmt % ('-s, --save=' + _('FILENAME'), _('Save kthreads sched tunables to %(filename)s') %
|
|
- {"filename": _('FILENAME')}))
|
|
- print(fmt % ('-S, --sockets=' +
|
|
- _('CPU-SOCKET-LIST'), _('%(cpusocketlist)s affected by commands') %
|
|
- {"cpusocketlist": _('CPU-SOCKET-LIST')}))
|
|
- print(fmt % ('-t, --threads=' +
|
|
- _('THREAD-LIST'), _('%(threadlist)s affected by commands') %
|
|
- {"threadlist": _('THREAD-LIST')}))
|
|
- 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')))
|
|
- print(fmt % ('-x, --spread', _('Spread selected entities over %(cpulist)s') %
|
|
- {"cpulist": _('CPU-LIST')}))
|
|
+ show_threads.add_argument('-n', '--show_sockets', **MODS['show_sockets'])
|
|
+ show_threads.add_argument('-G', '--cgroups', **MODS['cgroups'])
|
|
+
|
|
+ show_irqs.add_argument('-c', '--cpus', **MODS['cpus'])
|
|
+ show_irqs.add_argument('-q', '--irqs', **MODS['irqs'])
|
|
+
|
|
+ what_is.add_argument('thread_list', **POS['thread_list'])
|
|
+
|
|
+ gui.add_argument('-d', '--disable_perf', **MODS['disable_perf'])
|
|
+ gui.add_argument('-R', '--refresh', **MODS['refresh'])
|
|
+ gui.add_argument('-c', '--cpus', **MODS['cpus'])
|
|
+ gui.add_argument('-U', '--no_uthreads', **MODS['no_uthreads'])
|
|
+ gui.add_argument('-K', '--no_kthreads', **MODS['no_kthreads'])
|
|
+
|
|
+ return parser
|
|
|
|
|
|
def get_nr_cpus():
|
|
@@ -447,39 +516,34 @@ def do_list_op(op, current_list, op_list):
|
|
return list(set(current_list) - set(op_list))
|
|
return list(set(op_list))
|
|
|
|
-
|
|
-def thread_mapper(s):
|
|
+def threadstring_to_list(threadstr):
|
|
global ps
|
|
- try:
|
|
- return [int(s), ]
|
|
- except:
|
|
- pass
|
|
-
|
|
- ps = procfs.pidstats()
|
|
-
|
|
- try:
|
|
- return ps.find_by_regex(re.compile(fnmatch.translate(s)))
|
|
- except:
|
|
- return ps.find_by_name(s)
|
|
-
|
|
+ thread_list = []
|
|
+ thread_strings = list(set(threadstr.split(',')))
|
|
+ print(thread_strings)
|
|
+ for s in thread_strings:
|
|
+ if s.isdigit():
|
|
+ thread_list.append(int(s))
|
|
+ else:
|
|
+ ps = procfs.pidstats()
|
|
+ try:
|
|
+ thread_list += ps.find_by_regex(re.compile(fnmatch.translate(s)))
|
|
+ except:
|
|
+ thread_list += ps.find_by_name(s)
|
|
+ return thread_list
|
|
|
|
-def irq_mapper(s):
|
|
- global irqs
|
|
- try:
|
|
- return [int(s), ]
|
|
- except:
|
|
- pass
|
|
- if not irqs:
|
|
- irqs = procfs.interrupts()
|
|
+def irqstring_to_list(irqstr):
|
|
|
|
- irq_list_str = irqs.find_by_user_regex(re.compile(fnmatch.translate(s)))
|
|
irq_list = []
|
|
- for i in irq_list_str:
|
|
- try:
|
|
- irq_list.append(int(i))
|
|
- except:
|
|
- pass
|
|
-
|
|
+ irq_strings = list(set(irqstr.split(',')))
|
|
+ print(irq_strings)
|
|
+ for s in irq_strings:
|
|
+ if s.isdigit():
|
|
+ irq_list.append(int(s))
|
|
+ else:
|
|
+ # find_by_user_regex returns a list of strings corresponding to irq number
|
|
+ irq_list_str = procfs.interrupts().find_by_user_regex(re.compile(fnmatch.translate(s)))
|
|
+ irq_list += [int(i) for i in irq_list_str if i.isdigit()]
|
|
return irq_list
|
|
|
|
|
|
@@ -531,298 +595,123 @@ def list_config():
|
|
print(value)
|
|
sys.exit(1)
|
|
|
|
+def nohz_full_to_cpu():
|
|
+
|
|
+ try:
|
|
+ return tuna.nohz_full_list()
|
|
+ except:
|
|
+ print("tuna: --nohz_full " +
|
|
+ _(" needs nohz_full=cpulist on the kernel command line"))
|
|
+ sys.exit(2)
|
|
|
|
def main():
|
|
global ps
|
|
|
|
i18n_init()
|
|
- try:
|
|
- short = "a:c:dDCfgGhiIKlmNp:PQq:r:R:s:S:t:UvWxL:"
|
|
- long = ["cpus=", "affect_children", "filter", "gui", "help",
|
|
- "isolate", "include", "no_kthreads", "move", "nohz_full",
|
|
- "show_sockets", "priority=", "show_threads",
|
|
- "show_irqs", "irqs=",
|
|
- "save=", "sockets=", "threads=", "no_uthreads",
|
|
- "version", "what_is", "spread", "cgroup", "config_file_apply=",
|
|
- "config_file_list", "run=", "refresh=", "disable_perf", "logging=", "debug"]
|
|
- if have_inet_diag:
|
|
- short += "n"
|
|
- long.append("show_sockets")
|
|
- opts, args = getopt.getopt(sys.argv[1:], short, long)
|
|
- except getopt.GetoptError as err:
|
|
- usage()
|
|
- print(str(err))
|
|
- sys.exit(2)
|
|
+ parser = gen_parser()
|
|
+ # Set all necessary defaults for gui subparser if no arguments provided
|
|
+ args = parser.parse_args() if len(sys.argv) > 1 else parser.parse_args(['gui'])
|
|
+
|
|
+ if args.debug:
|
|
+ my_logger = setup_logging("my_logger")
|
|
+ my_logger.addHandler(add_handler("DEBUG", tofile=False))
|
|
+ my_logger.info("Debug option set")
|
|
+
|
|
+ if args.loglevel:
|
|
+ if not args.debug:
|
|
+ my_logger = setup_logging("my_logger")
|
|
+ try:
|
|
+ my_logger.addHandler(add_handler(args.loglevel, tofile=True))
|
|
+ my_logger.info("Logging option set at log level {}".format(args.loglevel))
|
|
|
|
- run_gui = not opts
|
|
- kthreads = True
|
|
- uthreads = True
|
|
- cgroups = False
|
|
- cpu_list = None
|
|
- debug = False
|
|
- irq_list = None
|
|
- irq_list_str = None
|
|
- log = False
|
|
- rtprio = None
|
|
- policy = None
|
|
- thread_list = []
|
|
- thread_list_str = None
|
|
- filter = False
|
|
- affect_children = False
|
|
- show_sockets = False
|
|
- p_waiting_action = False
|
|
- gui_refresh = 2500
|
|
- disable_perf = False
|
|
-
|
|
- for o, a in opts:
|
|
- if o in ("-h", "--help"):
|
|
- usage()
|
|
- return
|
|
- if o in ("-D", "--debug"):
|
|
- if debug:
|
|
- my_logger.warning("Debugging already set")
|
|
- continue
|
|
- debug = True
|
|
- if not log:
|
|
- my_logger = setup_logging("my_logger")
|
|
- my_logger.addHandler(add_handler("DEBUG", tofile=False))
|
|
- my_logger.info("Debug option set")
|
|
- if o in ("-L", "--logging"):
|
|
- if log:
|
|
- my_logger.warning("Logging already set")
|
|
- continue
|
|
- log = True
|
|
- loglevel = get_loglevel(a)
|
|
- if not debug:
|
|
- my_logger = setup_logging("my_logger")
|
|
- try:
|
|
- my_logger.addHandler(add_handler(loglevel, tofile=True))
|
|
- except ValueError as e:
|
|
- print(e, "tuna: --logging requires valid logging level\n")
|
|
- print("Valid log levels: NOTSET, DEBUG, INFO, WARNING, ERROR")
|
|
- print("Log levels may be specified numerically (0-4)")
|
|
- my_logger.info("Logging option set")
|
|
- if o in ("-a", "--config_file_apply"):
|
|
- apply_config(a)
|
|
- elif o in ("-l", "--config_file_list"):
|
|
- list_config()
|
|
- elif o in ("-c", "--cpus"):
|
|
- (op, a) = pick_op(a)
|
|
- try:
|
|
- op_list = tuna.cpustring_to_list(a)
|
|
- except ValueError:
|
|
- usage()
|
|
- return
|
|
- cpu_list = do_list_op(op, cpu_list, op_list)
|
|
- elif o in ("-N", "--nohz_full"):
|
|
- try:
|
|
- cpu_list = tuna.nohz_full_list()
|
|
- except:
|
|
- print("tuna: --nohz_full " +
|
|
- _(" needs nohz_full=cpulist on the kernel command line"))
|
|
- sys.exit(2)
|
|
- elif o in ("-C", "--affect_children"):
|
|
- affect_children = True
|
|
- elif o in ("-G", "--cgroup"):
|
|
- cgroups = True
|
|
- elif o in ("-t", "--threads"):
|
|
- # The -t - will reset thread list
|
|
- if a == '-':
|
|
- thread_list = []
|
|
- thread_list_str = ''
|
|
- else:
|
|
- (op, a) = pick_op(a)
|
|
- op_list = reduce(lambda i, j: i + j,
|
|
- list(map(thread_mapper, a.split(","))))
|
|
- op_list = list(set(op_list))
|
|
- thread_list = do_list_op(op, thread_list, op_list)
|
|
- # Check if a process name was specified and no
|
|
- # threads was found, which would result in an empty
|
|
- # thread list, i.e. we would print all the threads
|
|
- # in the system when we should print nothing.
|
|
- if not op_list and isinstance(a, type('')):
|
|
- thread_list_str = do_list_op(op, thread_list_str,
|
|
- a.split(","))
|
|
- if not op:
|
|
- irq_list = None
|
|
- elif o in ("-f", "--filter"):
|
|
- filter = True
|
|
- elif o in ("-g", "--gui"):
|
|
- run_gui = True
|
|
- elif o in ("-R", "--refresh"):
|
|
- run_gui = True
|
|
- (op, a) = pick_op(a)
|
|
- try:
|
|
- gui_refresh=int(a)
|
|
- except Exception as err:
|
|
- print("tuna: --refresh %s" % err)
|
|
- sys.exit(2)
|
|
- elif o in ("-d", "--disable_perf"):
|
|
- run_gui = True
|
|
- disable_perf = True
|
|
- elif o in ("-i", "--isolate"):
|
|
- if not cpu_list:
|
|
- print("tuna: --isolate " + _("requires a cpu list!"))
|
|
- sys.exit(2)
|
|
- tuna.isolate_cpus(cpu_list, get_nr_cpus())
|
|
- elif o in ("-I", "--include"):
|
|
- if not cpu_list:
|
|
- print("tuna: --include " + _("requires a cpu list!"))
|
|
- sys.exit(2)
|
|
- tuna.include_cpus(cpu_list, get_nr_cpus())
|
|
- elif o in ("-p", "--priority"):
|
|
- # Save policy and rtprio for future Actions (e.g. --run).
|
|
- try:
|
|
- (policy, rtprio) = tuna.get_policy_and_rtprio(a)
|
|
- except ValueError:
|
|
- print("tuna: " + _("\"%s\" is an unsupported priority value!") % a)
|
|
- sys.exit(2)
|
|
- if not thread_list:
|
|
- # For backward compatibility
|
|
- p_waiting_action = True
|
|
- else:
|
|
- try:
|
|
- tuna.threads_set_priority(thread_list, a, affect_children)
|
|
- except OSError as err:
|
|
- print("tuna: %s" % err)
|
|
- sys.exit(2)
|
|
- elif o in ("-P", "--show_threads"):
|
|
- # If the user specified process names that weren't
|
|
- # resolved to pids, don't show all threads.
|
|
- if not thread_list and not irq_list:
|
|
- if thread_list_str or irq_list_str:
|
|
- continue
|
|
- do_ps(thread_list, cpu_list, irq_list, uthreads,
|
|
- kthreads, affect_children, show_sockets, cgroups)
|
|
- elif o in ("-Q", "--show_irqs"):
|
|
- # If the user specified IRQ names that weren't
|
|
- # resolved to IRQs, don't show all IRQs.
|
|
- if not irq_list and irq_list_str:
|
|
- continue
|
|
- show_irqs(irq_list, cpu_list)
|
|
- elif o in ("-n", "--show_sockets"):
|
|
- show_sockets = True
|
|
- elif o in ("-m", "--move", "-x", "--spread"):
|
|
- spread = o in ("-x", "--spread")
|
|
- if not cpu_list:
|
|
- print("tuna: %s " % ("--spread" if spread else "--move") + _("requires a cpu list!"))
|
|
- sys.exit(2)
|
|
- if not (thread_list or irq_list):
|
|
- print("tuna: %s " % ("--spread" if spread else "--move") + _("requires a list of threads/irqs!"))
|
|
- sys.exit(2)
|
|
-
|
|
- if thread_list:
|
|
- tuna.move_threads_to_cpu(cpu_list, thread_list, spread=spread)
|
|
-
|
|
- if irq_list:
|
|
- tuna.move_irqs_to_cpu(cpu_list, irq_list, spread=spread)
|
|
- elif o in ("-s", "--save"):
|
|
- save(cpu_list, thread_list, a)
|
|
- elif o in ("-S", "--sockets"):
|
|
- (op, a) = pick_op(a)
|
|
- sockets = list(a.split(','))
|
|
-
|
|
- if not cpu_list:
|
|
- cpu_list = []
|
|
-
|
|
- cpu_info = sysfs.cpus()
|
|
- op_list = []
|
|
- for socket in sockets:
|
|
- if socket not in cpu_info.sockets:
|
|
- print("tuna: %s" %
|
|
- (_("invalid socket %(socket)s sockets available: %(available)s") %
|
|
- {"socket": socket,
|
|
- "available": ",".join(list(cpu_info.sockets.keys()))}))
|
|
- sys.exit(2)
|
|
- op_list += [int(cpu.name[3:])
|
|
- for cpu in cpu_info.sockets[socket]]
|
|
- cpu_list = do_list_op(op, cpu_list, op_list)
|
|
- elif o in ("-K", "--no_kthreads"):
|
|
- kthreads = False
|
|
- elif o in ("-q", "--irqs"):
|
|
- (op, a) = pick_op(a)
|
|
- op_list = reduce(lambda i, j: i + j,
|
|
- list(map(irq_mapper, list(set(a.split(","))))))
|
|
- irq_list = do_list_op(op, irq_list, op_list)
|
|
- # See comment above about thread_list_str
|
|
- if not op_list and isinstance(a, type('')):
|
|
- irq_list_str = do_list_op(op, irq_list_str, a.split(","))
|
|
- if not op:
|
|
- thread_list = []
|
|
- if not ps:
|
|
- ps = procfs.pidstats()
|
|
- if tuna.has_threaded_irqs(ps):
|
|
- for irq in irq_list:
|
|
- irq_re = tuna.threaded_irq_re(irq)
|
|
- irq_threads = ps.find_by_regex(irq_re)
|
|
- if irq_threads:
|
|
- # Change the affinity of the thread too
|
|
- # as we can't rely on changing the irq
|
|
- # affinity changing the affinity of the
|
|
- # thread or vice versa. We need to change
|
|
- # both.
|
|
- thread_list += irq_threads
|
|
-
|
|
- elif o in ("-U", "--no_uthreads"):
|
|
- uthreads = False
|
|
- elif o in ("-v", "--version"):
|
|
- print(version)
|
|
- elif o in ("-W", "--what_is"):
|
|
- if not thread_list:
|
|
- print("tuna: --what_is " + _("requires a thread list!"))
|
|
- sys.exit(2)
|
|
- for tid in thread_list:
|
|
- thread_help(tid)
|
|
- elif o in ("-r", "--run"):
|
|
- # If -p is set, it will be consumed. So, no backward compatible
|
|
- # error handling action must be taken.
|
|
- p_waiting_action = False
|
|
-
|
|
- # pick_op() before run the command: to remove the prefix
|
|
- # + or - from command line.
|
|
- (op, a) = pick_op(a)
|
|
-
|
|
- # In order to include the new process, it must run
|
|
- # the command first, and then get the list of pids,
|
|
- tuna.run_command(a, policy, rtprio, cpu_list)
|
|
-
|
|
- op_list = reduce(lambda i, j: i + j,
|
|
- list(map(thread_mapper, a.split(","))))
|
|
- op_list = list(set(op_list))
|
|
- thread_list = do_list_op(op, thread_list, op_list)
|
|
-
|
|
- # Check if a process name was specified and no
|
|
- # threads was found, which would result in an empty
|
|
- # thread list, i.e. we would print all the threads
|
|
- # in the system when we should print nothing.
|
|
- if not op_list and isinstance(a, type('')):
|
|
- thread_list_str = do_list_op(op, thread_list_str, a.split(","))
|
|
- if not op:
|
|
- irq_list = None
|
|
-
|
|
- # For backward compatibility: when -p used to be only an Action, it
|
|
- # used to exit(2) if no action was taken (i.e. if no threads_list
|
|
- # was set).
|
|
- if p_waiting_action:
|
|
- print(("tuna: -p ") + _("requires a thread list!"))
|
|
- sys.exit(2)
|
|
+ except ValueError as e:
|
|
+ print(e, "tuna: --logging requires valid logging level\n")
|
|
+ print("Valid log levels: NOTSET, DEBUG, INFO, WARNING, ERROR")
|
|
+ print("Log levels may be specified numerically (0-4)\n")
|
|
+
|
|
+ if 'irq_list' in vars(args):
|
|
+ ps = procfs.pidstats()
|
|
+ if tuna.has_threaded_irqs(ps):
|
|
+ for irq in args.irq_list:
|
|
+ irq_re = tuna.threaded_irq_re(irq)
|
|
+ irq_threads = ps.find_by_regex(irq_re)
|
|
+ if irq_threads:
|
|
+ # Change the affinity of the thread too
|
|
+ # as we can't rely on changing the irq
|
|
+ # affinity changing the affinity of the
|
|
+ # thread or vice versa. We need to change
|
|
+ # both.
|
|
+ if 'thread_list' in vars(args):
|
|
+ args.thread_list += irq_threads
|
|
+
|
|
+ if 'nohz_full' in vars(args) and args.nohz_full:
|
|
+ args.cpu_list = nohz_full_to_cpu()
|
|
+
|
|
+ if args.command in ['apply', 'a']:
|
|
+ apply_config(args.profilename)
|
|
+
|
|
+ elif args.command in ['include', 'I']:
|
|
+ tuna.include_cpus(args.cpu_list, get_nr_cpus())
|
|
+
|
|
+ elif args.command in ['isolate', 'i']:
|
|
+ tuna.isolate_cpus(args.cpu_list, get_nr_cpus())
|
|
+
|
|
+ elif args.command in ['run', 'r']:
|
|
+
|
|
+ tuna.run_command(args.run_command, args.priority[0], args.priority[1], args.cpu_list, args.background)
|
|
+
|
|
+ elif args.command in ['priority', 'p']:
|
|
+
|
|
+ try:
|
|
+ tuna.threads_set_priority(args.thread_list, args.priority, args.affect_children)
|
|
+ except OSError as err:
|
|
+ print("tuna: %s" % err)
|
|
+ sys.exit(2)
|
|
+
|
|
+ elif args.command in ['show_configs']:
|
|
+ list_config()
|
|
+
|
|
+ elif args.command in ['show_threads']:
|
|
+ do_ps(args.thread_list, args.cpu_list, args.irq_list, args.uthreads,
|
|
+ args.kthreads, args.affect_children, args.show_sockets if "show_sockets" in args else None, args.cgroups)
|
|
+
|
|
+ elif args.command in ['show_irqs']:
|
|
+ show_irqs(args.irq_list, args.cpu_list)
|
|
+
|
|
+ elif args.command in ['move', 'm', 'spread', 'x']:
|
|
+ spread = args.command in ['spread', 'x']
|
|
+
|
|
+ if not (args.thread_list or args.irq_list):
|
|
+ parser.error("tuna: %s " % (args.command) + _("requires a thread/irq list!\n"))
|
|
+
|
|
+ if args.thread_list:
|
|
+ tuna.move_threads_to_cpu(args.cpu_list, args.thread_list, spread=spread)
|
|
+
|
|
+ if args.irq_list:
|
|
+ tuna.move_irqs_to_cpu(args.cpu_list, args.irq_list, spread=spread)
|
|
+
|
|
+ elif args.command in ['s', 'save']:
|
|
+ save(args.cpu_list, args.thread_list, args.filename)
|
|
+
|
|
+ elif args.command in ['W', 'what_is']:
|
|
+ for tid in args.thread_list:
|
|
+ thread_help(tid)
|
|
|
|
- if run_gui:
|
|
+ elif args.command in ['g', 'gui']:
|
|
try:
|
|
from tuna import tuna_gui
|
|
except ImportError:
|
|
# gui packages not installed
|
|
print(_('tuna: packages needed for the GUI missing.'))
|
|
print(_(' Make sure xauth, pygtk2-libglade are installed.'))
|
|
- usage()
|
|
+ parser.print_help()
|
|
return
|
|
except RuntimeError:
|
|
print("tuna: machine needs to be authorized via xhost or ssh -X?")
|
|
return
|
|
|
|
try:
|
|
- cpus_filtered = filter if cpu_list else []
|
|
- app = tuna_gui.main_gui(kthreads, uthreads, cpus_filtered, gui_refresh, disable_perf)
|
|
+ app = tuna_gui.main_gui(args.kthreads, args.uthreads, args.cpu_list, args.refresh, args.disable_perf)
|
|
app.run()
|
|
except KeyboardInterrupt:
|
|
pass
|
|
diff --git a/tuna/tuna.py b/tuna/tuna.py
|
|
index 31707c9cb69c..8650f11c81c3 100755
|
|
--- a/tuna/tuna.py
|
|
+++ b/tuna/tuna.py
|
|
@@ -618,7 +618,7 @@ def get_kthread_sched_tunings(proc=None):
|
|
|
|
return kthreads
|
|
|
|
-def run_command(cmd, policy, rtprio, cpu_list):
|
|
+def run_command(cmd, policy, rtprio, cpu_list, background):
|
|
newpid = os.fork()
|
|
if newpid == 0:
|
|
cmd_list = shlex.split(cmd)
|
|
@@ -642,7 +642,8 @@ def run_command(cmd, policy, rtprio, cpu_list):
|
|
print("tuna: %s" % err)
|
|
sys.exit(2)
|
|
else:
|
|
- os.waitpid(newpid, 0)
|
|
+ if not background:
|
|
+ os.waitpid(newpid, 0)
|
|
|
|
def generate_rtgroups(filename, kthreads, nr_cpus):
|
|
f = open(filename, "w")
|
|
--
|
|
2.31.1
|
|
|