1
0
Fork 0

@command and @command_revert decorator

This commit is contained in:
Jan Kaluza 2012-04-25 08:15:18 +02:00
parent 32d9a9d201
commit 2a3422fcd1
6 changed files with 239 additions and 151 deletions

View file

@ -27,16 +27,45 @@ class Plugin(object):
def __init__(self, devices = None, options = None):
self._devices = devices
self._commands = {}
self._options = self._get_default_options()
self._options["_load_path"] = ""
if options is not None:
self._merge_options(options)
def __del__(self):
try:
self.cleanup()
except:
pass
#def __del__(self):
#try:
#self.cleanup()
#except:
#pass
def register_command(self, option, set_fnc, revert_fnc = None, is_per_dev = False):
self._commands[option] = (is_per_dev, set_fnc, revert_fnc)
def execute_commands(self, devices = []):
for option, (is_per_dev, set_fnc, revert_fnc) in self._commands.iteritems():
if not self._options.has_key(option):
continue
if is_per_dev:
for dev in devices:
set_fnc(dev, self._options[option])
else:
set_fnc(self._options[option])
def cleanup_commands(self, devices = []):
for option, (is_per_dev, set_fnc, revert_fnc) in self._commands.iteritems():
if not self._options.has_key(option):
continue
if revert_fnc:
set_fnc = revert_fnc
if is_per_dev:
for dev in devices:
set_fnc(dev, None)
else:
set_fnc(None)
def cleanup(self):
pass

View file

@ -1,7 +1,7 @@
import tuned.plugins
import tuned.logs
import tuned.monitors
import tuned.utils.commands
from tuned.utils.commands import *
import os
import struct
@ -24,6 +24,13 @@ class CPULatencyPlugin(tuned.plugins.Plugin):
if not tuned.utils.storage.Storage.get_instance().data.has_key("cpu"):
tuned.utils.storage.Storage.get_instance().data["cpu"] = {}
self.register_command("cpu_governor",
self._set_cpu_governor,
self._revert_cpu_governor)
self.register_command("cpu_multicore_powersave",
self._set_cpu_multicore_powersave,
self._revert_cpu_multicore_powersave)
@classmethod
def _get_default_options(cls):
return {
@ -35,16 +42,14 @@ class CPULatencyPlugin(tuned.plugins.Plugin):
}
def cleanup(self):
self._revert_cpu_governor()
self._revert_cpu_multicore_powersave()
self.cleanup_commands()
tuned.monitors.get_repository().delete(self._load_monitor)
os.close(self._cpu_latency_fd)
def update_tuning(self):
if not self._commands_run:
self._apply_cpu_governor()
self._apply_cpu_multicore_powersave()
self.execute_commands()
self._commands_run = True
load = self._load_monitor.get_load()["system"]
@ -61,65 +66,39 @@ class CPULatencyPlugin(tuned.plugins.Plugin):
os.write(self._cpu_latency_fd, latency_bin)
self._latency = latency
# COMMANDS:
def _apply_cpu_governor(self):
self._revert_cpu_governor()
if len(self._options["cpu_governor"]) == 0:
return False
storage = tuned.utils.storage.Storage.get_instance()
@command("cpu", "cpu_governor")
def _set_cpu_governor(self, value):
old_value = tuned.utils.commands.execute(["cpupower", "frequency-info", "-p"])
if old_value.startswith("analyzing CPU"):
try:
old_value = old_value.split('\n')[1].split(' ')[2]
storage.data["cpu"]["cpu_governor"] = old_value
storage.save()
except IndexError:
old_value = ""
pass
tuned.utils.commands.execute(["cpupower", "frequency-set", "-g", self._options["cpu_governor"]])
return True
tuned.utils.commands.execute(["cpupower", "frequency-set", "-g", value])
return old_value
def _revert_cpu_governor(self):
storage = tuned.utils.storage.Storage.get_instance()
if storage.data["cpu"].has_key("cpu_governor"):
tuned.utils.commands.execute(["cpupower", "frequency-set", "-g", storage.data["cpu"]["cpu_governor"]])
del storage.data["cpu"]["cpu_governor"]
@command_revert("cpu", "cpu_governor")
def _revert_cpu_governor(self, value):
tuned.utils.commands.execute(["cpupower", "frequency-set", "-g", value])
def _apply_cpu_multicore_powersave(self):
self._revert_cpu_multicore_powersave()
if len(self._options["cpu_multicore_powersave"]) == 0:
return False
storage = tuned.utils.storage.Storage.get_instance()
@command("cpu", "cpu_multicore_powersave")
def _set_cpu_multicore_powersave(self, value):
old_value = tuned.utils.commands.execute(["cpupower", "info", "-m"])
if old_value.find("not supported") != -1:
log.info("cpu_multicore_powersave is not supported by this system")
return False
return ""
if old_value.startswith("System's multi core scheduler setting"):
try:
old_value = old_value.split(' ')[:-1][:-1] # get "2\n" and remove '\n'
storage.data["cpu"]["cpu_multicore_powersave"] = old_value
storage.save()
except IndexError:
pass
old_value = ""
tuned.utils.commands.execute(["cpupower", "set", "-m", storage.data["cpu"]["cpu_multicore_powersave"]])
return True
tuned.utils.commands.execute(["cpupower", "set", "-m", value])
return old_value
def _revert_cpu_multicore_powersave(self):
storage = tuned.utils.storage.Storage.get_instance()
if storage.data["cpu"].has_key("cpu_multicore_powersave"):
tuned.utils.commands.execute(["cpupower", "set", "-m", storage.data["cpu"]["cpu_multicore_powersave"]])
del storage.data["cpu"]["cpu_multicore_powersave"]
@command_revert("cpu", "cpu_multicore_powersave")
def _revert_cpu_multicore_powersave(self, value):
tuned.utils.commands.execute(["cpupower", "set", "-m", value])

