Skip to content

Commit

Permalink
Merge pull request redhat-performance#533 from jmencak/rollbacks
Browse files Browse the repository at this point in the history
Add rollback_on_exit option
  • Loading branch information
yarda authored Jun 14, 2023
2 parents f65b43d + 7f3a79b commit 850368d
Show file tree
Hide file tree
Showing 16 changed files with 68 additions and 39 deletions.
7 changes: 7 additions & 0 deletions tuned-main.conf
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,10 @@ log_file_max_size = 1MB
# Size of connections backlog for listen function on socket
# Higher value allows to process requests from more clients
# connections_backlog = 1024

# TuneD daemon rollback strategy. Supported values: auto|not_on_exit
# - 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
# rollback = auto
6 changes: 6 additions & 0 deletions tuned/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@
FUNCTION_PREFIX = "function_"
# prefix for exported environment variables when calling scripts
ENV_PREFIX = "TUNED_"
ROLLBACK_NOT_ON_EXIT = 0
ROLLBACK_SOFT = 1
ROLLBACK_FULL = 2

# tuned-gui
PREFIX_PROFILE_FACTORY = "System"
Expand Down Expand Up @@ -108,6 +111,7 @@
CFG_UNIX_SOCKET_PERMISIONS = "unix_socket_permissions"
CFG_UNIX_SOCKET_CONNECTIONS_BACKLOG = "connections_backlog"
CFG_CPU_EPP_FLAG = "hwp_epp"
CFG_ROLLBACK = "rollback"

# no_daemon mode
CFG_DEF_DAEMON = True
Expand Down Expand Up @@ -155,6 +159,8 @@
# default unix socket conections backlog
CFG_DEF_UNIX_SOCKET_CONNECTIONS_BACKLOG = "1024"
CFG_FUNC_UNIX_SOCKET_CONNECTIONS_BACKLOG = "getint"
# default rollback strategy
CFG_DEF_ROLLBACK = "auto"

PATH_CPU_DMA_LATENCY = "/dev/cpu_dma_latency"

Expand Down
6 changes: 3 additions & 3 deletions tuned/daemon/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,13 @@ def start(self, caller = None):
return self._daemon.start()

@exports.export("", "b")
def stop(self, caller = None):
def stop(self, caller = None, profile_switch = False):
if caller == "":
return False
if not self._daemon.is_running():
res = True
else:
res = self._daemon.stop()
res = self._daemon.stop(profile_switch = profile_switch)
self._timer_store.cancel_all()
return res

