def set_profile(self, profile_name, save_instantly=False): if self.is_running(): raise TunedException( self._notify_profile_changed( profile_name, False, "Cannot set profile while the daemon is running.")) if profile_name == "" or profile_name is None: self._profile = None elif profile_name not in self.profile_loader.profile_locator.get_known_names( ): raise TunedException( self._notify_profile_changed( profile_name, False, "Requested profile '%s' doesn't exist." % profile_name)) else: try: self._profile = self._profile_loader.load(profile_name) except InvalidProfileException as e: raise TunedException( self._notify_profile_changed( profile_name, False, "Cannot load profile '%s': %s" % (profile_name, e))) if save_instantly: if profile_name is None: profile_name = "" self._save_active_profile(profile_name)
def get_active_profile(self): profile_name = "" mode = "" try: with open(consts.ACTIVE_PROFILE_FILE, "r") as f: profile_name = f.read().strip() except IOError as e: if e.errno != errno.ENOENT: raise TunedException("Failed to read active profile: %s" % e) except (OSError, EOFError) as e: raise TunedException("Failed to read active profile: %s" % e) try: with open(consts.PROFILE_MODE_FILE, "r") as f: mode = f.read().strip() if mode not in ["", consts.ACTIVE_PROFILE_AUTO, consts.ACTIVE_PROFILE_MANUAL]: raise TunedException("Invalid value in file %s." % consts.PROFILE_MODE_FILE) except IOError as e: if e.errno != errno.ENOENT: raise TunedException("Failed to read profile mode: %s" % e) except (OSError, EOFError) as e: raise TunedException("Failed to read profile mode: %s" % e) if mode == "": manual = None else: manual = mode == consts.ACTIVE_PROFILE_MANUAL if profile_name == "": profile_name = None return (profile_name, manual)
def _load_global_config(self, file_name=consts.GLOBAL_CONFIG_FILE): """ Loads global configuration file. """ try: config_parser = ConfigParser(delimiters=('='), inline_comment_prefixes=('#')) config_parser.optionxform = str with open(file_name) as f: config_parser.read_string("[" + consts.MAGIC_HEADER_NAME + "]\n" + f.read(), file_name) config, functions = GlobalConfig.get_global_config_spec() for option in config_parser.options(consts.MAGIC_HEADER_NAME): if option in config: try: func = getattr(config_parser, functions[option]) config[option] = func(consts.MAGIC_HEADER_NAME, option) except Error: raise TunedException("Global TuneD configuration file '%s' is not valid." % file_name) else: config[option] = config_parser.get(consts.MAGIC_HEADER_NAME, option, raw=True) except IOError as e: raise TunedException("Global TuneD configuration file '%s' not found." % file_name) except Error as e: raise TunedException("Error parsing global TuneD configuration file '%s'." % file_name) return config
def _load_global_config(self, file_name=consts.GLOBAL_CONFIG_FILE): """ Loads global configuration file. """ try: config = ConfigObj.ConfigObj(file_name, configspec=global_config_spec, raise_errors=True, file_error=True, list_values=False, interpolation=False) except IOError as e: raise TunedException( "Global tuned configuration file '%s' not found." % file_name) except ConfigObj.ConfigObjError as e: raise TunedException( "Error parsing global tuned configuration file '%s'." % file_name) vdt = Validator() if not config.validate(vdt, copy=True): raise TunedException( "Global tuned configuration file '%s' is not valid." % file_name) return config
def _load_profiles(self, profile_names, manual): profile_names = profile_names or "" profile_list = profile_names.split() if self._post_loaded_profile: log.info("Using post-loaded profile '%s'" % self._post_loaded_profile) profile_list = profile_list + [self._post_loaded_profile] for profile in profile_list: if profile not in self.profile_loader.profile_locator.get_known_names( ): errstr = "Requested profile '%s' doesn't exist." % profile self._notify_profile_changed(profile_names, False, errstr) raise TunedException(errstr) try: if profile_list: self._profile = self._profile_loader.load(profile_list) else: self._profile = None self._manual = manual self._active_profiles = profile_names.split() except InvalidProfileException as e: errstr = "Cannot load profile(s) '%s': %s" % ( " ".join(profile_list), e) self._notify_profile_changed(profile_names, False, errstr) raise TunedException(errstr)
def set_profile(self, profile_names, manual, save_instantly=False): if self.is_running(): raise TunedException( self._notify_profile_changed( profile_names, False, "Cannot set profile while the daemon is running.")) if profile_names == "" or profile_names is None: self._profile = None self._manual = manual else: profile_list = profile_names.split() for profile in profile_list: if profile not in self.profile_loader.profile_locator.get_known_names( ): raise TunedException(self._notify_profile_changed(\ profile_names, False,\ "Requested profile '%s' doesn't exist." % profile)) try: self._profile = self._profile_loader.load(profile_names) self._manual = manual except InvalidProfileException as e: raise TunedException( self._notify_profile_changed( profile_names, False, "Cannot load profile(s) '%s': %s" % (profile_names, e))) if save_instantly: if profile_names is None: profile_names = "" self._save_active_profile(profile_names, manual)
def _daemonize_parent(self, parent_in_fd, child_out_fd): """ Wait till the child signalizes that the initialization is complete by writing some uninteresting data into the pipe. """ os.close(child_out_fd) (read_ready, drop, drop) = select.select([parent_in_fd], [], [], consts.DAEMONIZE_PARENT_TIMEOUT) if len(read_ready) != 1: os.close(parent_in_fd) raise TunedException( "Cannot daemonize, timeout when waiting for the child process." ) response = os.read(parent_in_fd, 8) os.close(parent_in_fd) if len(response) == 0: raise TunedException( "Cannot daemonize, no response from child process received.") if response != ("%c" % True): raise TunedException( "Cannot daemonize, child process reports failure.")
def save_active_profile(self, profile_name, manual): try: with open(consts.ACTIVE_PROFILE_FILE, "w") as f: if profile_name is not None: f.write(profile_name + "\n") except (OSError,IOError) as e: raise TunedException("Failed to save active profile: %s" % e.strerror) try: with open(consts.PROFILE_MODE_FILE, "w") as f: mode = consts.ACTIVE_PROFILE_MANUAL if manual else consts.ACTIVE_PROFILE_AUTO f.write(mode + "\n") except (OSError,IOError) as e: raise TunedException("Failed to save profile mode: %s" % e.strerror)
def get_post_loaded_profile(self): profile_name = "" try: with open(consts.POST_LOADED_PROFILE_FILE, "r") as f: profile_name = f.read().strip() except IOError as e: if e.errno != errno.ENOENT: raise TunedException("Failed to read the active post-loaded profile: %s" % e) except (OSError, EOFError) as e: raise TunedException("Failed to read the active post-loaded profile: %s" % e) if profile_name == "": profile_name = None return profile_name
def load_config(self, file_name = consts.GLOBAL_CONFIG_FILE): """ Loads global configuration file. """ log.debug("reading and parsing global configuration file '%s'" % consts.GLOBAL_CONFIG_FILE) try: self._cfg = ConfigObj(file_name, configspec = self.global_config_spec, raise_errors = True, \ file_error = True, list_values = False, interpolation = False) except IOError as e: raise TunedException("Global tuned configuration file '%s' not found." % file_name) except ConfigObjError as e: raise TunedException("Error parsing global tuned configuration file '%s'." % file_name) vdt = Validator() if (not self._cfg.validate(vdt, copy=True)): raise TunedException("Global tuned configuration file '%s' is not valid." % file_name)
def _thread_code(self): if self._profile is None: raise TunedException( "Cannot start the daemon without setting a profile.") self._unit_manager.create(self._profile.units) self._save_active_profile(self._profile.name) self._unit_manager.start_tuning() self._profile_applied.set() log.info("static tuning from profile '%s' applied" % self._profile.name) self._notify_profile_changed(self._profile.name, True, "OK") if self._daemon: # In python 2 interpreter with applied patch for rhbz#917709 we need to periodically # poll, otherwise the python will not have chance to update events / locks (due to GIL) # and e.g. DBus control will not work. The polling interval of 1 seconds (which is # the default) is still much better than 50 ms polling with unpatched interpreter. # For more details see tuned rhbz#917587. _sleep_cnt = self._sleep_cycles while not self._cmd.wait(self._terminate, self._sleep_interval): if self._dynamic_tuning: _sleep_cnt -= 1 if _sleep_cnt <= 0: _sleep_cnt = self._sleep_cycles log.debug("updating monitors") self._unit_manager.update_monitors() log.debug("performing tunings") self._unit_manager.update_tuning() self._profile_applied.clear() # wait for others to complete their tasks, use timeout 3 x sleep_interval to prevent # deadlocks i = 0 while not self._cmd.wait(self._not_used, self._sleep_interval) and i < 3: i += 1 # if terminating due to profile switch if self._terminate_profile_switch.is_set(): full_rollback = True else: # with systemd it detects system shutdown and in such case it doesn't perform # full cleanup, if not shutting down it means that Tuned was explicitly # stopped by user and in such case do full cleanup, without systemd never # do full cleanup full_rollback = False retcode, out = self._cmd.execute( ["systemctl", "is-system-running"], no_errors=[0]) if retcode >= 0: if out[:8] == "stopping": log.info( "terminating Tuned due to system shutdown / reboot") else: log.info("terminating Tuned, rolling back all changes") full_rollback = True if self._daemon: self._unit_manager.stop_tuning(full_rollback) self._unit_manager.destroy_all()
def attach_to_dbus(self, bus_name, object_name, interface_name): if self._dbus_exporter is not None: raise TunedException("DBus interface is already initialized.") self._dbus_exporter = exports.dbus.DBusExporter(bus_name, interface_name, object_name) exports.register_exporter(self._dbus_exporter) exports.register_object(self._controller)
def save_post_loaded_profile(self, profile_name): try: with open(consts.POST_LOADED_PROFILE_FILE, "w") as f: if profile_name is not None: f.write(profile_name + "\n") except (OSError,IOError) as e: raise TunedException("Failed to save the active post-loaded profile: %s" % e.strerror)
def _daemonize_child(self, pid_file, parent_in_fd, child_out_fd): """ Finishes daemonizing process, writes a PID file and signalizes to the parent that the initialization is complete. """ os.close(parent_in_fd) os.chdir("/") os.setsid() os.umask(0) try: pid = os.fork() if pid > 0: sys.exit(0) except OSError as error: log.critical("cannot daemonize, fork() error: %s" % str(error)) os.write(child_out_fd, "%c" % False) os.close(child_out_fd) raise TunedException("Cannot daemonize, second fork() failed.") si = file("/dev/null", "r") so = file("/dev/null", "a+") se = file("/dev/null", "a+", 0) os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno()) self.write_pid_file(pid_file) log.debug("successfully daemonized") os.write(child_out_fd, "%c" % True) os.close(child_out_fd)
def set_profile(self, profile_names, manual): if self.is_running(): errstr = "Cannot set profile while the daemon is running." self._notify_profile_changed(profile_names, False, errstr) raise TunedException(errstr) self._load_profiles(profile_names, manual)
def daemonize(self, pid_file=consts.PID_FILE): """ Daemonizes the application. In case of failure, TunedException is raised in the parent process. If the operation is successfull, the main process is terminated and only child process returns from this method. """ parent_child_fds = os.pipe() try: child_pid = os.fork() except OSError as error: os.close(parent_child_fds[0]) os.close(parent_child_fds[1]) raise TunedException("Cannot daemonize, fork() failed.") try: if child_pid > 0: self._daemonize_parent(*parent_child_fds) sys.exit(0) else: self._daemonize_child(pid_file, *parent_child_fds) except: # pass exceptions only into parent process if child_pid > 0: raise else: sys.exit(1)
def _set_post_loaded_profile(self, profile_name): if not profile_name: self._post_loaded_profile = None elif len(profile_name.split()) > 1: errstr = "Whitespace is not allowed in profile names; only a single post-loaded profile is allowed." raise TunedException(errstr) else: self._post_loaded_profile = profile_name
def set_profile(self, profile_name, save_instantly=False): if self.is_running(): raise TunedException( "Cannot set profile while the daemon is running.") if profile_name == "" or profile_name is None: self._profile = None else: try: self._profile = self._profile_loader.load(profile_name) except: raise TunedException("Cannot load profile '%s'." % profile_name) if save_instantly: if profile_name is None: profile_name = "" self._save_active_profile(profile_name)
def set_all_profiles(self, active_profiles, manual, post_loaded_profile, save_instantly=False): if self.is_running(): errstr = "Cannot set profile while the daemon is running." self._notify_profile_changed(active_profiles, False, errstr) raise TunedException(errstr) self._set_profile(active_profiles, manual) self._set_post_loaded_profile(post_loaded_profile) self._load_profiles() if save_instantly: self._save_active_profile(active_profiles, manual) self._save_post_loaded_profile(post_loaded_profile)
def _thread_code(self): if self._profile is None: raise TunedException( "Cannot start the daemon without setting a profile.") self._unit_manager.create(self._profile.units) self._save_active_profile(self._profile.name) self._unit_manager.start_tuning() self._terminate.clear() while not self._terminate.wait(10): log.debug("updating monitors") self._unit_manager.update_monitors() log.debug("performing tunings") self._unit_manager.update_tuning() self._unit_manager.stop_tuning() self._unit_manager.destroy_all()
def _thread_code(self): if self._profile is None: raise TunedException("Cannot start the daemon without setting a profile.") self._unit_manager.create(self._profile.units) self._save_active_profile(self._profile.name) self._unit_manager.start_tuning() self._profile_applied.set() log.info("static tuning from profile '%s' applied" % self._profile.name) self._notify_profile_changed(self._profile.name, True, "OK") if self._daemon: # In python 2 interpreter with applied patch for rhbz#917709 we need to periodically # poll, otherwise the python will not have chance to update events / locks (due to GIL) # and e.g. DBus control will not work. The polling interval of 1 seconds (which is # the default) is still much better than 50 ms polling with unpatched interpreter. # For more details see tuned rhbz#917587. _sleep_cnt = self._sleep_cycles while not self._cmd.wait(self._terminate, self._sleep_interval): if self._dynamic_tuning: _sleep_cnt -= 1 if _sleep_cnt <= 0: _sleep_cnt = self._sleep_cycles log.debug("updating monitors") self._unit_manager.update_monitors() log.debug("performing tunings") self._unit_manager.update_tuning() self._profile_applied.clear() # wait for others to complete their tasks, use timeout 3 x sleep_interval to prevent # deadlocks i = 0 while not self._cmd.wait(self._not_used, self._sleep_interval) and i < 3: i += 1 # if terminating due to profile switch if self._terminate_profile_switch.is_set(): profile_switch = True else: profile_switch = False if self._daemon: self._unit_manager.stop_tuning(profile_switch) self._unit_manager.destroy_all()