View file

@ -2,7 +2,7 @@ import os, copy
import tuned.plugins
import tuned.logs
import tuned.monitors
import tuned.utils.commands
from tuned.utils.commands import *
import tuned.utils.storage
import struct
@ -30,6 +30,25 @@ class DiskPlugin(tuned.plugins.Plugin):
if not tuned.utils.storage.Storage.get_instance().data.has_key("disk"):
tuned.utils.storage.Storage.get_instance().data["disk"] = {}
self.register_command("elevator",
self._set_elevator,
self._revert_elevator,
is_per_dev = True)
self.register_command("disk_readahead_multiplier",
self._set_disk_readahead_multiplier,
self._revert_disk_readahead_multiplier,
is_per_dev = True)
self.register_command("disk_alpm",
self._set_disk_alpm,
self._revert_disk_alpm)
self.register_command("disk_apm",
self._set_disk_apm,
self._revert_disk_apm,
is_per_dev = True)
self.register_command("disk_spindown",
self._set_disk_spindown,
is_per_dev = True)
@classmethod
def tunable_devices(cls):
block_devices = os.listdir("/sys/block")
@ -101,21 +120,12 @@ class DiskPlugin(tuned.plugins.Plugin):
for dev in self.devidle.keys():
if self.devidle[dev]["LEVEL"] > 0:
os.system("hdparm -S0 -B255 /dev/"+dev+" > /dev/null 2>&1")
self._revert_elevator(dev)
self._revert_disk_apm(dev)
self._revert_disk_readahead_multiplier(dev)
self._revert_disk_alpm()
self.cleanup_commands(self.devidle.keys())
def update_tuning(self):
load = self._load_monitor.get_load()
for dev, devload in load.iteritems():
if not self._elevator_set:
self._apply_elevator(dev)
self._apply_disk_apm(dev)
self._apply_disk_spindown(dev)
self._apply_disk_readahead_multiplier(dev)
self._init_stats(dev)
self._update_stats(dev, devload)
self._update_idle(dev)
@ -142,32 +152,24 @@ class DiskPlugin(tuned.plugins.Plugin):
log.debug("%s idle: read %d, write %d, level %d" % (dev, self.devidle[dev]["read"], self.devidle[dev]["write"], self.devidle[dev]["LEVEL"]))
if not self._elevator_set:
self._apply_disk_alpm()
self._elevator_set = True
# Commands:
def _apply_elevator(self, dev):
self._revert_elevator(dev)
if len(self._options["elevator"]) == 0:
return False
self.execute_commands(load.keys())
self._elevator_set = True
@command("disk", "elevator")
def _set_elevator(self, dev, value):
sys_file = os.path.join("/sys/block/", dev, "queue/scheduler")
tuned.utils.commands.set_file("disk", "elevator_" + dev, sys_file, self._options["elevator"])
return True
old_value = tuned.utils.commands.read_file(sys_file)
tuned.utils.commands.write_to_file(sys_file, value)
return old_value
def _revert_elevator(self, dev):
@command_revert("disk", "elevator")
def _revert_elevator(self, dev, value):
sys_file = os.path.join("/sys/block/", dev, "queue/scheduler")
tuned.utils.commands.revert_file("disk", "elevator_" + dev, sys_file)
def _apply_disk_alpm(self):
self._revert_disk_alpm()
if len(self._options["disk_alpm"]) == 0:
return False
tuned.utils.commands.write_to_file(sys_file, value)
@command("disk", "disk_alpm")
def _set_disk_alpm(self, value):
old_value = ""
for host in os.listdir("/sys/class/scsi_host/"):
port_cmd_path = os.path.join("/sys/class/scsi_host/", host, "ahci_port_cmd")
try:
@ -186,57 +188,46 @@ class DiskPlugin(tuned.plugins.Plugin):
policy = "max_performance"
sys_file = os.path.join("/sys/class/scsi_host/", host, "link_power_management_policy")
tuned.utils.commands.set_file("disk", "disk_alpm", sys_file, policy)
if len(old_value) == 0:
old_value = tuned.utils.commands.read_file(sys_file)
tuned.utils.commands.write_to_file(sys_file, policy)
return True
return old_value
def _revert_disk_alpm(self):
@command_revert("disk", "disk_alpm")
def _revert_disk_alpm(self, value):
for host in os.listdir("/sys/class/scsi_host/"):
sys_file = os.path.join("/sys/class/scsi_host/", host, "link_power_management_policy")
tuned.utils.commands.revert_file("disk", "disk_alpm", sys_file)
def _apply_disk_apm(self, dev):
self._revert_disk_apm(dev)
if len(self._options["disk_apm"]) == 0:
return False
tuned.utils.commands.write_to_file(sys_file, value)
@command("disk", "disk_apm")
def _set_disk_apm(self, dev, value):
#TODO: get current value using hdparm -B. My disk does not support it...
tuned.utils.commands.execute(["hdparm", "-B", self._options["disk_apm"], "/dev/" + dev])
return True
tuned.utils.commands.execute(["hdparm", "-B", value, "/dev/" + dev])
return ""
def _revert_disk_apm(self, dev):
storage = tuned.utils.storage.Storage.get_instance()
if storage.data["disk"].has_key("disk_apm_" + dev):
tuned.utils.commands.execute(["hdparm", "-B", storage.data["disk"]["disk_apm_" + dev], "/dev/" + dev])
del storage.data["disk"]["disk_apm_" + dev]
@command_revert("disk", "disk_apm")
def _revert_disk_apm(self, dev, value):
tuned.utils.commands.execute(["hdparm", "-B", value, "/dev/" + dev])
def _apply_disk_spindown(self, dev):
if len(self._options["disk_spindown"]) == 0:
return False
tuned.utils.commands.execute(["hdparm", "-S", self._options["disk_spindown"], "/dev/" + dev])
return True
def _apply_disk_readahead_multiplier(self, dev):
self._revert_elevator(dev)
if len(self._options["elevator"]) == 0:
return False
@command("disk", "disk_spindown")
def _set_disk_spindown(self, dev, value):
# There's no way how to get current/old spindown value...
tuned.utils.commands.execute(["hdparm", "-S", value, "/dev/" + dev])
@command("disk", "disk_readahead_multiplier")
def _set_disk_readahead_multiplier(self, dev, value):
sys_file = os.path.join("/sys/block/", dev, "queue/read_ahead_kb")
try:
value = open(sys_file).read().strip()
except (OSError,IOError) as e:
log.error("Reading %s error: %s" % (sys_file, e))
return
new_value = int(int(value) * float(self._options["disk_readahead_multiplier"]))
old_value = tuned.utils.commands.read_file(sys_file).strip()
if len(old_value) == 0:
return ""
new_value = int(int(old_value) * float(value))
tuned.utils.commands.set_file("disk", "disk_readahead_multiplier_" + dev, sys_file, str(new_value))
return True
tuned.utils.commands.write_to_file(sys_file, new_value)
return old_value
def _revert_disk_readahead_multiplier(self, dev):
@command_revert("disk", "disk_readahead_multiplier")
def _revert_disk_readahead_multiplier(self, dev, value):
sys_file = os.path.join("/sys/block/", dev, "queue/read_ahead_kb")
tuned.utils.commands.revert_file("disk", "disk_readahead_multiplier_" + dev, sys_file)
tuned.utils.commands.write_to_file(sys_file, value)

