diff --git a/tuned-main.conf b/tuned-main.conf index ceaf3e5..22cd64b 100644 --- a/tuned-main.conf +++ b/tuned-main.conf @@ -26,3 +26,6 @@ recommend_command = 1 # If enabled these sysctls will be re-appliead after Tuned sysctls are # applied, i.e. Tuned sysctls will not override system sysctls. reapply_sysctl = 1 + +# Default priority assigned to instances +default_instance_priority = 0 diff --git a/tuned/consts.py b/tuned/consts.py index 8beeb9a..2d06765 100644 --- a/tuned/consts.py +++ b/tuned/consts.py @@ -56,6 +56,7 @@ CFG_SLEEP_INTERVAL = "sleep_interval" CFG_UPDATE_INTERVAL = "update_interval" CFG_RECOMMEND_COMMAND = "recommend_command" CFG_REAPPLY_SYSCTL = "reapply_sysctl" +CFG_DEFAULT_INSTANCE_PRIORITY = "default_instance_priority" # no_daemon mode CFG_DEF_DAEMON = True @@ -69,6 +70,8 @@ CFG_DEF_UPDATE_INTERVAL = 10 CFG_DEF_RECOMMEND_COMMAND = True # reapply system sysctl CFG_DEF_REAPPLY_SYSCTL = True +# default instance priority +CFG_DEF_DEFAULT_INSTANCE_PRIORITY = 0 PATH_CPU_DMA_LATENCY = "/dev/cpu_dma_latency" diff --git a/tuned/daemon/application.py b/tuned/daemon/application.py index a7708ae..2877709 100644 --- a/tuned/daemon/application.py +++ b/tuned/daemon/application.py @@ -34,7 +34,8 @@ class Application(object): log.info("dynamic tuning is globally disabled") plugins_repository = plugins.Repository(monitors_repository, storage_factory, hardware_inventory, device_matcher, plugin_instance_factory, self.config, self.variables) - unit_manager = units.Manager(plugins_repository, monitors_repository) + def_instance_priority = int(self.config.get(consts.CFG_DEFAULT_INSTANCE_PRIORITY, consts.CFG_DEF_DEFAULT_INSTANCE_PRIORITY)) + unit_manager = units.Manager(plugins_repository, monitors_repository, def_instance_priority) profile_factory = profiles.Factory() profile_merger = profiles.Merger() diff --git a/tuned/plugins/base.py b/tuned/plugins/base.py index b07f0a4..7079d93 100644 --- a/tuned/plugins/base.py +++ b/tuned/plugins/base.py @@ -102,11 +102,10 @@ class Plugin(object): self._destroy_instance(instance) del self._instances[instance.name] - def initialize_instances(self): - """Initialize all created instances.""" - for (instance_name, instance) in self._instances.items(): - log.debug("initializing instance %s (%s)" % (instance_name, self.name)) - self._instance_init(instance) + def initialize_instance(self, instance): + """Initialize an instance.""" + log.debug("initializing instance %s (%s)" % (instance.name, self.name)) + self._instance_init(instance) def destroy_instances(self): """Destroy all instances.""" @@ -140,21 +139,20 @@ class Plugin(object): def _get_matching_devices(self, instance, devices): return set(self._device_matcher.match_list(instance.devices_expression, devices)) - def assign_free_devices(self): + def assign_free_devices(self, instance): if not self._devices_supported(): return - log.debug("assigning devices to all instances") - for instance_name, instance in reversed(self._instances.items()): - to_assign = self._get_matching_devices(instance, self._free_devices) - instance.active = len(to_assign) > 0 - if not instance.active: - log.warn("instance %s: no matching devices available" % instance_name) - else: - log.info("instance %s: assigning devices %s" % (instance_name, ", ".join(to_assign))) - instance.devices.update(to_assign) # cannot use |= - self._assigned_devices |= to_assign - self._free_devices -= to_assign + log.debug("assigning devices to instance %s" % instance.name) + to_assign = self._get_matching_devices(instance, self._free_devices) + instance.active = len(to_assign) > 0 + if not instance.active: + log.warn("instance %s: no matching devices available" % instance.name) + else: + log.info("instance %s: assigning devices %s" % (instance.name, ", ".join(to_assign))) + instance.devices.update(to_assign) # cannot use |= + self._assigned_devices |= to_assign + self._free_devices -= to_assign def release_devices(self, instance): if not self._devices_supported(): diff --git a/tuned/plugins/instance/instance.py b/tuned/plugins/instance/instance.py index d012cb5..be0d6ba 100644 --- a/tuned/plugins/instance/instance.py +++ b/tuned/plugins/instance/instance.py @@ -15,6 +15,10 @@ class Instance(object): # properties + @property + def plugin(self): + return self._plugin + @property def name(self): return self._name diff --git a/tuned/units/manager.py b/tuned/units/manager.py index 1097063..2dd5600 100644 --- a/tuned/units/manager.py +++ b/tuned/units/manager.py @@ -1,3 +1,4 @@ +import collections import tuned.exceptions import tuned.logs import tuned.plugins.exceptions @@ -11,10 +12,11 @@ class Manager(object): Manager creates plugin instances and keeps a track of them. """ - def __init__(self, plugins_repository, monitors_repository): + def __init__(self, plugins_repository, monitors_repository, def_instance_priority): super(self.__class__, self).__init__() self._plugins_repository = plugins_repository self._monitors_repository = monitors_repository + self._def_instance_priority = def_instance_priority self._instances = [] self._plugins = [] @@ -27,22 +29,25 @@ class Manager(object): return self._instances def create(self, instances_config): - - # group instances by plugin - - instances_by_plugin = {} + instance_info_list = [] for instance_name, instance_info in instances_config.items(): if not instance_info.enabled: log.debug("skipping disabled instance '%s'" % instance_name) continue - instances_by_plugin.setdefault(instance_info.type, []) - instances_by_plugin[instance_info.type].append(instance_info) + instance_info.options.setdefault("instance_priority", self._def_instance_priority) + instance_info.options["instance_priority"] = int(instance_info.options["instance_priority"]) + instance_info_list.append(instance_info) - # create all plugin instances at once + instance_info_list.sort(key=lambda x: x.options["instance_priority"]) + plugins_by_name = collections.OrderedDict() + for instance_info in instance_info_list: + instance_info.options.pop("instance_priority") + plugins_by_name[instance_info.type] = None - for plugin_name, instances_info in instances_by_plugin.items(): + for plugin_name, none in plugins_by_name.items(): try: plugin = self._plugins_repository.create(plugin_name) + plugins_by_name[plugin_name] = plugin self._plugins.append(plugin) except tuned.plugins.exceptions.NotSupportedPluginException: log.info("skipping plugin '%s', not supported on your system" % plugin_name) @@ -52,21 +57,20 @@ class Manager(object): log.exception(e) continue - created_instances = [] - for instance_info in instances_info: - log.debug("creating '%s' (%s)" % (instance_info.name, instance_info.type)) - new_instance = plugin.create_instance(instance_info.name, instance_info.devices, instance_info.options) - created_instances.append(new_instance) - - plugin.assign_free_devices() - plugin.initialize_instances() - - self._instances.extend(created_instances) + for instance_info in instance_info_list: + plugin = plugins_by_name[instance_info.type] + if plugin is None: + continue + log.debug("creating '%s' (%s)" % (instance_info.name, instance_info.type)) + new_instance = plugin.create_instance(instance_info.name, instance_info.devices, instance_info.options) + plugin.assign_free_devices(new_instance) + plugin.initialize_instance(new_instance) + self._instances.append(new_instance) def destroy_all(self): - for plugin in self._plugins: - log.debug("cleaning plugin '%s'" % plugin.name) - plugin.cleanup() + for instance in self._instances: + log.debug("destroying instance %s" % instance.name) + instance.plugin.destroy_instance(instance) del self._plugins[:] del self._instances[:] @@ -93,5 +97,5 @@ class Manager(object): # profile_switch is helper telling plugins whether the stop is due to profile switch def stop_tuning(self, profile_switch = False): - for instance in self._instances: + for instance in reversed(self._instances): instance.unapply_tuning(profile_switch)