From bc55810995077b26b77d4775c324c0ca14fabb33 Mon Sep 17 00:00:00 2001 From: Jan Vcelak Date: Fri, 26 Oct 2012 17:58:03 +0200 Subject: [PATCH] units.manager: devices claiming priority, creating units --- tuned/application.py | 4 ++- tuned/daemon.py | 4 +-- tuned/plugins/base.py | 4 +++ tuned/profiles/unit.py | 7 +++- tuned/units/__init__.py | 3 ++ tuned/units/factory.py | 5 +++ tuned/units/manager.py | 77 ++++++++++++++++++++++++++++++++--------- tuned/units/unit.py | 36 +++++++------------ 8 files changed, 95 insertions(+), 45 deletions(-) create mode 100644 tuned/units/factory.py diff --git a/tuned/application.py b/tuned/application.py index f1bd7c9..100e433 100644 --- a/tuned/application.py +++ b/tuned/application.py @@ -38,9 +38,11 @@ class Application(object): storage_provider = storage.PickleProvider() storage_factory = storage.Factory(storage_provider) + unit_factory = units.Factory() + device_matcher = units.DeviceMatcher() monitors_repository = monitors.Repository() plugins_repository = plugins.Repository(storage_factory, monitors_repository) - unit_manager = units.Manager(plugins_repository, monitors_repository) + unit_manager = units.Manager(plugins_repository, monitors_repository, unit_factory, device_matcher) profile_factory = profiles.Factory() profile_merger = profiles.Merger() diff --git a/tuned/daemon.py b/tuned/daemon.py index 734964a..f32add7 100644 --- a/tuned/daemon.py +++ b/tuned/daemon.py @@ -45,9 +45,7 @@ class Daemon(object): if self._profile is None: raise Exception("Cannot start the daemon without setting a profile.") - for unit_info in self._profile.units: - self._unit_manager.create(unit_info.name, unit_info.plugin, unit_info.options) - + self._unit_manager.create(self._profile.units) self.save_active_profile() self._unit_manager.plugins_repository.do_static_tuning() diff --git a/tuned/plugins/base.py b/tuned/plugins/base.py index 31c9773..6c2eb33 100644 --- a/tuned/plugins/base.py +++ b/tuned/plugins/base.py @@ -60,6 +60,10 @@ class Plugin(object): def dynamic_tuning(self): return self._dynamic_tuning + @property + def devices(self): + return self._devices + def _autoregister_commands(self): """ Register all commands marked using @command_set and @command_get decorators. diff --git a/tuned/profiles/unit.py b/tuned/profiles/unit.py index 6d00ba6..df814d3 100644 --- a/tuned/profiles/unit.py +++ b/tuned/profiles/unit.py @@ -3,13 +3,14 @@ class Unit(object): Unit description. """ - __slots__ = [ "_name", "_type", "_enabled", "_replace", "_options" ] + __slots__ = [ "_name", "_type", "_enabled", "_replace", "_devices", "_options" ] def __init__(self, name, config): self._name = name self._type = config.pop("type", self._name) self._enabled = config.pop("enabled", True) in [True, "true", 1] self._replace = config.pop("replace", False) in [True, "true", 1] + self._devices = config.pop("devices", "*") self._options = dict(config) @property @@ -32,6 +33,10 @@ class Unit(object): def replace(self): return self._replace + @property + def devices(self): + return self._devices + @property def options(self): return self._options diff --git a/tuned/units/__init__.py b/tuned/units/__init__.py index fa54824..99df76b 100644 --- a/tuned/units/__init__.py +++ b/tuned/units/__init__.py @@ -1 +1,4 @@ from manager import * +from device_matcher import * +from factory import * +from unit import * diff --git a/tuned/units/factory.py b/tuned/units/factory.py new file mode 100644 index 0000000..b251866 --- /dev/null +++ b/tuned/units/factory.py @@ -0,0 +1,5 @@ +import tuned.units.unit + +class Factory(object): + def create(self, name, type, plugin): + return tuned.units.unit.Unit(name, type, plugin) diff --git a/tuned/units/manager.py b/tuned/units/manager.py index 59178e9..d3d36eb 100644 --- a/tuned/units/manager.py +++ b/tuned/units/manager.py @@ -12,17 +12,19 @@ class Manager(object): Manager instantiates Unit objects, and keeps track of them. """ - __slots__ = ["_units", "_plugins_repository", "_monitors_repository"] + __slots__ = ["_units", "_plugins_repository", "_monitors_repository", "_unit_factory", "_device_matcher"] - def __init__(self, plugins_repository, monitors_repository): + def __init__(self, plugins_repository, monitors_repository, unit_factory, device_matcher): super(self.__class__, self).__init__() self._units = set() - self._plugins_repository = plugins_repository self._monitors_repository = monitors_repository + self._plugins_repository = plugins_repository + self._unit_factory = unit_factory + self._device_matcher = device_matcher @property def units(self): - return self._units.copy() + return self._units @property def plugins_repository(self): @@ -32,22 +34,65 @@ class Manager(object): def monitors_repository(self): return self._monitors_repository - def create(self, name, plugin_name, config): - log.info("creating unit '%s'" % name) - try: - new_unit = tuned.units.unit.Unit(self._plugins_repository, self._monitors_repository, name, plugin_name, config) - self._units.add(new_unit) - return new_unit - except tuned.exceptions.TunedException as e: - e.log() - log.error("unable to create unit '%s'" % name) + def create(self, units): + # reverse order, newer units have priority to claim a device + for unit_info in reversed(units): + if not unit_info.enabled: + log.debug("skipping disabled unit '%s'" % unit_info.name) + continue + + if not self._plugins_repository.is_supported(unit_info.type): + log.info("skipping unit '%s', plugin not supported on your system" % unit_info.type) + continue + + devices = self._possible_devices(unit_info) + if devices is None: + continue + + log.info("creating unit '%s' (devices: %s)" % (unit_info.name, ", ".join(devices))) + try: + self._create_unit(unit_info, devices) + except tuned.exceptions.TunedException as e: + log.error("unable to create unit '%s' (trace follows)" % unit_info.name) + e.log() + except Exception as E: + log.error("unable to create unit '%s' (%s)" % (unit_info.name, str(e))) + + def _possible_devices(self, unit_info): + tunable_devices = self._plugins_repository.tunable_devices(unit_info.type) + if len(tunable_devices) == 0: + log.info("skipping unit '%s', no devices available" % unit_info.name) + return None + + available_devices = [dev for dev in tunable_devices if dev not in self._seized_devices(unit_info.type)] + if len(available_devices) == 0: + log.info("skipping unit '%s', all devices are already claimed by another unit" % unit_info.name) + return None + + devices = self._device_matcher.match_list(unit_info.devices, available_devices) + if len(devices) == 0: + log.info("skipping unit '%s', no matching devices available" % unit_info.name) + return None + + return devices + + def _seized_devices(self, type): + devices = [] + for unit in self._units: + if unit.type == type: + devices.extend(unit.devices) + return set(devices) + + def _create_unit(self, unit_info, devices): + plugin = self._plugins_repository.create(unit_info.type, devices, unit_info.options) + unit = self._unit_factory.create(unit_info.name, unit_info.type, plugin) + self._units.add(unit) def delete(self, unit): - assert type(unit) is tuned.units.unit.Unit - unit.clean() + self._plugins_repository.delete(unit.plugin) self._units.delete(unit) def delete_all(self): for unit in self._units: - unit.clean() + self._plugins_repository.delete(unit.plugin) self._units.clear() diff --git a/tuned/units/unit.py b/tuned/units/unit.py index cd49927..0142289 100644 --- a/tuned/units/unit.py +++ b/tuned/units/unit.py @@ -9,37 +9,25 @@ class Unit(object): device. """ - __slots__ = ["_name", "_plugin", "_plugin_repository", "_monitor_repository"] + __slots__ = ["_name", "_type", "_plugin"] - def __init__(self, plugin_repository, monitor_repository, name, plugin_name, config): - self._plugin_repository = plugin_repository - self._monitor_repository = monitor_repository + def __init__(self, name, type, plugin): self._name = name - - (devices, options) = self._get_plugin_params(config) - self._plugin = self._plugin_repository.create(plugin_name, devices, options) + self._type = type + self._plugin = plugin @property def name(self): return self._name + @property + def type(self): + return self._type + + @property + def devices(self): + return self._plugin.devices + @property def plugin(self): return self._plugin - - def clean(self): - self._plugin_repository.delete(self._plugin) - self._plugin = None - - def _get_plugin_params(self, config): - if config is None: - return (None, {}) - - devices = None - if "devices" in config: - devices = config["devices"] - if devices and len(devices) == 0: - devices = None - del(config["devices"]) - - return (devices, config)