View file

@ -1,7 +1,7 @@
import tuned.plugins
import tuned.logs
import tuned.monitors
import tuned.utils.commands
from tuned.utils.commands import *
import os
import struct
import glob
@ -22,6 +22,8 @@ class WirelessPlugin(tuned.plugins.Plugin):
if not tuned.utils.storage.Storage.get_instance().data.has_key("wireless"):
tuned.utils.storage.Storage.get_instance().data["wireless"] = {}
self.register_command("wifi_power_level", self._set_wifi_power_level)
@classmethod
def _get_default_options(cls):
return {
@ -29,21 +31,22 @@ class WirelessPlugin(tuned.plugins.Plugin):
}
def cleanup(self):
self._revert_wifi_power_level()
self.cleanup_commands()
def update_tuning(self):
if not self._commands_run:
self._apply_wifi_power_level()
self.execute_commands()
self._commands_run = True
# COMMANDS:
@command("wireless", "wifi_power_level")
def _set_wifi_power_level(self, power_level):
try:
lines = open("/proc/net/wireless").readlines()
except (OSError,IOError) as e:
log.error("Error reading wifi devices from /proc/net/wireless: %s" % (e))
return None
return ""
ifaces = []
for line in lines:
@ -56,7 +59,7 @@ class WirelessPlugin(tuned.plugins.Plugin):
if len(ifaces) == 0:
log.info("No wifi interfaces found")
return None
return ""
# TODO: set old_value properly. Is there "get_power"? I don't have wifi here
old_value = "5"
@ -68,23 +71,3 @@ class WirelessPlugin(tuned.plugins.Plugin):
tuned.utils.commands.write_to_file(sys_file, power_level)
return old_value
def _apply_wifi_power_level(self):
self._revert_wifi_power_level()
if len(self._options["wifi_power_level"]) == 0:
return False
old_value = self._set_wifi_power_level(self._options["wifi_power_level"])
if old_value:
storage = tuned.utils.storage.Storage.get_instance()
storage.data["wireless"]["wifi_power_level"] = old_value
storage.save()
return True
def _revert_wifi_power_level(self):
storage = tuned.utils.storage.Storage.get_instance()
if storage.data["wireless"].has_key("wifi_power_level"):
self._set_wifi_power_level(storage.data["wireless"]["wifi_power_level"])
del storage.data["wireless"]["wifi_power_level"]

