1
0
Fork 0

Implement instance priority

Resolves: rhbz#1246172

Allow specifying order in which individual plugin instances are to be
executed.

Each instance can be given the 'instance_priority' option
in the profile configuration. The value must be an integer (it can be
negative). If no priority is specified, it is inherited from the parent
profile, or set to the default instance priority, if no parent profile
specifies the priority for that instance.

The default instance priority is by default zero, but it can be set to
a different value using the 'default_instance_priority' option in the
global configuration file.

Creating plugin instances, assigning devices to instances, initializing
instances, applying, updating and verifying tuning are all done in order
from lowest numerical instance priority to highest. Unapplying tuning and
destroying instances is done in reversed order.

Signed-off-by: Ondřej Lysoněk <olysonek@redhat.com>
This commit is contained in:
Ondřej Lysoněk 2017-02-17 14:24:53 +01:00
parent 82546e3027
commit 363d74815a
6 changed files with 54 additions and 41 deletions

View file

@ -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

View file

@ -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"

View file

@ -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()

View file

@ -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():

View file

@ -15,6 +15,10 @@ class Instance(object):
# properties
@property
def plugin(self):
return self._plugin
@property
def name(self):
return self._name

View file

@ -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)