diff --git a/SOURCES/tuna-Adapt-show_threads-cgroup-output-to-terminal-si.patch b/SOURCES/tuna-Adapt-show_threads-cgroup-output-to-terminal-si.patch new file mode 100644 index 0000000..530c1c4 --- /dev/null +++ b/SOURCES/tuna-Adapt-show_threads-cgroup-output-to-terminal-si.patch @@ -0,0 +1,148 @@ +From b04ce6fa8b183f6a930fbff240eff44efe801f91 Mon Sep 17 00:00:00 2001 +From: Leah Leshchinsky +Date: Mon, 14 Nov 2022 14:55:08 -0500 +Subject: [PATCH] tuna: Adapt show_threads cgroup output to terminal size + +Passing the --cgroup flag to the show_threads command currently displays +long cgroup strings on the thread output and decreases readability. + +Adapt the show_threads output to account for output string and terminal +size, and format output accordingly to improve readability. Add +--spaced flag to show_threads to print cgroups with spacing in +between thread outputs. + +Signed-off-by: Leah Leshchinsky + +--- +target branch: main + +Signed-off-by: John Kacur + +diff --git a/docs/tuna.8 b/docs/tuna.8 +index f50a8c2a0a16..242389455f83 100644 +--- a/docs/tuna.8 ++++ b/docs/tuna.8 +@@ -188,6 +188,7 @@ optional arguments: + Operation will affect children threads + -G, --cgroups Display the processes with the type of cgroups they + are in ++ -z, --spaced Display spaced view for cgroups + + .TP + \fBtuna show_irqs\fR +diff --git a/tuna-cmd.py b/tuna-cmd.py +index 8be35f7fb4c4..630c8bc60deb 100755 +--- a/tuna-cmd.py ++++ b/tuna-cmd.py +@@ -114,6 +114,7 @@ def gen_parser(): + "sockets": dict(dest='cpu_list', default=[], metavar='CPU-SOCKET-LIST', type=socketstring_to_list, 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'), ++ "spaced": dict(action='store_false', dest='compact', help='Display spaced view for cgroups'), + "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"), +@@ -215,6 +216,7 @@ def gen_parser(): + if have_inet_diag: + show_threads.add_argument('-n', '--show_sockets', **MODS['show_sockets']) + show_threads.add_argument('-G', '--cgroups', **MODS['cgroups']) ++ show_threads.add_argument('-z', '--spaced', **MODS['spaced']) + + + show_irqs_group = show_irqs.add_mutually_exclusive_group(required=False) +@@ -335,7 +337,7 @@ def format_affinity(affinity): + return ",".join(str(hex(a)) for a in procfs.hexbitmask(affinity, get_nr_cpus())) + + def ps_show_thread(pid, affect_children, ps, has_ctxt_switch_info, sock_inodes, +- sock_inode_re, cgroups): ++ sock_inode_re, cgroups, columns=None, compact=True): + global irqs + try: + affinity = format_affinity(os.sched_getaffinity(pid)) +@@ -372,10 +374,20 @@ def ps_show_thread(pid, affect_children, ps, has_ctxt_switch_info, sock_inodes, + nonvoluntary_ctxt_switches) + + # Indent affected children +- print(" %-5d " % pid if affect_children else " %-5d" % pid, end=' ') +- print("%6s %5d %8s%s %15s %s" % (sched, rtprio, affinity, +- ctxt_switch_info, cmd, users), end=' ') +- print(" %9s" % cgout if cgroups else "") ++ s1 = " %-5d " % pid if affect_children else " %-5d" % pid ++ print(s1, end=' ') ++ s2 = "%6s %5d %8s%s %15s %s" % (sched, rtprio, affinity, ++ ctxt_switch_info, cmd, users) ++ print(s2, end=' ') ++ ++ if cgroups: ++ length = int(columns) - len(s1 + " ") - len(s2 + " ") ++ if len(" %9s" % cgout) <= length: ++ print("%s" % cgout) ++ else: ++ print("\n %s" % cgout + ("" if compact else "\n")) ++ else: ++ print() + + if sock_inodes: + ps_show_sockets(pid, ps, sock_inodes, sock_inode_re, +@@ -384,12 +396,12 @@ def ps_show_thread(pid, affect_children, ps, has_ctxt_switch_info, sock_inodes, + for tid in list(ps[pid]["threads"].keys()): + ps_show_thread(tid, False, ps[pid]["threads"], + has_ctxt_switch_info, +- sock_inodes, sock_inode_re, cgroups) ++ sock_inodes, sock_inode_re, cgroups, columns, compact) + + + def ps_show(ps, affect_children, thread_list, cpu_list, + irq_list_numbers, show_uthreads, show_kthreads, +- has_ctxt_switch_info, sock_inodes, sock_inode_re, cgroups): ++ has_ctxt_switch_info, sock_inodes, sock_inode_re, cgroups, compact): + + ps_list = [] + for pid in list(ps.keys()): +@@ -426,9 +438,15 @@ def ps_show(ps, affect_children, thread_list, cpu_list, + + ps_list.sort() + ++ ++ # Width of terminal in columns ++ columns = None ++ if cgroups: ++ _, columns = os.popen('stty size', 'r').read().split() ++ + for pid in ps_list: + ps_show_thread(pid, affect_children, ps, has_ctxt_switch_info, +- sock_inodes, sock_inode_re, cgroups) ++ sock_inodes, sock_inode_re, cgroups, columns, compact) + + + def load_socktype(socktype, inodes): +@@ -449,7 +467,7 @@ def load_sockets(): + + + def do_ps(thread_list, cpu_list, irq_list, show_uthreads, show_kthreads, +- affect_children, show_sockets, cgroups): ++ affect_children, show_sockets, cgroups, compact): + ps = procfs.pidstats() + if affect_children: + ps.reload_threads() +@@ -466,7 +484,7 @@ def do_ps(thread_list, cpu_list, irq_list, show_uthreads, show_kthreads, + ps_show_header(has_ctxt_switch_info, cgroups) + ps_show(ps, affect_children, thread_list, + cpu_list, irq_list, show_uthreads, show_kthreads, +- has_ctxt_switch_info, sock_inodes, sock_inode_re, cgroups) ++ has_ctxt_switch_info, sock_inodes, sock_inode_re, cgroups, compact) + except IOError: + # 'tuna -P | head' for instance + pass +@@ -698,7 +716,7 @@ def main(): + + 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) ++ args.kthreads, args.affect_children, args.show_sockets if "show_sockets" in args else None, args.cgroups, args.compact) + + elif args.command in ['show_irqs']: + show_irqs(args.irq_list, args.cpu_list) +-- +2.31.1 + diff --git a/SOURCES/tuna-Add-sockets-command-line-option.patch b/SOURCES/tuna-Add-sockets-command-line-option.patch new file mode 100644 index 0000000..d6f829b --- /dev/null +++ b/SOURCES/tuna-Add-sockets-command-line-option.patch @@ -0,0 +1,137 @@ +From 87f6d9e29bab615b03b26210e3ead493fd08fe1f Mon Sep 17 00:00:00 2001 +From: Leah Leshchinsky +Date: Thu, 8 Sep 2022 14:49:35 -0400 +Subject: [PATCH 3/6] tuna: Add --sockets command line option + +The getopt version of tuna implements the --sockets argument which is used +to specify a cpulist from the cpu sockets on a system. The --sockets +and --cpus arguments in the getopt version override each other, such +that 'tuna -S 0 -c 1,2' will cause a cpu_list of [1, 2]. + +In the argparse cli, add support for a --sockets argument used to specify a +cpulist and is mutually exclusive with the --cpus and --nohz_full arguments. + +Signed-off-by: Leah Leshchinsky +Signed-off-by: John Kacur + +diff --git a/tuna-cmd.py b/tuna-cmd.py +index 554912057f03..9a3d3f32398b 100755 +--- a/tuna-cmd.py ++++ b/tuna-cmd.py +@@ -112,7 +112,7 @@ def gen_parser(): + "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"), ++ "sockets": dict(dest='cpu_list', default=[], metavar='CPU-SOCKET-LIST', type=socketstring_to_list, 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"), +@@ -159,20 +159,24 @@ def gen_parser(): + + isolate_group = isolate.add_mutually_exclusive_group(required=True) + isolate_group.add_argument('-c', '--cpus', **MODS['cpus']) ++ isolate_group.add_argument('-S', '--sockets', **MODS['sockets']) + 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('-S', '--sockets', **MODS['sockets']) + 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('-S', '--sockets', **MODS['sockets']) + 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('-S', '--sockets', **MODS['sockets']) + spread_group.add_argument('-N', '--nohz_full', **MODS['nohz_full']) + spread.add_argument('-t', '--threads', **MODS['threads']) + spread.add_argument('-q', '--irqs', **MODS['irqs']) +@@ -182,12 +186,18 @@ def gen_parser(): + 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_group = run.add_mutually_exclusive_group(required=False) ++ run_group.add_argument('-c', '--cpus', **MODS['cpus']) ++ run_group.add_argument('-S', '--sockets', **MODS['sockets']) ++ run_group.add_argument('-N', '--nohz_full', **MODS['nohz_full']) + 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_group = save.add_mutually_exclusive_group(required=False) ++ save_group.add_argument('-c', '--cpus', **MODS['cpus']) ++ save_group.add_argument('-S', '--sockets', **MODS['sockets']) ++ save_group.add_argument('-N', '--nohz_full', **MODS['nohz_full']) + save.add_argument('-t', '--threads', **MODS['threads']) + + apply.add_argument('profilename', **POS['profilename']) +@@ -195,6 +205,7 @@ def gen_parser(): + 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_group1.add_argument('-S', '--sockets', **MODS['sockets']) + 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']) +@@ -206,14 +217,21 @@ def gen_parser(): + 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_group = show_irqs.add_mutually_exclusive_group(required=False) ++ show_irqs_group.add_argument('-c', '--cpus', **MODS['cpus']) ++ show_irqs_group.add_argument('-N', '--nohz_full', **MODS['nohz_full']) ++ show_irqs_group.add_argument('-S', '--sockets', **MODS['sockets']) + 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_group = gui.add_mutually_exclusive_group(required=False) ++ gui_group.add_argument('-c', '--cpus', **MODS['cpus']) ++ gui_group.add_argument('-N', '--nohz_full', **MODS['nohz_full']) ++ gui_group.add_argument('-S', '--sockets', **MODS['sockets']) + gui.add_argument('-U', '--no_uthreads', **MODS['no_uthreads']) + gui.add_argument('-K', '--no_kthreads', **MODS['no_kthreads']) + +@@ -536,7 +554,6 @@ def irqstring_to_list(irqstr): + + irq_list = [] + irq_strings = list(set(irqstr.split(','))) +- print(irq_strings) + for s in irq_strings: + if s.isdigit(): + irq_list.append(int(s)) +@@ -546,6 +563,18 @@ def irqstring_to_list(irqstr): + irq_list += [int(i) for i in irq_list_str if i.isdigit()] + return irq_list + ++def socketstring_to_list(socketstr): ++ cpu_list = [] ++ socket_strings = list(set(socketstr.split(','))) ++ cpu_info = sysfs.cpus() ++ ++ for s in socket_strings: ++ if s not in cpu_info.sockets: ++ print("tuna: invalid socket %(socket)s sockets available: %(available)s" % ++ {"socket": s,"available": ",".join(list(cpu_info.sockets.keys()))}) ++ sys.exit(2) ++ cpu_list += [int(cpu.name[3:]) for cpu in cpu_info.sockets[s]] ++ return cpu_list + + def pick_op(argument): + if argument == "": +-- +2.31.1 + diff --git a/SOURCES/tuna-Fix-matching-irqs-in-ps_show_thread.patch b/SOURCES/tuna-Fix-matching-irqs-in-ps_show_thread.patch new file mode 100644 index 0000000..b218c88 --- /dev/null +++ b/SOURCES/tuna-Fix-matching-irqs-in-ps_show_thread.patch @@ -0,0 +1,49 @@ +From 3f1fbb092f5ef07d04fef7ddec9e538f36d84450 Mon Sep 17 00:00:00 2001 +From: John Kacur +Date: Fri, 2 Sep 2022 11:55:07 -0400 +Subject: [PATCH 5/6] tuna: Fix matching irqs in ps_show_thread + +To new format to match irqs is "irqs/" +We already test this when we call is_irq_thread(cmd): + +With this fix if you do + +tuna show_threads + +You will get nic information that was previously missed such as + + 986 FIFO 50 9 69286 2 irq/164-iwlwifi:default_que +ue iwlwifi:default_queue + +Signed-off-by: John Kacur + +diff --git a/tuna-cmd.py b/tuna-cmd.py +index b13b25b8a801..80e27523acc6 100755 +--- a/tuna-cmd.py ++++ b/tuna-cmd.py +@@ -351,17 +351,12 @@ def ps_show_thread(pid, affect_children, ps, has_ctxt_switch_info, sock_inodes, + try: + if not irqs: + irqs = procfs.interrupts() +- if cmd[:4] == "IRQ-": +- users = irqs[tuna.irq_thread_number(cmd)]["users"] +- for u in users: +- if u in get_nics(): +- users[users.index(u)] = "%s(%s)" % ( +- u, ethtool.get_module(u)) +- users = ",".join(users) +- else: +- u = cmd[cmd.find('-') + 1:] ++ users = irqs[tuna.irq_thread_number(cmd)]["users"] ++ for u in users: + if u in get_nics(): +- users = ethtool.get_module(u) ++ users[users.index(u)] = "%s(%s)" % ( ++ u, ethtool.get_module(u)) ++ users = ",".join(users) + except: + users = "Not found in /proc/interrupts!" + +-- +2.31.1 + diff --git a/SOURCES/tuna-Fix-show_threads-cgroups-run-without-a-term.patch b/SOURCES/tuna-Fix-show_threads-cgroups-run-without-a-term.patch new file mode 100644 index 0000000..e8afb68 --- /dev/null +++ b/SOURCES/tuna-Fix-show_threads-cgroups-run-without-a-term.patch @@ -0,0 +1,42 @@ +From 4ccef8c2996e59e7031e77d7f8e2b42b73036210 Mon Sep 17 00:00:00 2001 +From: Leah Leshchinsky +Date: Wed, 23 Nov 2022 14:14:36 -0500 +Subject: [PATCH] tuna: Fix show_threads --cgroups run without a term + +When tuna show_threads --cgroups is run without a term, +provide a default column size of 80 to fix a traceback +that occurred when querying the terminal size. + +Signed-off-by: Leah Leshchinsky +- Edited the commit title +- Edited the description +Signed-off-by: John Kacur + +diff --git a/tuna-cmd.py b/tuna-cmd.py +index 630c8bc..4e809dd 100755 +--- a/tuna-cmd.py ++++ b/tuna-cmd.py +@@ -31,6 +31,7 @@ import procfs + from tuna import tuna, sysfs + import logging + import time ++import shutil + + def get_loglevel(level): + if level.isdigit() and int(level) in range(0,5): +@@ -440,9 +441,10 @@ def ps_show(ps, affect_children, thread_list, cpu_list, + + + # Width of terminal in columns +- columns = None ++ columns = 80 + if cgroups: +- _, columns = os.popen('stty size', 'r').read().split() ++ if os.isatty(sys.stdout.fileno()): ++ columns = shutil.get_terminal_size().columns + + for pid in ps_list: + ps_show_thread(pid, affect_children, ps, has_ctxt_switch_info, +-- +2.38.1 + diff --git a/SOURCES/tuna-Move-get_policy_and_rtprio-call-to-parser-level.patch b/SOURCES/tuna-Move-get_policy_and_rtprio-call-to-parser-level.patch new file mode 100644 index 0000000..45c4fb6 --- /dev/null +++ b/SOURCES/tuna-Move-get_policy_and_rtprio-call-to-parser-level.patch @@ -0,0 +1,48 @@ +From 9dd8c3e889fe632405561cc8476ed42659a99e2e Mon Sep 17 00:00:00 2001 +From: Leah Leshchinsky +Date: Thu, 4 Aug 2022 09:39:11 -0400 +Subject: [PATCH 2/6] tuna: Move get_policy_and_rtprio call to parser level + +Due to the implementation of the parser for the priority action, +the valid policy and rtprio input can be checked at the parser level. + +Call get_policy_and_rtprio on `priority` and `run --priority` commands +at argparse level. + +Signed-off-by: Leah Leshchinsky +Signed-off-by: John Kacur + +diff --git a/tuna-cmd.py b/tuna-cmd.py +index f49cce4d84d4..554912057f03 100755 +--- a/tuna-cmd.py ++++ b/tuna-cmd.py +@@ -102,7 +102,7 @@ def gen_parser(): + "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"), ++ "priority": dict(type=tuna.get_policy_and_rtprio, help="policy/priority help"), + } + + MODS = { +diff --git a/tuna/tuna.py b/tuna/tuna.py +index 8650f11c81c3..30a5a570c9d4 100755 +--- a/tuna/tuna.py ++++ b/tuna/tuna.py +@@ -558,11 +558,8 @@ def thread_set_priority(tid, policy, rtprio): + os.sched_setscheduler(tid, policy, param) + + def threads_set_priority(tids, parm, affect_children=False): +- try: +- (policy, rtprio) = get_policy_and_rtprio(parm) +- except ValueError: +- print("tuna: " + _("\"%s\" is an unsupported priority value!") % parm[0]) +- return ++ ++ (policy, rtprio) = parm + + for tid in tids: + try: +-- +2.31.1 + diff --git a/SOURCES/tuna-Remove-threads-print-statement.patch b/SOURCES/tuna-Remove-threads-print-statement.patch new file mode 100644 index 0000000..297038e --- /dev/null +++ b/SOURCES/tuna-Remove-threads-print-statement.patch @@ -0,0 +1,24 @@ +From b82d9037fe7f51e49a9b3c84b1ccb71fda1e1f61 Mon Sep 17 00:00:00 2001 +From: Leah Leshchinsky +Date: Tue, 25 Oct 2022 16:19:25 -0400 +Subject: [PATCH 6/6] tuna: Remove threads print statement + +Remove unnecessary print statement from threadstring_to_list function + +Signed-off-by: Leah Leshchinsky + +diff --git a/tuna-cmd.py b/tuna-cmd.py +index 80e27523acc6..c5bc65059da7 100755 +--- a/tuna-cmd.py ++++ b/tuna-cmd.py +@@ -533,7 +533,6 @@ def threadstring_to_list(threadstr): + global ps + thread_list = [] + thread_strings = list(set(threadstr.split(','))) +- print(thread_strings) + for s in thread_strings: + if s.isdigit(): + thread_list.append(int(s)) +-- +2.31.1 + diff --git a/SOURCES/tuna-Replace-python_ethtool-with-builtin-funtionalit.patch b/SOURCES/tuna-Replace-python_ethtool-with-builtin-funtionalit.patch new file mode 100644 index 0000000..b8408f6 --- /dev/null +++ b/SOURCES/tuna-Replace-python_ethtool-with-builtin-funtionalit.patch @@ -0,0 +1,97 @@ +From f2a28b05264fa9557192b73a1b888756748930ac Mon Sep 17 00:00:00 2001 +From: John Kacur +Date: Tue, 27 Sep 2022 12:59:54 -0400 +Subject: [PATCH 4/6] tuna: Replace python_ethtool with builtin funtionality + +This patch replaces the dependency on python_ethtool with some +simplified functions to achieve the same result. + +Reviewed-by: Federico Pellegrin +- return 'tun' only if tun_flags exists +Signed-off-by: John Kacur + +diff --git a/tuna-cmd.py b/tuna-cmd.py +index 9a3d3f32398b..b13b25b8a801 100755 +--- a/tuna-cmd.py ++++ b/tuna-cmd.py +@@ -26,7 +26,7 @@ import fnmatch + import gettext + import locale + from functools import reduce +-import ethtool ++import tuna.new_eth as ethtool + import tuna.tuna_sched as tuna_sched + import procfs + from tuna import tuna, sysfs +diff --git a/tuna/gui/irqview.py b/tuna/gui/irqview.py +index 35fc3fd0b0ca..5143d6dc0df5 100755 +--- a/tuna/gui/irqview.py ++++ b/tuna/gui/irqview.py +@@ -7,7 +7,7 @@ from gi.repository import Gtk + from gi.repository import GObject + import os + from functools import reduce +-import ethtool ++import tuna.new_eth as ethtool + import tuna.tuna_sched as tuna_sched + + import gi +diff --git a/tuna/new_eth.py b/tuna/new_eth.py +new file mode 100755 +index 000000000000..98f9179d5695 +--- /dev/null ++++ b/tuna/new_eth.py +@@ -0,0 +1,37 @@ ++# Copyright (C) 2022 John Kacur ++""" A few functions similar to ethtool """ ++import os ++import socket ++ ++def get_active_devices(): ++ """ return a list of network devices """ ++ ret = [] ++ ++ for device in socket.if_nameindex(): ++ ret.append(device[1]) ++ ++ return ret ++ ++def get_module(intf): ++ """ return the kernel module for the given network interface """ ++ if intf == 'lo': ++ return "" ++ myp = f'/sys/class/net/{intf}/device/driver' ++ if os.path.exists(myp): ++ return os.path.basename(os.readlink(myp)) ++ if os.path.exists(f'/sys/class/net/{intf}/bridge'): ++ return 'bridge' ++ if os.path.exists(f'/sys/class/net/{intf}/tun_flags'): ++ return 'tun' ++ return "" ++ ++if __name__ == "__main__": ++ nics = get_active_devices() ++ print(f'nics = {nics}') ++ ++ for intf in nics: ++ driver = get_module(intf) ++ if driver: ++ print(f'{intf}, {driver}') ++ else: ++ print(f'{intf}') +diff --git a/tuna/tuna.py b/tuna/tuna.py +index 30a5a570c9d4..43adb84079e4 100755 +--- a/tuna/tuna.py ++++ b/tuna/tuna.py +@@ -9,7 +9,7 @@ import sys + import shlex + import fnmatch + import platform +-import ethtool ++import tuna.new_eth as ethtool + import procfs + from procfs import utilist + from tuna import help +-- +2.31.1 + diff --git a/SOURCES/tuna-Update-command-line-interface.patch b/SOURCES/tuna-Update-command-line-interface.patch new file mode 100644 index 0000000..d86331e --- /dev/null +++ b/SOURCES/tuna-Update-command-line-interface.patch @@ -0,0 +1,733 @@ +From eba1333c50f8a5eebb12b523c30faffac33681b3 Mon Sep 17 00:00:00 2001 +From: Leah Leshchinsky +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 +Signed-off-by: John Kacur + +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 + diff --git a/SOURCES/tuna-Update-manpages-for-argparse-CLI-changes.patch b/SOURCES/tuna-Update-manpages-for-argparse-CLI-changes.patch new file mode 100644 index 0000000..88275aa --- /dev/null +++ b/SOURCES/tuna-Update-manpages-for-argparse-CLI-changes.patch @@ -0,0 +1,372 @@ +From 0681906e75e1c8166126bbfc2f3055e7507bfcb5 Mon Sep 17 00:00:00 2001 +From: Leah Leshchinsky +Date: Mon, 31 Oct 2022 13:04:28 -0400 +Subject: [PATCH 2/2] tuna: Update manpages for argparse CLI changes + +Due to the introduction of a new commandline interface, +update the tuna manpages. + +Update with new command line options. + +Signed-off-by: Leah Leshchinsky +- Slightly edited the description +- Changed "seperated" to "separated" +- Changed the "explains" to "describes" (not part of Leah's patch) +Signed-off-by: John Kacur + +diff --git a/docs/tuna.8 b/docs/tuna.8 +index 3a065562b00e..f50a8c2a0a16 100644 +--- a/docs/tuna.8 ++++ b/docs/tuna.8 +@@ -9,100 +9,261 @@ This manual page explains the \fBtuna\fR program. The program can be used to cha + .PP + \fBtuna\fP can change scheduling policy, scheduler priority and processor affinity for processes and process threads. \fBtuna\fR can also change the processor affinity for interrupts. + When \fBtuna\fR is invoked without any options it starts up in its graphical interface mode. This manual page explains only the command\-line options for \fBtuna\fR +-.SH "OPTIONS" +-\fBtuna\fR has both \fIaction\fR options and \fImodifier\fR options. Modifier options must be specified on the command\-line before the actions they are intended to modify. Any modifier option applies to following actions on the same command-line until it is over-ridden. +-.IP \fIActions\fR ++.SH "GLOBAL OPTIONS" + .TP + \fB\-h\fR, \fB\-\-help\fR + Print a list of options. \fBtuna\fR will exit after this action, ignoring the remainder of the command-line. + .TP +-\fB\-g\fR, \fB\-\-gui\fR +-Start the GUI. Actions that follow this on the command-line will be processed without waiting for the GUI to complete. ++\fB\-v\fR, \fB\-\-version\fR ++Show version + .TP +-\fB\-a\fR, \fB\-\-config_file_apply=profilename\fR +-Apply changes described in profile ++\fB\-L\fR, \fB\-\-logging\fR=\fILOG-LEVEL\fR ++Log application details to file for given LOG-LEVEL + .TP +-\fB\-l\fR, \fB\-\-config_file_list\fR +-List preloaded profiles ++\fB\-D\fR, \fB\-\-debug\fR ++Print DEBUG level logging details to console ++.SH "COMMANDS" + .TP +-\fB\-i\fR, \fB\-\-isolate\fR +-Move all allowed threads and IRQs away from CPU\-LIST. Requires \fB\-c\fR or \fB-S\fR. ++\fBtuna isolate\fR ++usage: tuna-cmd.py isolate [-h] (-c CPU-LIST | -S CPU-SOCKET-LIST | -N) ++ ++Move all allowed threads and IRQs away from CPU\-LIST. Requires \fB\-c\fR, \fB-S\fR, or \fB-N\fR. ++ ++optional arguments: ++ -h, --help show this help message and exit ++ -c CPU-LIST, --cpus CPU-LIST ++ CPU-LIST affected by commands ++ -S CPU-SOCKET-LIST, --sockets CPU-SOCKET-LIST ++ CPU-SOCKET-LIST affected by commands ++ -N, --nohz_full CPUs in nohz_full kernel command line will be affected ++ by operations + .TP +-\fB\-I\fR, \fB\-\-include\fR +-Allow all allowed threads and IRQs to run on CPU\-LIST. Requires \fB\-c\fR or \fB-S\fR. ++\fBtuna include\fR ++usage: tuna-cmd.py include [-h] (-c CPU-LIST | -S CPU-SOCKET-LIST | -N) ++ ++Allow all allowed threads and IRQs to run on CPU\-LIST. Requires \fB\-c\fR, \fB-S\fR, or \fB-N\fR. ++ ++optional arguments: ++ -h, --help show this help message and exit ++ -c CPU-LIST, --cpus CPU-LIST ++ CPU-LIST affected by commands ++ -S CPU-SOCKET-LIST, --sockets CPU-SOCKET-LIST ++ CPU-SOCKET-LIST affected by commands ++ -N, --nohz_full CPUs in nohz_full kernel command line will be affected ++ by operations + .TP +-\fB\-m\fR, \fB\-\-move\fR +-Move selected entities to CPU\-LIST. Requires \fB\-c\fR and either \fB-t\fR or \fB-q\fR. ++\fBtuna move\fR ++usage: tuna-cmd.py move [-h] (-c CPU-LIST | -S CPU-SOCKET-LIST | -N) ++ [-t THREAD-LIST] [-q IRQ-LIST] ++ ++Move selected entities to CPU\-LIST. Requires \fB\-c\fR, \fB-S\fR, or \fB-N\fR and \fB-t\fR or \fB-q\fR. ++ ++optional arguments: ++ -h, --help show this help message and exit ++ -c CPU-LIST, --cpus CPU-LIST ++ CPU-LIST affected by commands ++ -S CPU-SOCKET-LIST, --sockets CPU-SOCKET-LIST ++ CPU-SOCKET-LIST affected by commands ++ -N, --nohz_full CPUs in nohz_full kernel command line will be affected ++ by operations ++ -t THREAD-LIST, --threads THREAD-LIST ++ THREAD-LIST affected by commands ++ -q IRQ-LIST, --irqs IRQ-LIST ++ IRQ-LIST affect by commands + .TP +-\fB\-p\fR, \fB\-\-priority\fR=\fI[POLICY:]\fRRTPRIO +-Set thread scheduler tunables: POLICY and RTPRIO. POLICY is one of OTHER, FIFO, RR, or BATCH. If \fB\-t\fR is not set, \fB\-p\fR will act as a Modifier saving the sched tunables for future Actions, for example \fB\-r\fR. ++\fBtuna spread\fR ++usage: tuna-cmd.py spread [-h] (-c CPU-LIST | -S CPU-SOCKET-LIST | -N) ++ [-t THREAD-LIST] [-q IRQ-LIST] ++ ++Spread selected entities over CPU-LIST. The specified threads and IRQs are each assigned to one cpu in CPU-LIST. Requires \fB\-c\fR, \fB-S\fR, or \fB-N\fR and \fB-t\fR or \fB-q\fR. ++ ++ ++optional arguments: ++ -h, --help show this help message and exit ++ -c CPU-LIST, --cpus CPU-LIST ++ CPU-LIST affected by commands ++ -S CPU-SOCKET-LIST, --sockets CPU-SOCKET-LIST ++ CPU-SOCKET-LIST affected by commands ++ -N, --nohz_full CPUs in nohz_full kernel command line will be affected ++ by operations ++ -t THREAD-LIST, --threads THREAD-LIST ++ THREAD-LIST affected by commands ++ -q IRQ-LIST, --irqs IRQ-LIST ++ IRQ-LIST affect by commands + .TP +-\fB\-P\fR, \fB\-\-show_threads\fR +-Show thread list. ++ ++\fBtuna priority\fR ++usage: tuna-cmd.py priority [-h] -t THREAD-LIST [-C] POLICY:RTPRIO ++ ++Set thread scheduler tunables: POLICY and RTPRIO. POLICY is one of OTHER, FIFO, RR, or BATCH. Provide POLICY, RTPRIO, or POLICY:RTPRIO separated by ":". If only POLICY is set, the RT priority will default to 1 if the policy is RT, and 0 otherwise. If only RTPRIO is specified, policy will not be changed. ++ ++positional arguments: ++ POLICY:RTPRIO Set thread scheduler tunables: POLICY and RTPRIO ++ ++optional arguments: ++ -h, --help show this help message and exit ++ -t THREAD-LIST, --threads THREAD-LIST ++ THREAD-LIST affected by commands ++ -C, --affect_children ++ Operation will affect children threads + .TP +-\fB\-Q\fR, \fB\-\-show_irqs\fR +-Show IRQ list. ++\fBtuna run\fR ++usage: tuna-cmd.py run [-h] [-c CPU-LIST | -S CPU-SOCKET-LIST | -N] ++ [-p PRIORITY] [-b] ++ COMMAND ++ ++Run the COMMAND. The entire command line must be provided inside "quotes". Modifiers \fB-c\fR, \fB-S\fR and \fB-p\fR can be used to set the affinity and scheduler tunables of the given COMMAND. ++ ++positional arguments: ++ COMMAND fork a new process and run the "COMMAND" ++ ++optional arguments: ++ -h, --help show this help message and exit ++ -c CPU-LIST, --cpus CPU-LIST ++ CPU-LIST affected by commands ++ -S CPU-SOCKET-LIST, --sockets CPU-SOCKET-LIST ++ CPU-SOCKET-LIST affected by commands ++ -N, --nohz_full CPUs in nohz_full kernel command line will be affected ++ by operations ++ -p PRIORITY, --priority PRIORITY ++ Set thread scheduler tunables: POLICY and RTPRIO ++ -b, --background Run command as background task ++ + .TP +-\fB\-r\fR, \fB\-\-run\fR=\fI"COMMAND"\fR +-Run the COMMAND. If arguments are passed, the entire command line must be provided inside "quotes". Modifiers \fB-c\fR and \fB-p\fR can be used to set the affinity and scheduler tunables of the given COMMAND. The arg[0] (i.e. the command) will be set in THREAD\-LIST. Likewise the \fB-t\fR, the COMMAND accepts the prefix \fB+\fR and \fB-\fR as wildcards in order to be appended or removed from THREAD\-LIST, respectively. ++\fBtuna save\fR ++usage: tuna-cmd.py save [-h] [-c CPU-LIST | -S CPU-SOCKET-LIST | -N] ++ [-t THREAD-LIST] ++ FILENAME ++ ++Save kthreads sched tunables to FILENAME ++ ++positional arguments: ++ FILENAME Save kthreads sched tunables to this file ++ ++optional arguments: ++ -h, --help show this help message and exit ++ -c CPU-LIST, --cpus CPU-LIST ++ CPU-LIST affected by commands ++ -S CPU-SOCKET-LIST, --sockets CPU-SOCKET-LIST ++ CPU-SOCKET-LIST affected by commands ++ -N, --nohz_full CPUs in nohz_full kernel command line will be affected ++ by operations ++ -t THREAD-LIST, --threads THREAD-LIST ++ THREAD-LIST affected by commands + .TP +-\fB\-R\fR, \fB\-\-refresh\fR=\fIMSEC\fR +-Refresh the GUI every MSEC milliseconds ++\fBtuna apply\fR ++usage: tuna-cmd.py apply [-h] profilename ++ ++Apply changes described in profile ++ ++positional arguments: ++ profilename Apply changes described in this file ++ ++optional arguments: ++ -h, --help show this help message and exit ++ + .TP +-\fB\-s\fR, \fB\-\-save\fR=\fIFILENAME\fR +-Save kthreads sched tunables to FILENAME. ++\fBtuna show_threads\fR ++usage: tuna-cmd.py show_threads [-h] [-c CPU-LIST | -N | -S CPU-SOCKET-LIST] ++ [-t THREAD-LIST | -q IRQ-LIST] [-U] [-K] [-C] ++ [-G] ++ ++Show thread list ++ ++optional arguments: ++ -h, --help show this help message and exit ++ -c CPU-LIST, --cpus CPU-LIST ++ CPU-LIST affected by commands ++ -N, --nohz_full CPUs in nohz_full kernel command line will be affected ++ by operations ++ -S CPU-SOCKET-LIST, --sockets CPU-SOCKET-LIST ++ CPU-SOCKET-LIST affected by commands ++ -t THREAD-LIST, --threads THREAD-LIST ++ THREAD-LIST affected by commands ++ -q IRQ-LIST, --irqs IRQ-LIST ++ IRQ-LIST affect by commands ++ -U, --no_uthreads Operations will not affect user threads ++ -K, --no_kthreads Operations will not affect kernel threads ++ -C, --affect_children ++ Operation will affect children threads ++ -G, --cgroups Display the processes with the type of cgroups they ++ are in ++ + .TP +-\fB\-v\fR, \fB\-\-version\fR +-Show version ++\fBtuna show_irqs\fR ++usage: tuna-cmd.py show_irqs [-h] [-c CPU-LIST | -N | -S CPU-SOCKET-LIST] ++ [-q IRQ-LIST] ++ ++Show IRQ list ++ ++optional arguments: ++ -h, --help show this help message and exit ++ -c CPU-LIST, --cpus CPU-LIST ++ CPU-LIST affected by commands ++ -N, --nohz_full CPUs in nohz_full kernel command line will be affected ++ by operations ++ -S CPU-SOCKET-LIST, --sockets CPU-SOCKET-LIST ++ CPU-SOCKET-LIST affected by commands ++ -q IRQ-LIST, --irqs IRQ-LIST ++ IRQ-LIST affect by commands ++ + .TP +-\fB\-W\fR, \fB\-\-what_is\fR +-Provides help about selected entities. Requires \fB-t\fR. ++\fBtuna show_configs\fR ++usage: tuna-cmd.py show_configs [-h] ++ ++List preloaded profiles ++ ++optional arguments: ++ -h, --help show this help message and exit ++ + .TP +-\fB\-x\fR, \fB\-\-spread\fR +-Spread selected entities over CPU\-LIST. Requires at least one of \fB-t\fR or \fB-q\fR. The specified threads and IRQs are each assigned to one cpu in CPU\-LIST. ++\fB tuna what_is\fR ++usage: tuna-cmd.py what_is [-h] THREAD-LIST ++ ++Provides help about selected entities ++ ++positional arguments: ++ THREAD-LIST THREAD-LIST affected by commands ++ ++optional arguments: ++ -h, --help show this help message and exit ++.TP ++\fB tuna gui\fR ++usage: tuna-cmd.py gui [-h] [-d] [-R MSEC] ++ [-c CPU-LIST | -N | -S CPU-SOCKET-LIST] [-U] [-K] ++ ++Start the GUI ++ ++optional arguments: ++ -h, --help show this help message and exit ++ -d, --disable_perf Explicitly disable usage of perf in GUI for process ++ view ++ -R MSEC, --refresh MSEC ++ Refresh the GUI every MSEC milliseconds ++ -c CPU-LIST, --cpus CPU-LIST ++ CPU-LIST affected by commands ++ -N, --nohz_full CPUs in nohz_full kernel command line will be affected ++ by operations ++ -S CPU-SOCKET-LIST, --sockets CPU-SOCKET-LIST ++ CPU-SOCKET-LIST affected by commands ++ -U, --no_uthreads Operations will not affect user threads ++ -K, --no_kthreads Operations will not affect kernel threads + .IP \fIModifiers\fR + .TP + \fB\-c\fR, \fB\-\-cpus\fR=\fICPU\-LIST\fR +-CPU\-LIST affected by commands. Requires a CPU number or a comma-separated list of CPU numbers. +-.TP +-\fB\-C\fR, \fB\-\-affect_children\fR +-Operation will affect children threads. +-.TP +-\fB\-d\fR, \fB\-\-disable_perf\fR +-Explicitly disable usage of perf in GUI for process view +-.TP +-\fB\-D\fR, \fB\-\-debug\fR +-Print DEBUG level logging details to console. +-.TP +-\fB\-f\fR, \fB\-\-filter\fR +-Disable display of selected CPUs in \fB--gui\fR. Requires \fB-c\R. +-.TP +-\fB\-G\fR, \fB\-\-cgroup\fR +-Display the processes with the type of cgroups they are in. Requires \fB-P\R. +-.TP +-\fB\-K\fR, \fB\-\-no_kthreads\fR +-Operations will not affect kernel threads. +-.TP +-\fB\-L\fR, \fB\-\-logging\fR=\fILOG\-LEVEL\fR +-Log application details to log file for given LOG-LEVEL +-.TP +-\fB\-N\fR, \fB\-\-nohz_full\fR +-CPUs in nohz_full= kernel command line parameter will be affected by operations +-.TP +-\fB\-q\fR, \fB\-\-irqs\fR=\fIIRQ\-LIST\fR +-IRQ\-LIST affected by commands. Requires an IRQ number or a comma-separated list of IRQ numbers. ++CPU\-LIST affected by commands. Requires a CPU number, a range, or a comma-separated list of CPU numbers. + .TP + \fB\-S\fR, \fB\-\-sockets\fR=\fICPU\-SOCKET\-LIST\fR + CPU\-SOCKET\-LIST affected by commands. Requires a socket number or a comma-separated list of socket numbers. + .TP + \fB\-t\fR, \fB\-\-threads\fR=\fITHREAD\-LIST\fR +-THREAD\-LIST affected by commands. Requires a thread number or thread name, or a comma-separated list of thread numbers and/or names. Thread names may contain wildcards. Be sure to quote or escape any wildcard specifications. If only \fB-\fR is passed as argument, the THREAD\-LIST will be cleared. ++THREAD\-LIST affected by commands. Requires a thread number or thread name, or a comma-separated list of thread numbers and/or names. Thread names may contain wildcards. Be sure to quote or escape any wildcard specifications. + .TP +-\fB\-U\fR, \fB\-\-no_uthreads\fR +-Operations will not affect user threads. + .SH USAGE EXAMPLES + If for instance the Ethernet NICs have multiple queues for both receive and transmit, each with its own IRQ, the Ethernet IRQs can be associated with a CPU socket: + .TP +-.B tuna -S 2 -i -q 'eth*' -x ++.B tuna isolate -S 2 ++.TP ++.B tuna spread -q 'eth*' -S 2 + + Move everything off the CPUs in socket 2, then spread the IRQs for the Ethernet devices across those same CPUs. +diff --git a/tuna-cmd.py b/tuna-cmd.py +index 4ac01f4f4522..8be35f7fb4c4 100755 +--- a/tuna-cmd.py ++++ b/tuna-cmd.py +@@ -101,7 +101,7 @@ def gen_parser(): + "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=tuna.get_policy_and_rtprio, help="policy/priority help"), ++ "priority": dict(type=tuna.get_policy_and_rtprio, metavar="POLICY:RTPRIO", help="Set thread scheduler tunables: POLICY and RTPRIO"), + } + + MODS = { +@@ -120,7 +120,7 @@ def gen_parser(): + "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"), ++ "priority": dict(default=(None, None), metavar="POLICY:RTPRIO", 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") + } + +-- +2.31.1 + diff --git a/SOURCES/tuna-remove-import-and-fix-help-message.patch b/SOURCES/tuna-remove-import-and-fix-help-message.patch new file mode 100644 index 0000000..0bd2812 --- /dev/null +++ b/SOURCES/tuna-remove-import-and-fix-help-message.patch @@ -0,0 +1,33 @@ +From bef2c2009ed5151cf7ae4bf258a908c9f577ca7d Mon Sep 17 00:00:00 2001 +From: Leah Leshchinsky +Date: Wed, 2 Nov 2022 11:16:48 -0400 +Subject: [PATCH 1/2] tuna: remove import and fix help message + +Remove getopt import and fix help message for 'spread' command. + +Signed-off-by: Leah Leshchinsky + +diff --git a/tuna-cmd.py b/tuna-cmd.py +index 44d9faaf15fb..4ac01f4f4522 100755 +--- a/tuna-cmd.py ++++ b/tuna-cmd.py +@@ -21,7 +21,6 @@ import os + import sys + import errno + import re +-import getopt + import fnmatch + import gettext + import locale +@@ -140,7 +139,7 @@ def gen_parser(): + 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", ++ spread = subparser.add_parser('spread', description="Spread 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") +-- +2.31.1 + diff --git a/SOURCES/tuna-tuna-cmd.py-use-fstrings.patch b/SOURCES/tuna-tuna-cmd.py-use-fstrings.patch new file mode 100644 index 0000000..e9ba212 --- /dev/null +++ b/SOURCES/tuna-tuna-cmd.py-use-fstrings.patch @@ -0,0 +1,75 @@ +From 1e2f6a3b64bce4ea335e97b1ab31ada3e082a6bc Mon Sep 17 00:00:00 2001 +From: Leah Leshchinsky +Date: Tue, 1 Nov 2022 13:24:00 -0400 +Subject: [PATCH 2/4] tuna: tuna-cmd.py use fstrings + +Add fstrings where possible to improve readabilty + +Due to the discussion regarding dropping the language feature, gettext +shorthand _() have been removed. + +Signed-off-by: Leah Leshchinsky +Signed-off-by: John Kacur + +diff --git a/tuna-cmd.py b/tuna-cmd.py +index c5bc65059da7..44d9faaf15fb 100755 +--- a/tuna-cmd.py ++++ b/tuna-cmd.py +@@ -89,7 +89,7 @@ irqs = None + + class HelpMessageParser(argparse.ArgumentParser): + def error(self, message): +- sys.stderr.write('error: %s\n' % message) ++ sys.stderr.write(f'error: {message}\n') + self.print_help() + sys.exit(2) + +@@ -263,13 +263,16 @@ def thread_help(tid): + ps = procfs.pidstats() + + if tid not in ps: +- print("tuna: " + _("thread %d doesn't exists!") % tid) ++ print(f"tuna: thread {tid} doesn't exist!") + return + + pinfo = ps[tid] + cmdline = procfs.process_cmdline(pinfo) + help, title = tuna.kthread_help_plain_text(tid, cmdline) +- print("%s\n\n%s" % (title, _(help))) ++ print(title, "\n\n") ++ if help.isspace(): ++ help = "No help description available." ++ print(help) + + + def save(cpu_list, thread_list, filename): +@@ -295,7 +298,7 @@ def ps_show_header(has_ctxt_switch_info, cgroups=False): + + def ps_show_sockets(pid, ps, inodes, inode_re, indent=0): + header_printed = False +- dirname = "/proc/%s/fd" % pid ++ dirname = f"/proc/{pid}/fd" + try: + filenames = os.listdir(dirname) + except: # Process died +@@ -688,7 +691,7 @@ def main(): + try: + tuna.threads_set_priority(args.thread_list, args.priority, args.affect_children) + except OSError as err: +- print("tuna: %s" % err) ++ print(f"tuna: {err}") + sys.exit(2) + + elif args.command in ['show_configs']: +@@ -705,7 +708,7 @@ def main(): + 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")) ++ parser.error(f"tuna: {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) +-- +2.31.1 + diff --git a/SOURCES/tuna-tuna.py-use-fstrings.patch b/SOURCES/tuna-tuna.py-use-fstrings.patch new file mode 100644 index 0000000..02277c9 --- /dev/null +++ b/SOURCES/tuna-tuna.py-use-fstrings.patch @@ -0,0 +1,94 @@ +From efcc75a317b63227a8630ca17e9bcf153a6cc03e Mon Sep 17 00:00:00 2001 +From: Leah Leshchinsky +Date: Mon, 31 Oct 2022 13:11:31 -0400 +Subject: [PATCH 3/4] tuna: tuna.py use fstrings + +Add fstrings where possible to improve readabilty + +Signed-off-by: Leah Leshchinsky +Signed-off-by: John Kacur + +diff --git a/tuna/tuna.py b/tuna/tuna.py +index 43adb84079e4..e527facb151c 100755 +--- a/tuna/tuna.py ++++ b/tuna/tuna.py +@@ -58,7 +58,7 @@ def iskthread(pid): + # in this function, so that they know that the thread vanished and + # can act accordingly, removing entries from tree views, etc + try: +- f = open("/proc/%d/smaps" % pid) ++ f = open(f"/proc/{pid}/smaps") + except IOError: + # Thread has vanished + return True +@@ -88,7 +88,7 @@ def is_irq_thread(cmd): + return cmd[:4] in ("IRQ-", "irq/") + + def threaded_irq_re(irq): +- return re.compile("(irq/%s-.+|IRQ-%s)" % (irq, irq)) ++ return re.compile(f"(irq/{irq}-.+|IRQ-{irq})") + + # FIXME: Move to python-linux-procfs + def has_threaded_irqs(ps): +@@ -96,10 +96,10 @@ def has_threaded_irqs(ps): + return len(ps.find_by_regex(irq_re)) > 0 + + def set_irq_affinity_filename(filename, bitmasklist): +- pathname = "/proc/irq/%s" % filename ++ pathname = f"/proc/irq/{filename}" + f = open(pathname, "w") + text = ",".join(["%x" % a for a in bitmasklist]) +- f.write("%s\n" % text) ++ f.write(f"{text}\n") + try: + f.close() + except IOError: +@@ -225,7 +225,7 @@ def move_threads_to_cpu(cpus, pid_list, set_affinity_warning=None, spread=False) + if pid not in ps: + continue + +- threads = procfs.pidstats("/proc/%d/task" % pid) ++ threads = procfs.pidstats(f"/proc/{pid}/task") + for tid in list(threads.keys()): + try: + curr_affinity = os.sched_getaffinity(tid) +@@ -320,11 +320,11 @@ def affinity_remove_cpus(affinity, cpus, nr_cpus): + # Should be moved to python_linux_procfs.interrupts, shared with interrupts.parse_affinity, etc. + def parse_irq_affinity_filename(filename, nr_cpus): + try: +- f = open("/proc/irq/%s" % filename) ++ f = open(f"/proc/irq/{filename}") + except IOError as err: + if procfs.is_s390(): + print("This operation is not supported on s390", file=sys.stderr) +- print("tuna: %s" % err, file=sys.stderr) ++ print(f"tuna: {err}", file=sys.stderr) + sys.exit(2) + + line = f.readline() +@@ -624,19 +624,19 @@ def run_command(cmd, policy, rtprio, cpu_list, background): + try: + thread_set_priority(pid, policy, rtprio) + except (SystemError, OSError) as err: +- print("tuna: %s" % err) ++ print(f"tuna: {err}") + sys.exit(2) + if cpu_list: + try: + os.sched_setaffinity(pid, cpu_list) + except (SystemError, OSError) as err: +- print("tuna: %s" % err) ++ print(f"tuna: {err}") + sys.exit(2) + + try: + os.execvp(cmd_list[0], cmd_list) + except (SystemError, OSError) as err: +- print("tuna: %s" % err) ++ print(f"tuna: {err}") + sys.exit(2) + else: + if not background: +-- +2.31.1 + diff --git a/SOURCES/tuna-tuna_gui.py-use-fstrings.patch b/SOURCES/tuna-tuna_gui.py-use-fstrings.patch new file mode 100644 index 0000000..9e4663e --- /dev/null +++ b/SOURCES/tuna-tuna_gui.py-use-fstrings.patch @@ -0,0 +1,26 @@ +From 67c5a4dc31f7dd8a6204a1a636fcec4e8f17a86b Mon Sep 17 00:00:00 2001 +From: Leah Leshchinsky +Date: Fri, 28 Oct 2022 12:52:46 -0400 +Subject: [PATCH 1/4] tuna: tuna_gui.py use fstrings + +Add fstrings where possible to improve readabilty + +Signed-off-by: Leah Leshchinsky +Signed-off-by: John Kacur + +diff --git a/tuna/tuna_gui.py b/tuna/tuna_gui.py +index f1f2caacbcba..459f90303ed5 100755 +--- a/tuna/tuna_gui.py ++++ b/tuna/tuna_gui.py +@@ -33,7 +33,7 @@ class main_gui: + if self.check_root(): + sys.exit(1) + for dir in tuna_glade_dirs: +- tuna_glade = "%s/tuna_gui.glade" % dir ++ tuna_glade = f"{dir}/tuna_gui.glade" + if os.access(tuna_glade, os.F_OK): + break + self.wtree = Gtk.Builder() +-- +2.31.1 + diff --git a/SPECS/tuna.spec b/SPECS/tuna.spec index d885bf6..7e44416 100644 --- a/SPECS/tuna.spec +++ b/SPECS/tuna.spec @@ -1,6 +1,6 @@ Name: tuna Version: 0.18 -Release: 2%{?dist} +Release: 12%{?dist} License: GPLv2 Summary: Application tuning GUI & command line utility URL: https://git.kernel.org/pub/scm/utils/tuna/tuna.git @@ -8,12 +8,24 @@ Source: https://www.kernel.org/pub/software/utils/%{name}/%{name}-%{version}.tar BuildArch: noarch BuildRequires: python3-devel, gettext -Requires: python3-ethtool Requires: python3-linux-procfs >= 0.6 # This really should be a Suggests... # Requires: python-inet_diag # Patches +Patch1: tuna-Update-command-line-interface.patch +Patch2: tuna-Move-get_policy_and_rtprio-call-to-parser-level.patch +Patch3: tuna-Add-sockets-command-line-option.patch +Patch4: tuna-Replace-python_ethtool-with-builtin-funtionalit.patch +Patch5: tuna-Fix-matching-irqs-in-ps_show_thread.patch +Patch6: tuna-Remove-threads-print-statement.patch +Patch7: tuna-tuna_gui.py-use-fstrings.patch +Patch8: tuna-tuna-cmd.py-use-fstrings.patch +Patch9: tuna-tuna.py-use-fstrings.patch +Patch10: tuna-remove-import-and-fix-help-message.patch +Patch11: tuna-Update-manpages-for-argparse-CLI-changes.patch +Patch12: tuna-Adapt-show_threads-cgroup-output-to-terminal-si.patch +Patch13: tuna-Fix-show_threads-cgroups-run-without-a-term.patch %description Provides interface for changing scheduler and IRQ tunables, at whole CPU and at @@ -25,7 +37,7 @@ Can be used as a command line utility without requiring the GUI libraries to be installed. %prep -%setup -q +%autosetup -p1 %build %py3_build @@ -67,6 +79,49 @@ done %{_datadir}/polkit-1/actions/org.tuna.policy %changelog +* Wed Nov 23 2022 Leah Leshchinsky - 0.18-12 +- Fix show_threads --cgroups run without term +Resolves: rhbz#2121517 + +* Fri Nov 18 2022 Leah Leshchinsky - 0.18-11 +- Adapt show_threads cgroup output to terminal size +Resolves: rhbz#2121517 + +* Wed Nov 09 2022 Leah Leshchinsky - 0.18-10 +- Edit run_tests.sh to support new CLI changes +Resolves: rhbz#2141349 + +* Tue Nov 08 2022 Leah Leshchinsky - 0.18-9 +- Remove import and fix help message +- Update manpages for argparse CLI changes +Resolves: rhbz#2138692 + +* Wed Nov 02 2022 Leah Leshchinsky - 0.18-8 +- Use f-strings in tuna where possible +Resolves: rhbz#2120803 + +* Wed Oct 26 2022 Leah Leshchinsky - 0.18-7 +- Add sockets command line option +Resolves: rhbz#2122781 + +* Wed Oct 26 2022 Leah Leshchinsky - 0.18-6 +- Update tuna command line interface +- Move get_policy_and_rtprio call to parser level +- Remove threads print statement +Resolves: rhbz#2062865 + +* Mon Oct 03 2022 John Kacur - 0.18-5 +- Match irqs with "irqs/" +Resolves: rhbz#2131343 + +* Fri Sep 30 2022 John Kacur - 0.18-4 +- Remove the "Requires" of python-ethtool from the specfile +Resolves: rhbz#2123751 + +* Fri Sep 30 2022 John Kacur - 0.18-3 +- Replace dependency on python-ethtool with built-in functionality +Resolves: rhbz#2123751 + * Wed Jun 29 2022 Leah Leshchinsky - 0.18-2 - Delete patches Resolves: rhbz#2068629