Expand All @@ -132,7 +132,7 @@ def reload(self, caller = None):
if caller == "":
return False
if self._daemon.is_running():
stop_ok = self.stop()
stop_ok = self.stop(profile_switch = True)
if not stop_ok:
return False
try:
Expand Down
30 changes: 20 additions & 10 deletions tuned/daemon/daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ def __init__(self, unit_manager, profile_loader, profile_names=None, config=None
self._update_interval = int(consts.CFG_DEF_UPDATE_INTERVAL)
self._dynamic_tuning = consts.CFG_DEF_DYNAMIC_TUNING
self._recommend_command = True
self._rollback = consts.CFG_DEF_ROLLBACK
if config is not None:
self._daemon = config.get_bool(consts.CFG_DAEMON, consts.CFG_DEF_DAEMON)
self._sleep_interval = int(config.get(consts.CFG_SLEEP_INTERVAL, consts.CFG_DEF_SLEEP_INTERVAL))
self._update_interval = int(config.get(consts.CFG_UPDATE_INTERVAL, consts.CFG_DEF_UPDATE_INTERVAL))
self._dynamic_tuning = config.get_bool(consts.CFG_DYNAMIC_TUNING, consts.CFG_DEF_DYNAMIC_TUNING)
self._recommend_command = config.get_bool(consts.CFG_RECOMMEND_COMMAND, consts.CFG_DEF_RECOMMEND_COMMAND)
self._rollback = config.get(consts.CFG_ROLLBACK, consts.CFG_DEF_ROLLBACK)
self._application = application
if self._sleep_interval <= 0:
self._sleep_interval = int(consts.CFG_DEF_SLEEP_INTERVAL)
Expand Down Expand Up @@ -229,21 +231,29 @@ def _thread_code(self):

# if terminating due to profile switch
if self._terminate_profile_switch.is_set():
full_rollback = True
full_rollback = consts.ROLLBACK_FULL
else:
# with systemd it detects system shutdown and in such case it doesn't perform
# full cleanup, if not shutting down it means that TuneD was explicitly
# stopped by user and in such case do full cleanup, without systemd never
# do full cleanup
full_rollback = False
if self._full_rollback_required():
# Assume only soft rollback is needed. Soft rollback means reverting all
# non-persistent tunings applied by a plugin instance. In contrast to full
# rollback, information about what to revert is kept in RAM (volatile
# memory) -- TuneD data structures.
# With systemd TuneD detects system shutdown and in such a case it doesn't
# perform full cleanup. If the system is not shutting down, it means that TuneD
# was explicitly stopped by the user and in such case do the full cleanup. On
# systems without systemd, full cleanup is never performed.
full_rollback = consts.ROLLBACK_SOFT
if not self._full_rollback_required():
log.info("terminating TuneD due to system shutdown / reboot")
elif self._rollback == "not_on_exit":
# no rollback on TuneD exit whatsoever
full_rollback = consts.ROLLBACK_NOT_ON_EXIT
log.info("terminating TuneD and not rolling back any changes due to '%s' option in '%s'" % (consts.CFG_ROLLBACK, consts.GLOBAL_CONFIG_FILE))
else:
if self._daemon:
log.info("terminating TuneD, rolling back all changes")
full_rollback = True
full_rollback = consts.ROLLBACK_FULL
else:
log.info("terminating TuneD in one-shot mode")
else:
log.info("terminating TuneD due to system shutdown / reboot")
if self._daemon:
self._unit_manager.stop_tuning(full_rollback)
self._unit_manager.destroy_all()
Expand Down
11 changes: 7 additions & 4 deletions tuned/plugins/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ def _instance_pre_static(self, instance, enabling):
def _instance_post_static(self, instance, enabling):
pass

def _call_device_script(self, instance, script, op, devices, full_rollback = False):
def _call_device_script(self, instance, script, op, devices, full_rollback = consts.ROLLBACK_SOFT):
if script is None:
return None
if len(devices) == 0:
Expand All @@ -228,7 +228,7 @@ def _call_device_script(self, instance, script, op, devices, full_rollback = Fal
environ = os.environ
environ.update(self._variables.get_env())
arguments = [op]
if full_rollback:
if full_rollback == consts.ROLLBACK_FULL:
arguments.append("full_rollback")
arguments.append(dev)
log.info("calling script '%s' with arguments '%s'" % (script, str(arguments)))
Expand Down Expand Up @@ -298,10 +298,13 @@ def instance_update_tuning(self, instance):
if instance.has_dynamic_tuning and self._global_cfg.get(consts.CFG_DYNAMIC_TUNING, consts.CFG_DEF_DYNAMIC_TUNING):
self._run_for_each_device(instance, self._instance_update_dynamic, instance.processed_devices.copy())

def instance_unapply_tuning(self, instance, full_rollback = False):
def instance_unapply_tuning(self, instance, full_rollback = consts.ROLLBACK_SOFT):
"""
Remove all tunings applied by the plugin instance.
"""
if full_rollback == consts.ROLLBACK_NOT_ON_EXIT:
return

if instance.has_dynamic_tuning and self._global_cfg.get(consts.CFG_DYNAMIC_TUNING, consts.CFG_DEF_DYNAMIC_TUNING):
self._run_for_each_device(instance, self._instance_unapply_dynamic, instance.processed_devices)
if instance.has_static_tuning:
Expand All @@ -325,7 +328,7 @@ def _instance_verify_static(self, instance, ignore_missing, devices):
ret = False
return ret

def _instance_unapply_static(self, instance, full_rollback = False):
def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
self._cleanup_all_device_commands(instance,
instance.processed_devices)
self._cleanup_all_non_device_commands(instance)
Expand Down
4 changes: 3 additions & 1 deletion tuned/plugins/instance/instance.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import tuned.consts as consts

class Instance(object):
"""
"""
Expand Down Expand Up @@ -83,7 +85,7 @@ def verify_tuning(self, ignore_missing):
def update_tuning(self):
self._plugin.instance_update_tuning(self)

def unapply_tuning(self, full_rollback = False):
def unapply_tuning(self, full_rollback = consts.ROLLBACK_SOFT):
self._plugin.instance_unapply_tuning(self, full_rollback)

def destroy(self):
Expand Down
4 changes: 2 additions & 2 deletions tuned/plugins/plugin_bootloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,8 +391,8 @@ def _remove_rpm_ostree_tuning(self):
self._rpm_ostree_kargs(append=self._options_to_dict(deleted), delete=self._options_to_dict(appended))
self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR: "", consts.BOOT_CMDLINE_KARGS_DELETED_VAR: ""})

def _instance_unapply_static(self, instance, full_rollback = False):
if full_rollback and not self._skip_grub_config_val:
def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
if full_rollback == consts.ROLLBACK_FULL and not self._skip_grub_config_val:
if self._rpm_ostree:
log.info("removing rpm-ostree tuning previously added by Tuned")
self._remove_rpm_ostree_tuning()
Expand Down
2 changes: 1 addition & 1 deletion tuned/plugins/plugin_cpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ def _instance_apply_static(self, instance):
self._no_turbo_save = self._getset_intel_pstate_attr(
"no_turbo", new_value)

def _instance_unapply_static(self, instance, full_rollback = False):
def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
super(CPULatencyPlugin, self)._instance_unapply_static(instance, full_rollback)

