diff --git a/tuned/plugins/plugin_scheduler.py b/tuned/plugins/plugin_scheduler.py index 32b9c1a..2b55f8b 100644 --- a/tuned/plugins/plugin_scheduler.py +++ b/tuned/plugins/plugin_scheduler.py @@ -12,12 +12,16 @@ import perf import select import tuned.consts as consts import procfs -import schedutils from tuned.utils.commands import commands import errno import os import collections import math +# Check existence of scheduler API in os module +try: + os.SCHED_FIFO +except AttributeError: + import schedutils log = tuned.logs.get() @@ -52,20 +56,90 @@ class IRQAffinities(object): # IRQs that don't support changing CPU affinity: self.unchangeable = [] +class SchedulerUtils(object): + """ + Class encapsulating scheduler implementation in os module + """ + + _dict_schedcfg2schedconst = { + "f": "SCHED_FIFO", + "b": "SCHED_BATCH", + "r": "SCHED_RR", + "o": "SCHED_OTHER", + "i": "SCHED_IDLE", + } + + def __init__(self): + # {"f": os.SCHED_FIFO...} + self._dict_schedcfg2num = dict((k, getattr(os, name)) for k, name in self._dict_schedcfg2schedconst.items()) + # { os.SCHED_FIFO: "SCHED_FIFO"... } + self._dict_num2schedconst = dict((getattr(os, name), name) for name in self._dict_schedcfg2schedconst.values()) + + def sched_cfg_to_num(self, str_scheduler): + return self._dict_schedcfg2num.get(str_scheduler) + + # Reimplementation of schedstr from schedutils for logging purposes + def sched_num_to_const(self, scheduler): + return self._dict_num2schedconst.get(scheduler) + + def get_scheduler(self, pid): + return os.sched_getscheduler(pid) + + def set_scheduler(self, pid, sched, prio): + os.sched_setscheduler(pid, sched, os.sched_param(prio)) + + def get_affinity(self, pid): + return os.sched_getaffinity(pid) + + def set_affinity(self, pid, affinity): + os.sched_setaffinity(pid, affinity) + + def get_priority(self, pid): + return os.sched_getparam(pid).sched_priority + + def get_priority_min(self, sched): + return os.sched_get_priority_min(sched) + + def get_priority_max(self, sched): + return os.sched_get_priority_max(sched) + +class SchedulerUtilsSchedutils(SchedulerUtils): + """ + Class encapsulating scheduler implementation in schedutils module + """ + def __init__(self): + # { "f": schedutils.SCHED_FIFO... } + self._dict_schedcfg2num = dict((k, getattr(schedutils, name)) for k, name in self._dict_schedcfg2schedconst.items()) + # { schedutils.SCHED_FIFO: "SCHED_FIFO"... } + self._dict_num2schedconst = dict((getattr(schedutils, name), name) for name in self._dict_schedcfg2schedconst.values()) + + def get_scheduler(self, pid): + return schedutils.get_scheduler(pid) + + def set_scheduler(self, pid, sched, prio): + schedutils.set_scheduler(pid, sched, prio) + + def get_affinity(self, pid): + return schedutils.get_affinity(pid) + + def set_affinity(self, pid, affinity): + schedutils.set_affinity(pid, affinity) + + def get_priority(self, pid): + return schedutils.get_priority(pid) + + def get_priority_min(self, sched): + return schedutils.get_priority_min(sched) + + def get_priority_max(self, sched): + return schedutils.get_priority_max(sched) + class SchedulerPlugin(base.Plugin): """ Plugin for tuning of scheduler. Currently it can control scheduling priorities of system threads (it is substitution for the rtctl tool). """ - _dict_schedcfg2num = { - "f": schedutils.SCHED_FIFO, - "b": schedutils.SCHED_BATCH, - "r": schedutils.SCHED_RR, - "o": schedutils.SCHED_OTHER, - "i": schedutils.SCHED_IDLE, - } - def __init__(self, monitor_repository, storage_factory, hardware_inventory, device_matcher, device_matcher_udev, plugin_instance_factory, global_cfg, variables): super(SchedulerPlugin, self).__init__(monitor_repository, storage_factory, hardware_inventory, device_matcher, device_matcher_udev, plugin_instance_factory, global_cfg, variables) self._has_dynamic_options = True @@ -83,6 +157,10 @@ class SchedulerPlugin(base.Plugin): command_name = "scheduler") self._irq_storage_key = self._storage_key( command_name = "irq") + try: + self._scheduler_utils = SchedulerUtils() + except AttributeError: + self._scheduler_utils = SchedulerUtilsSchedutils() def _calc_mmap_pages(self, mmap_pages): if mmap_pages is None: @@ -216,20 +294,20 @@ class SchedulerPlugin(base.Plugin): # instead of OSError # If PID doesn't exist, errno == ESRCH def _get_rt(self, pid): - scheduler = schedutils.get_scheduler(pid) - sched_str = schedutils.schedstr(scheduler) - priority = schedutils.get_priority(pid) + scheduler = self._scheduler_utils.get_scheduler(pid) + sched_str = self._scheduler_utils.sched_num_to_const(scheduler) + priority = self._scheduler_utils.get_priority(pid) log.debug("Read scheduler policy '%s' and priority '%d' of PID '%d'" % (sched_str, priority, pid)) return (scheduler, priority) def _set_rt(self, pid, sched, prio): - sched_str = schedutils.schedstr(sched) + sched_str = self._scheduler_utils.sched_num_to_const(sched) log.debug("Setting scheduler policy to '%s' and priority to '%d' of PID '%d'." % (sched_str, prio, pid)) try: - prio_min = schedutils.get_priority_min(sched) - prio_max = schedutils.get_priority_max(sched) + prio_min = self._scheduler_utils.get_priority_min(sched) + prio_max = self._scheduler_utils.get_priority_max(sched) if prio < prio_min or prio > prio_max: log.error("Priority for %s must be in range %d - %d. '%d' was given." % (sched_str, prio_min, @@ -240,7 +318,7 @@ class SchedulerPlugin(base.Plugin): log.error("Failed to get allowed priority range: %s" % e) try: - schedutils.set_scheduler(pid, sched, prio) + self._scheduler_utils.set_scheduler(pid, sched, prio) except (SystemError, OSError) as e: if hasattr(e, "errno") and e.errno == errno.ESRCH: log.debug("Failed to set scheduling parameters of PID %d, the task vanished." @@ -404,7 +482,7 @@ class SchedulerPlugin(base.Plugin): self._scheduler_original[pid].cmdline = cmd def _convert_sched_params(self, str_scheduler, str_priority): - scheduler = self._dict_schedcfg2num.get(str_scheduler) + scheduler = self._scheduler_utils.sched_cfg_to_num(str_scheduler) if scheduler is None and str_scheduler != "*": log.error("Invalid scheduler: %s. Scheduler and priority will be ignored." % str_scheduler) @@ -759,14 +837,14 @@ class SchedulerPlugin(base.Plugin): # instead of OSError # If PID doesn't exist, errno == ESRCH def _get_affinity(self, pid): - res = schedutils.get_affinity(pid) + res = self._scheduler_utils.get_affinity(pid) log.debug("Read affinity '%s' of PID %d" % (res, pid)) return res def _set_affinity(self, pid, affinity): log.debug("Setting CPU affinity of PID %d to '%s'." % (pid, affinity)) try: - schedutils.set_affinity(pid, affinity) + self._scheduler_utils.set_affinity(pid, affinity) return True # Workaround for old python-schedutils (pre-0.4) which # incorrectly raised SystemError instead of OSError