From db6b880bb615550b7afb9e7359c3a9b1a0a90b89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavol=20=C5=BD=C3=A1=C4=8Dik?= Date: Mon, 13 Nov 2023 19:25:28 +0100 Subject: [PATCH] Add API functions to retrieve active instances and their devices Resolves: RHEL-15137 Appropriate commands are added to tuned-adm as well. `get_instances`: Retrieves a list of active instances of a given plugin or all active instances. `instance_get_devices`: Retrieves a list of devices assigned to a given instance. --- com.redhat.tuned.policy | 20 ++++++++++++++++ man/tuned-adm.8 | 10 +++++++- tuned-adm.py | 8 +++++++ tuned/admin/admin.py | 26 ++++++++++++++++++++ tuned/admin/dbus_controller.py | 6 +++++ tuned/daemon/controller.py | 44 ++++++++++++++++++++++++++++++++++ 6 files changed, 113 insertions(+), 1 deletion(-) diff --git a/com.redhat.tuned.policy b/com.redhat.tuned.policy index 824ae0c..8bee088 100644 --- a/com.redhat.tuned.policy +++ b/com.redhat.tuned.policy @@ -227,4 +227,24 @@ + + Get list of active TuneD plugin instances + Authentication is required to get list of active TuneD plugin instances + + yes + yes + yes + + + + + Get list of devices assigned to the instance + Authentication is required to get list of devices assigned to the instance + + yes + yes + yes + + + diff --git a/man/tuned-adm.8 b/man/tuned-adm.8 index 4620f3f..f29966d 100644 --- a/man/tuned-adm.8 +++ b/man/tuned-adm.8 @@ -24,7 +24,7 @@ tuned\-adm - command line tool for switching between different tuning profiles .SH SYNOPSIS .B tuned\-adm -.RB [ list " | " active " | " "profile \fI[profile]\fP..." " | " "profile_info \fI[profile]\fP..." " | " off " | " auto_profile " | " profile_mode " | " "verify \fI[\-i | \-\-ignore\-missing]\fP" " | " recommend " | " "instance_acquire_devices \fIdevices\fP \fIinstance\fP" ] +.RB [ list " | " active " | " "profile \fI[profile]\fP..." " | " "profile_info \fI[profile]\fP..." " | " off " | " auto_profile " | " profile_mode " | " "verify \fI[\-i | \-\-ignore\-missing]\fP" " | " recommend " | " "instance_acquire_devices \fIdevices\fP \fIinstance\fP" " | " "get_instances \fI[plugin]\fP" " | " "instance_get_devices \fIinstance\fP" ] .SH DESCRIPTION This command line utility allows you to switch between user definable tuning @@ -119,6 +119,14 @@ The devices are specified using a comma-separated list. When moving a set of CPU it is possible to use the cpulist syntax by including the 'cpulist:' prefix. For instance, 'cpulist:0,2-4' will move the devices cpu0, cpu1, cpu2, and cpu4. +.TP +.B "get_instances \fI[plugin]\fP" +List active instances of a given plugin or all active instances if no plugin is specified. + +.TP +.B "instance_get_devices \fIinstance\fP" +List devices currently assigned to a given instance. + .TP .B off Unload tunings. diff --git a/tuned-adm.py b/tuned-adm.py index b512902..712e7da 100755 --- a/tuned-adm.py +++ b/tuned-adm.py @@ -102,6 +102,14 @@ if __name__ == "__main__": parser_instance_acquire_devices.add_argument("devices", metavar="devices", type=str, help="comma-separated list of device names; may use the cpulist syntax if prefixed with 'cpulist:'") parser_instance_acquire_devices.add_argument("instance", metavar="instance", type=str, help="name of the plugin instance which should acquire the devices") + parser_get_instances = subparsers.add_parser("get_instances", help="list active instances of a given plugin or all active instances if no plugin is specified") + parser_get_instances.set_defaults(action="get_instances") + parser_get_instances.add_argument("plugin_name", metavar="plugin_name", type=str, nargs="?", default="", help="name of the plugin to restrict the list of instances to") + + parser_instance_get_devices = subparsers.add_parser("instance_get_devices", help="list devices assigned to a given instance") + parser_instance_get_devices.set_defaults(action="instance_get_devices") + parser_instance_get_devices.add_argument("instance", metavar="instance", type=str, help="name of the plugin instance") + args = parser.parse_args(sys.argv[1:]) options = vars(args) diff --git a/tuned/admin/admin.py b/tuned/admin/admin.py index d868f1a..b9ef94b 100644 --- a/tuned/admin/admin.py +++ b/tuned/admin/admin.py @@ -449,3 +449,29 @@ class Admin(object): def _action_instance_acquire_devices(self, devices, instance): print("Not supported in no_daemon mode.") return False + + def _action_dbus_get_instances(self, plugin_name): + (ret, msg, pairs) = self._controller.get_instances(plugin_name) + if not ret: + self._error("Unable to list instances: %s" % msg) + return self._controller.exit(False) + for instance, plugin in pairs: + print("%s (%s)" % (instance, plugin)) + return self._controller.exit(True) + + def _action_get_instances(self, plugin_name): + print("Not supported in no_daemon mode.") + return False + + def _action_dbus_instance_get_devices(self, instance): + (ret, msg, devices) = self._controller.instance_get_devices(instance) + if not ret: + self._error("Unable to list devices: %s" % msg) + return self._controller.exit(False) + for device in devices: + print(device) + return self._controller.exit(True) + + def _action_instance_get_devices(self, instance): + print("Not supported in no_daemon mode.") + return False diff --git a/tuned/admin/dbus_controller.py b/tuned/admin/dbus_controller.py index e865dd4..22c8b8d 100644 --- a/tuned/admin/dbus_controller.py +++ b/tuned/admin/dbus_controller.py @@ -166,6 +166,12 @@ class DBusController(object): def instance_acquire_devices(self, devices, instance): return self._call("instance_acquire_devices", devices, instance) + def get_instances(self, plugin_name): + return self._call("get_instances", plugin_name) + + def instance_get_devices(self, instance): + return self._call("instance_get_devices", instance) + def exit(self, ret): self.set_action(None) self._ret = ret diff --git a/tuned/daemon/controller.py b/tuned/daemon/controller.py index 1292a8a..6a59a1d 100644 --- a/tuned/daemon/controller.py +++ b/tuned/daemon/controller.py @@ -373,3 +373,47 @@ class Controller(tuned.exports.interfaces.ExportableInterface): log.info(rets) return (False, rets) return (True, "OK") + + @exports.export("s", "(bsa(ss))") + def get_instances(self, plugin_name, caller = None): + """Return a list of active instances of a plugin or all active instances + + Parameters: + plugin_name -- name of the plugin or an empty string + + Return: + bool -- True on success + string -- error message or "OK" + list of string pairs -- [(instance_name, plugin_name)] + """ + if caller == "": + return (False, "Unauthorized", []) + if plugin_name != "" and plugin_name not in self.get_all_plugins().keys(): + rets = "Plugin '%s' does not exist" % plugin_name + log.error(rets) + return (False, rets, []) + instances = filter(lambda instance: instance.active, self._daemon._unit_manager.instances) + if plugin_name != "": + instances = filter(lambda instance: instance.plugin.name == plugin_name, instances) + return (True, "OK", list(map(lambda instance: (instance.name, instance.plugin.name), instances))) + + @exports.export("s", "(bsas)") + def instance_get_devices(self, instance_name, caller = None): + """Return a list of devices assigned to an instance + + Parameters: + instance_name -- name of the instance + + Return: + bool -- True on success + string -- error message or "OK" + list of strings -- device names + """ + if caller == "": + return (False, "Unauthorized", []) + for instance in self._daemon._unit_manager.instances: + if instance.name == instance_name: + return (True, "OK", sorted(list(instance.processed_devices))) + rets = "Instance '%s' not found" % instance_name + log.error(rets) + return (False, rets, [])