if instance._first_instance and self._has_intel_pstate:
Expand Down
4 changes: 2 additions & 2 deletions tuned/plugins/plugin_modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ def _instance_verify_static(self, instance, ignore_missing, devices):
ret = False
return ret

def _instance_unapply_static(self, instance, full_rollback = False):
if full_rollback:
def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
if full_rollback == consts.ROLLBACK_FULL:
self._clear_modprobe_file()

def _clear_modprobe_file(self):
Expand Down
2 changes: 1 addition & 1 deletion tuned/plugins/plugin_scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -1003,7 +1003,7 @@ def _cgroup_cleanup_tasks(self):
for cg in self._cgroups:
self._cgroup_cleanup_tasks_one(cg)

def _instance_unapply_static(self, instance, full_rollback = False):
def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
super(SchedulerPlugin, self)._instance_unapply_static(instance, full_rollback)
if self._daemon and instance._runtime_tuning:
instance._terminate.set()
Expand Down
4 changes: 2 additions & 2 deletions tuned/plugins/plugin_script.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,9 @@ def _instance_verify_static(self, instance, ignore_missing, devices):
ret = False
return ret

def _instance_unapply_static(self, instance, full_rollback = False):
def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
args = ["stop"]
if full_rollback:
if full_rollback == consts.ROLLBACK_FULL:
args = args + ["full_rollback"]
self._call_scripts(reversed(instance._scripts), args)
super(ScriptPlugin, self)._instance_unapply_static(instance, full_rollback)
2 changes: 1 addition & 1 deletion tuned/plugins/plugin_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ def _instance_verify_static(self, instance, ignore_missing, devices):
ret = False
return ret

def _instance_unapply_static(self, instance, full_rollback = False):
def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
for name, value in list(instance._services_original.items()):
if value.cfg_file:
self._init_handler.cfg_uninstall(name, value.cfg_file)
Expand Down
2 changes: 1 addition & 1 deletion tuned/plugins/plugin_sysctl.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def _instance_verify_static(self, instance, ignore_missing, devices):
ret = False
return ret

def _instance_unapply_static(self, instance, full_rollback = False):
def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
for option, value in list(instance._sysctl_original.items()):
_write_sysctl(option, value)

Expand Down
3 changes: 2 additions & 1 deletion tuned/plugins/plugin_sysfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import os.path
from .decorators import *
import tuned.logs
import tuned.consts as consts
from subprocess import *
from tuned.utils.commands import commands

Expand Down Expand Up @@ -71,7 +72,7 @@ def _instance_verify_static(self, instance, ignore_missing, devices):
ret = False
return ret

def _instance_unapply_static(self, instance, full_rollback = False):
def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
for key, value in list(instance._sysfs_original.items()):
self._write_sysfs(key, value)

Expand Down
4 changes: 2 additions & 2 deletions tuned/plugins/plugin_systemd.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ def _remove_systemd_tuning(self):
conf = self._add_keyval(conf, consts.SYSTEMD_CPUAFFINITY_VAR, cpu_affinity_saved)
self._write_systemd_system_conf(conf)

def _instance_unapply_static(self, instance, full_rollback = False):
if full_rollback:
def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
if full_rollback == consts.ROLLBACK_FULL:
log.info("removing '%s' systemd tuning previously added by TuneD" % consts.SYSTEMD_CPUAFFINITY_VAR)
self._remove_systemd_tuning()
log.console("you may need to manualy run 'dracut -f' to update the systemd configuration in initrd image")
Expand Down
16 changes: 8 additions & 8 deletions tuned/units/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,15 +161,15 @@ def update_tuning(self):
self._try_call("update_tuning", None,
instance.update_tuning)

# full_rollback is a helper telling plugins whether soft or full roll
# back is needed, e.g. for bootloader plugin we need e.g grub.cfg
# full_rollback is a helper telling plugins whether soft or full
# rollback is needed, e.g. for bootloader plugin we need grub.cfg
# tuning to persist across reboots and restarts of the daemon, so in
# this case the full_rollback is usually set to False, but we also
# need to clean it all up when TuneD is disabled or the profile is
# changed. In this case the full_rollback is set to True. In practice
# it means to remove all temporal or helper files, unpatch third
# party config files, etc.
def stop_tuning(self, full_rollback = False):
# this case the full_rollback is usually set to consts.ROLLBACK_SOFT,
# but we also need to clean it all up when TuneD is disabled or the
# profile is changed. In this case the full_rollback is set to
# consts.ROLLBACK_FULL. In practice it means to remove all temporal
# or helper files, unpatch third party config files, etc.
def stop_tuning(self, full_rollback = consts.ROLLBACK_SOFT):
self._hardware_inventory.stop_processing_events()
for instance in reversed(self._instances):
self._try_call("stop_tuning", None,
Expand Down

0 comments on commit 850368d

Please sign in to comment.