From d1a63c7b5a77c88a81d7001cfaad00d93ae5e81a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20=C5=A0karvada?= Date: Sun, 14 Apr 2024 17:26:07 +0200 Subject: [PATCH] WIP: dump: added new command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dump command dumps active profile. It's good for debugging, because the output is flattened, i.e. it shows the resulting profile after inheritance (profiles merging) is processed. It keeps naming conventions - for tuned-adm it's named 'dump' action, for API it's named 'dump_profile' method. The 'priority' value is not output, but output is ordered according to it. The 'cpuinfo_regex' and 'uname_regex' are not output, but output is rendered according to it. Variables are not expanded. Signed-off-by: Jaroslav Škarvada --- com.redhat.tuned.policy | 10 ++++++++++ tuned-adm.py | 3 +++ tuned/admin/admin.py | 12 ++++++++++++ tuned/admin/dbus_controller.py | 3 +++ tuned/daemon/controller.py | 6 ++++++ tuned/daemon/daemon.py | 24 ++++++++++++++++++++++++ tuned/plugins/base.py | 21 +++++++++++++++++++++ tuned/plugins/instance/instance.py | 3 +++ tuned/units/manager.py | 7 +++++++ 9 files changed, 89 insertions(+) diff --git a/com.redhat.tuned.policy b/com.redhat.tuned.policy index 8bee088b8..cc41fd3ed 100644 --- a/com.redhat.tuned.policy +++ b/com.redhat.tuned.policy @@ -177,6 +177,16 @@ + + Dump TuneD profile + Authentication is required to dump TuneD profile + + yes + yes + yes + + + Verify TuneD profile, ignore missing values Authentication is required to verify TuneD profile diff --git a/tuned-adm.py b/tuned-adm.py index 83ed56984..835640969 100755 --- a/tuned-adm.py +++ b/tuned-adm.py @@ -91,6 +91,9 @@ def check_log_level(value): parser_verify.set_defaults(action="verify_profile") parser_verify.add_argument("--ignore-missing", "-i", action="store_true", help="do not treat missing/non-supported tunings as errors") + parser_dump = subparsers.add_parser("dump", help="dump current profile") + parser_dump.set_defaults(action="dump") + parser_auto_profile = subparsers.add_parser("auto_profile", help="enable automatic profile selection mode, switch to the recommended profile") parser_auto_profile.set_defaults(action="auto_profile") diff --git a/tuned/admin/admin.py b/tuned/admin/admin.py index 8f8682f39..932ed1dd0 100644 --- a/tuned/admin/admin.py +++ b/tuned/admin/admin.py @@ -375,6 +375,18 @@ def _action_verify_profile(self, ignore_missing): print("Not supported in no_daemon mode.") return False + def _action_dbus_dump(self): + (ret, msg) = self._controller.dump() + if ret: + print(msg) + else: + self._error("Unable to dump profile: '%s'" % msg) + return self._controller.exit(ret) + + def _action_dump(self): + print("Not supported in no_daemon mode.") + return False + def _action_dbus_off(self): # 25 seconds default DBus timeout + 5 secs safety margin timeout = 25 + 5 diff --git a/tuned/admin/dbus_controller.py b/tuned/admin/dbus_controller.py index 22c8b8d3b..273c66f2e 100644 --- a/tuned/admin/dbus_controller.py +++ b/tuned/admin/dbus_controller.py @@ -134,6 +134,9 @@ def recommend_profile(self): def verify_profile(self): return self._call("verify_profile") + def dump(self): + return self._call("dump_profile") + def verify_profile_ignore_missing(self): return self._call("verify_profile_ignore_missing") diff --git a/tuned/daemon/controller.py b/tuned/daemon/controller.py index 6a59a1d86..b43810989 100644 --- a/tuned/daemon/controller.py +++ b/tuned/daemon/controller.py @@ -279,6 +279,12 @@ def verify_profile_ignore_missing(self, caller = None): return False return self._daemon.verify_profile(ignore_missing = True) + @exports.export("", "(bs)") + def dump_profile(self, caller = None): + if caller == "": + return False + return self._daemon.dump_profile() + @exports.export("", "a{sa{ss}}") def get_all_plugins(self, caller = None): """Return dictionary with accesible plugins diff --git a/tuned/daemon/daemon.py b/tuned/daemon/daemon.py index 81582d05d..cc3e2a23b 100644 --- a/tuned/daemon/daemon.py +++ b/tuned/daemon/daemon.py @@ -360,6 +360,30 @@ def verify_profile(self, ignore_missing): self._not_used.set() return ret + def dump_profile(self): + if not self.is_running(): + s = "TuneD is not running" + log.error(s) + return (False, s) + + if self._profile is None: + s = "no profile is set" + log.error(s) + return (False, s) + + if not self._profile_applied.is_set(): + s = "profile is not applied" + log.error(s) + return (False, s) + + # using daemon, the main loop mustn't exit before our completion + self._not_used.clear() + log.info("dumping profile(s): %s" % self._profile.name) + s = self._unit_manager.dump_tuning() + # main loop is allowed to exit + self._not_used.set() + return (True, s) + # profile_switch is helper telling plugins whether the stop is due to profile switch def stop(self, profile_switch = False): if not self.is_running(): diff --git a/tuned/plugins/base.py b/tuned/plugins/base.py index 8eaf48ada..539bc2d8d 100644 --- a/tuned/plugins/base.py +++ b/tuned/plugins/base.py @@ -290,6 +290,27 @@ def instance_verify_tuning(self, instance, ignore_missing): else: return None + def instance_dump_tuning(self, instance): + """ + Dump tuning if the plugin instance is active. + """ + if not instance.active: + return "" + + s = "[%s]\n" % instance.name + s += "type = %s\n" % self.name + if instance._devices_expression: + s += "devices = %s\n" % instance._devices_expression + if instance._devices_udev_regex: + s += "devices_udev_regex = %s\n" % instance._devices_udev_regex + if instance._script_pre: + s += "script_pre = %s\n" % instance._script_pre + if instance._script_post: + s += "script_post = %s\n" % instance._script_post + for option, val in instance._options.items(): + s += "%s = %s\n" % (option, val) + return s + def instance_update_tuning(self, instance): """ Apply dynamic tuning if the plugin instance is active. diff --git a/tuned/plugins/instance/instance.py b/tuned/plugins/instance/instance.py index 1e286729d..65f1722f8 100644 --- a/tuned/plugins/instance/instance.py +++ b/tuned/plugins/instance/instance.py @@ -82,6 +82,9 @@ def apply_tuning(self): def verify_tuning(self, ignore_missing): return self._plugin.instance_verify_tuning(self, ignore_missing) + def dump_tuning(self): + return self._plugin.instance_dump_tuning(self) + def update_tuning(self): self._plugin.instance_update_tuning(self) diff --git a/tuned/units/manager.py b/tuned/units/manager.py index 2612c1c4e..6225f509c 100644 --- a/tuned/units/manager.py +++ b/tuned/units/manager.py @@ -156,6 +156,13 @@ def verify_tuning(self, ignore_missing): ret = False return ret + def dump_tuning(self): + s = "" + for instance in self._instances: + s += self._try_call("dump_tuning", None, + instance.dump_tuning) + "\n" + return s[:-1] + def update_tuning(self): for instance in self._instances: self._try_call("update_tuning", None,