From 3c7b4195e351fa4f1f98c602c31f4271c7edece3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= Date: Tue, 28 Apr 2020 14:31:20 +0200 Subject: [PATCH] Add irqbalance plugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The irqbalance plugin is a replacement for the bash functions irqbalance_banned_cpus_setup and irqbalance_banned_cpus_clear. It configures the banned CPUs in /etc/sysconfig/irqbalance. Then it restarts irqbalance (if and only if it was previously running). The banned CPUs can be specified as a CPU list. For example: [irqbalance] banned_cpus=2,4,9-13 Signed-off-by: Ondřej Lysoněk Resolves: rhbz#1784645 --- tuned/consts.py | 3 + tuned/plugins/plugin_irqbalance.py | 110 +++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 tuned/plugins/plugin_irqbalance.py diff --git a/tuned/consts.py b/tuned/consts.py index 40928ec..6d1ff53 100644 --- a/tuned/consts.py +++ b/tuned/consts.py @@ -48,6 +48,9 @@ MODULES_FILE = "/etc/modprobe.d/tuned.conf" SYSTEMD_SYSTEM_CONF_FILE = "/etc/systemd/system.conf" SYSTEMD_CPUAFFINITY_VAR = "CPUAffinity" +# irqbalance plugin configuration +IRQBALANCE_SYSCONFIG_FILE = "/etc/sysconfig/irqbalance" + # number of backups LOG_FILE_COUNT = 2 LOG_FILE_MAXBYTES = 100*1000 diff --git a/tuned/plugins/plugin_irqbalance.py b/tuned/plugins/plugin_irqbalance.py new file mode 100644 index 0000000..5bcffac --- /dev/null +++ b/tuned/plugins/plugin_irqbalance.py @@ -0,0 +1,110 @@ +from . import base +from .decorators import command_custom +from tuned import consts +import tuned.logs +import errno +import perf +import re + +log = tuned.logs.get() + +class IrqbalancePlugin(base.Plugin): + """ + Plugin for irqbalance settings management. + """ + + def __init__(self, *args, **kwargs): + super(IrqbalancePlugin, self).__init__(*args, **kwargs) + self._cpus = perf.cpu_map() + + def _instance_init(self, instance): + instance._has_dynamic_tuning = False + instance._has_static_tuning = True + + def _instance_cleanup(self, instance): + pass + + @classmethod + def _get_config_options(cls): + return { + "banned_cpus": None, + } + + def _read_irqbalance_sysconfig(self): + try: + with open(consts.IRQBALANCE_SYSCONFIG_FILE, "r") as f: + return f.read() + except IOError as e: + if e.errno == errno.ENOENT: + log.warn("irqbalance sysconfig file is missing. Is irqbalance installed?") + else: + log.error("Failed to read irqbalance sysconfig file: %s" % e) + return None + + def _write_irqbalance_sysconfig(self, content): + try: + with open(consts.IRQBALANCE_SYSCONFIG_FILE, "w") as f: + f.write(content) + return True + except IOError as e: + log.error("Failed to write irqbalance sysconfig file: %s" % e) + return False + + def _write_banned_cpus(self, sysconfig, banned_cpumask): + return sysconfig + "IRQBALANCE_BANNED_CPUS=%s\n" % banned_cpumask + + def _clear_banned_cpus(self, sysconfig): + lines = [] + for line in sysconfig.split("\n"): + if not re.match(r"\s*IRQBALANCE_BANNED_CPUS=", line): + lines.append(line) + return "\n".join(lines) + + def _restart_irqbalance(self): + # Exit code 5 means unit not found (see 'EXIT_NOTINSTALLED' in + # systemd.exec(5)) + retcode, out = self._cmd.execute( + ["systemctl", "try-restart", "irqbalance"], + no_errors=[5]) + if retcode != 0: + log.warn("Failed to restart irqbalance. Is it installed?") + + def _set_banned_cpus(self, banned_cpumask): + content = self._read_irqbalance_sysconfig() + if content is None: + return + content = self._clear_banned_cpus(content) + content = self._write_banned_cpus(content, banned_cpumask) + if self._write_irqbalance_sysconfig(content): + self._restart_irqbalance() + + def _restore_banned_cpus(self): + content = self._read_irqbalance_sysconfig() + if content is None: + return + content = self._clear_banned_cpus(content) + if self._write_irqbalance_sysconfig(content): + self._restart_irqbalance() + + @command_custom("banned_cpus", per_device=False) + def _banned_cpus(self, enabling, value, verify, ignore_missing): + banned_cpumask = None + if value is not None: + banned = set(self._cmd.cpulist_unpack(value)) + present = set(self._cpus) + if banned.issubset(present): + banned_cpumask = self._cmd.cpulist2hex(list(banned)) + else: + str_cpus = ",".join([str(x) for x in self._cpus]) + log.error("Invalid banned_cpus specified, '%s' does not match available cores '%s'" + % (value, str_cpus)) + + if (enabling or verify) and banned_cpumask is None: + return None + if verify: + # Verification is currently not supported + return None + elif enabling: + self._set_banned_cpus(banned_cpumask) + else: + self._restore_banned_cpus()