diff --git a/tuned-main.conf b/tuned-main.conf index 1f1269f..004511e 100644 --- a/tuned-main.conf +++ b/tuned-main.conf @@ -77,7 +77,7 @@ log_file_max_size = 1MB # connections_backlog = 1024 # TuneD daemon rollback strategy. Supported values: auto|not_on_exit -# - auto: rollbacks are always performed on a profile switch or +# - auto: rollbacks are always performed on a profile switch or # graceful TuneD process exit # - not_on_exit: rollbacks are always performed on a profile # switch, but not on any kind of TuneD process exit @@ -87,3 +87,13 @@ log_file_max_size = 1MB # In case of conflicts in profile names, the later directory # takes precedence # profile_dirs = /usr/lib/tuned/profiles,/etc/tuned/profiles + +# Timeout in seconds to wait until udev settles. Value 0 disables the wait. +# With non-zero wait TuneD startup is delayed until there are no pending +# udev events or the specified timeout occurs. +# The delay can help in situations where there are a lot of udev events +# during TuneD startup and TuneD is too slow to handle them. +# In environments where systemd is utilised for starting TuneD +# it is better to keep this feature disabled and rely on systemd +# functionality (systemd-udev-settle). +startup_udev_settle_wait = 0 diff --git a/tuned/consts.py b/tuned/consts.py index f933efa..577ad95 100644 --- a/tuned/consts.py +++ b/tuned/consts.py @@ -146,6 +146,7 @@ CFG_UNIX_SOCKET_CONNECTIONS_BACKLOG = "connections_backlog" CFG_CPU_EPP_FLAG = "hwp_epp" CFG_ROLLBACK = "rollback" CFG_PROFILE_DIRS = "profile_dirs" +CFG_STARTUP_UDEV_SETTLE_WAIT = "startup_udev_settle_wait" # no_daemon mode CFG_DEF_DAEMON = True @@ -197,6 +198,8 @@ CFG_FUNC_UNIX_SOCKET_CONNECTIONS_BACKLOG = "getint" CFG_DEF_ROLLBACK = "auto" # default profile directories CFG_DEF_PROFILE_DIRS = [SYSTEM_PROFILES_DIR, USER_PROFILES_DIR] +# default startup udev settle wait +CFG_DEF_STARTUP_UDEV_SETTLE_WAIT = 0 PATH_CPU_DMA_LATENCY = "/dev/cpu_dma_latency" diff --git a/tuned/daemon/controller.py b/tuned/daemon/controller.py index 726e3a2..85ae2ff 100644 --- a/tuned/daemon/controller.py +++ b/tuned/daemon/controller.py @@ -6,6 +6,8 @@ import threading import tuned.consts as consts from tuned.utils.commands import commands from tuned.plugins import hotplug +import pyudev +import time __all__ = ["Controller"] @@ -54,13 +56,29 @@ class Controller(tuned.exports.interfaces.ExportableInterface): Controller main loop. The call is blocking. """ log.info("starting controller") + self._terminate.clear() + wait_settle = self._global_config.get_int(consts.CFG_STARTUP_UDEV_SETTLE_WAIT, \ + consts.CFG_DEF_STARTUP_UDEV_SETTLE_WAIT) + if wait_settle > 0: + log.info("waiting for udev to settle") + monitor = pyudev.Monitor.from_netlink(pyudev.Context()) + p = True + t = time.time() + while time.time() < (t + wait_settle) and not self._terminate.is_set() and p: + p = monitor.poll(timeout = 1) + if not self._terminate.is_set(): + if p: + log.info("udev settle timed out") + else: + log.info("udev settled") + del monitor + res = self.start() daemon = self._global_config.get_bool(consts.CFG_DAEMON, consts.CFG_DEF_DAEMON) if not res and daemon: exports.start() if daemon: - self._terminate.clear() # we have to pass some timeout, otherwise signals will not work while not self._cmd.wait(self._terminate, 1): exports.period_check() diff --git a/tuned/utils/global_config.py b/tuned/utils/global_config.py index e0ed436..2e02ce3 100644 --- a/tuned/utils/global_config.py +++ b/tuned/utils/global_config.py @@ -75,7 +75,10 @@ class GlobalConfig(): if isinstance(i, int): return i else: - return int(i, 0) + try: + return int(i, 0) + except ValueError: + log.error("Error parsing integer '%s', using '%d'." %(str(i), default)) return default def get_list(self, key, default = []):