diff --git a/test.cfg b/test.cfg index c0c757e..2eaf762 100644 --- a/test.cfg +++ b/test.cfg @@ -72,3 +72,7 @@ merge=1 [my_broken_plugin] type=broken +[my_disk_plugin] +type=disk + + diff --git a/tuned/monitors/monitor_disk.py b/tuned/monitors/monitor_disk.py index e7ceeb2..fe01749 100644 --- a/tuned/monitors/monitor_disk.py +++ b/tuned/monitors/monitor_disk.py @@ -11,6 +11,13 @@ class DiskMonitor(tuned.monitors.Monitor): available = set(filter(cls._is_device_supported, block_devices)) cls._available_devices = available + for d in available: + cls._load[d] = {} + cls._load[d]["new"] = ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'] + cls._load[d]["max"] = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + cls._update_disk(d) + cls._load[d]["max"] = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + @classmethod def _is_device_supported(cls, device): vendor_file = "/sys/block/%s/device/vendor" % device @@ -24,9 +31,26 @@ class DiskMonitor(tuned.monitors.Monitor): @classmethod def update(cls): for device in cls._updating_devices: - # TODO - cls._load[device] = None + cls._update_disk(device) + @classmethod - def _update_disk(cls, name): - pass + def _update_disk(cls, dev): + l = open("/sys/block/"+dev+"/stat", "r").read() + cls._load[dev]["old"] = cls._load[dev]["new"] + cls._load[dev]["new"] = l.split() + l = cls._calcdiff(dev) + for i in xrange(len(l)): + if l[i] > cls._load[dev]["max"][i]: + cls._load[dev]["max"][i] = l[i] + + cls._load[dev]['diff'] = cls._calcdiff(dev) + cls._load[dev]["READ"] = float(cls._load[dev]["diff"][1]) / float(cls._load[dev]["max"][1]) + cls._load[dev]["WRITE"] = float(cls._load[dev]["diff"][5]) / float(cls._load[dev]["max"][5]) + + @classmethod + def _calcdiff(cls, dev): + l = [] + for i in xrange(len(cls._load[dev]["old"])): + l.append(int(cls._load[dev]["new"][i]) - int(cls._load[dev]["old"][i])) + return l diff --git a/tuned/monitors/repository.py b/tuned/monitors/repository.py index 72c1246..846cd7d 100644 --- a/tuned/monitors/repository.py +++ b/tuned/monitors/repository.py @@ -14,6 +14,12 @@ class MonitorRepository(tuned.patterns.Singleton): log.debug("creating monitor %s" % plugin_name) # TODO: exception handling monitor_cls = self._loader.load(plugin_name) + + for monitor in self._monitors: + if (isinstance(monitor, monitor_cls) and + (monitor.devices == devices or devices == None)): + return monitor + monitor_instance = monitor_cls(devices) self._monitors.add(monitor_instance) return monitor_instance diff --git a/tuned/plugins/plugin_disk.py b/tuned/plugins/plugin_disk.py new file mode 100644 index 0000000..210417e --- /dev/null +++ b/tuned/plugins/plugin_disk.py @@ -0,0 +1,84 @@ +import os, copy +import tuned.plugins +import tuned.logs +import tuned.monitors +import struct + +log = tuned.logs.get() + +class DiskPlugin(tuned.plugins.Plugin): + + _supported_vendors = ["ATA", "SCSI"] + + def __init__(self, devices, options): + """ + """ + super(self.__class__, self).__init__(None, options) + + self.devidle = {} + self.power = ["255", "225", "195", "165", "145", "125", "105", "85", "70", "55", "30", "20"] + self.spindown = ["0", "250", "230", "210", "190", "170", "150", "130", "110", "90", "70", "60"] + self.levels = len(self.power) + + self._load_monitor = tuned.monitors.get_repository().create("disk", devices) + + @classmethod + def tunable_devices(cls): + block_devices = os.listdir("/sys/block") + available = set(filter(cls._is_device_supported, block_devices)) + cls._available_devices = available + + @classmethod + def _is_device_supported(cls, device): + vendor_file = "/sys/block/%s/device/vendor" % device + try: + vendor = open(vendor_file).read().strip() + except IOError: + return False + + return vendor in cls._supported_vendors + + def _updateIdle(self, dev, devload): + idle = self.devidle.setdefault(dev, {}) + idle.setdefault("LEVEL", 0) + for type in ("READ", "WRITE"): + if devload[type] == 0.0: + idle.setdefault(type, 0) + idle[type] += 1 + else: + idle.setdefault(type, 0) + idle[type] = 0 + + + def cleanup(self): + log.debug("Cleanup") + + for dev in self.devidle.keys(): + if self.devidle[dev]["LEVEL"] > 0: + os.system("hdparm -S0 -B255 /dev/"+dev+" > /dev/null 2>&1") + + def update_tuning(self): + load = self._load_monitor.get_load() + for dev, devload in load.iteritems(): + self._updateIdle(dev, devload) + + if self.devidle[dev]["LEVEL"] < self.levels-1 and self.devidle[dev]["READ"] >= 6 and self.devidle[dev]["WRITE"] >= 6: + self.devidle[dev].setdefault("LEVEL", 0) + self.devidle[dev]["LEVEL"] += 1 + level = self.devidle[dev]["LEVEL"] + + log.debug("Level changed to %d (power %s, spindown %s)" % (level, self.power[level], self.spindown[level])) + os.system("hdparm -S"+self.power[level]+" -B"+self.spindown[level]+" /dev/"+dev+" > /dev/null 2>&1") + + if self.devidle[dev]["LEVEL"] > 0 and (self.devidle[dev]["READ"] == 0 or self.devidle[dev]["WRITE"] == 0): + self.devidle[dev].setdefault("LEVEL", 0) + self.devidle[dev]["LEVEL"] -= 2 + if self.devidle[dev]["LEVEL"] < 0: + self.devidle[dev]["LEVEL"] = 0 + level = self.devidle[dev]["LEVEL"] + + log.debug("Level changed to %d (power %s, spindown %s)" % (level, self.power[level], self.spindown[level])) + os.system("hdparm -S"+self.power[level]+" -B"+self.spindown[level]+" /dev/"+dev+" > /dev/null 2>&1") + + log.debug("%s load: read %f, write %f" % (dev, load[dev]["READ"], load[dev]["WRITE"])) + log.debug("%s idle: read %d, write %d, level %d" % (dev, self.devidle[dev]["READ"], self.devidle[dev]["WRITE"], self.devidle[dev]["LEVEL"])) diff --git a/tuned/plugins/plugin_net.py b/tuned/plugins/plugin_net.py index 85a6819..adf2975 100644 --- a/tuned/plugins/plugin_net.py +++ b/tuned/plugins/plugin_net.py @@ -49,7 +49,6 @@ class NetTuningPlugin(tuned.plugins.Plugin): load = self._load_monitor.get_load() for dev, devload in load.iteritems(): self._updateIdle(dev, devload) - print self.devidle if self.devidle[dev]["LEVEL"] == 0 and self.devidle[dev]["READ"] >= 6 and self.devidle[dev]["WRITE"] >= 6: self.devidle[dev]["LEVEL"] = 1