View file

@ -42,6 +42,7 @@ class PluginRepository(tuned.patterns.Singleton):
def delete(self, plugin):
assert isinstance(plugin, self._loader.interface)
log.debug("removing plugin %s" % plugin)
plugin.cleanup()
self._plugins.remove(plugin)
def update(self):

View file

@ -22,15 +22,120 @@ import tuned.monitors
import tuned.utils.storage
import struct
from subprocess import *
from functools import wraps
log = tuned.logs.get()
# command decorator
def command(plugin, key):
"""
This decorator makes adding new commands easier. The only thing you have to do is
to implement method which handles the value of particular option from config file
and returns previosly set value.
Here is example of method like that:
@command("disk", "elevator")
def _set_elevator(self, dev, value):
sys_file = os.path.join("/sys/block/", dev, "queue/scheduler")
old_value = tuned.utils.commands.read_file(sys_file)
tuned.utils.commands.write_to_file(sys_file, value)
return old_value
This decorator works then like this:
1. Tries to revert to previously stored value in Storage class
2. Tries to set the new value
3. Stores old value returned by the original method into Storage
"""
def my_decorator(target):
def wrapper(self, *args, **kwargs):
# Find out if the original method is def method(self, dev, value)
# or just def method(self, value) and set the variables.
dev = ""
value = None
if len(args) == 1:
value = args[0]
else:
dev = "_" + args[0]
value = args[1]
# Check if this plugin has key in Storage cache
storage = tuned.utils.storage.Storage.get_instance()
if not storage.data.has_key(plugin):
log.error("Storage file does not contain item with key %s" % (plugin))
return
# Revert to previous value if it exists
if storage.data[plugin].has_key(key + dev):
old_value = storage.data[plugin][key + dev]
# Plugin could call Plugin.register_command with revert_fnc
# set, so we should try to use specialized method for reverting.
# However, if there's no method like that, use the original method
# this decorator decorates.
revert_fnc = self._commands[key][2]
if not revert_fnc:
if len(dev) == 0:
target(self, old_value)
else:
target(self, dev[1:], old_value)
del storage.data[plugin][key + dev]
else:
if len(dev) == 0:
revert_fnc(old_value)
else:
revert_fnc(dev[1:], old_value)
# set it to new state and store old_value
if not value or len(value) == 0:
return False
old_value = target(self, *args, **kwargs)
if len(old_value) != 0:
storage.data[plugin][key + dev] = old_value
storage.save()
return True
# Fix the wrapper's call signature
return wraps(target)(wrapper)
return my_decorator
# command_revert decorator
def command_revert(plugin, key):
def my_decorator(target):
def wrapper(self, *args, **kwargs):
dev = ""
value = None
if len(args) == 1:
value = args[0]
else:
dev = "_" + args[0]
value = args[1]
# revert to previous state
storage = tuned.utils.storage.Storage.get_instance()
if not storage.data.has_key(plugin):
log.error("Storage file does not contain item with key %s" % (plugin))
return
if storage.data[plugin].has_key(key + dev):
old_value = storage.data[plugin][key + dev]
if len(dev) == 0:
target(self, old_value)
else:
target(self, dev[1:], old_value)
del storage.data[plugin][key + dev]
return True
# Fix the wrapper's call signature
return wraps(target)(wrapper)
return my_decorator
def write_to_file(f, data):
log.debug("Writing to file: %s < %s" % (f, data))
try:
fd = open(f, "w")
fd.write(data)
fd.write(str(data))
fd.close()
except (OSError,IOError) as e:
log.error("Writing to file %s error: %s" % (f, e))