/tuned-2.0.1/tuned/plugins/plugin_disk.py

# · Python · 172 lines · 136 code · 34 blank · 2 comment · 30 complexity · 36655bffd515dc310f4408ba809f9544 MD5 · raw file

  1. import os, copy
  2. import tuned.plugins
  3. import tuned.logs
  4. import tuned.monitors
  5. import struct
  6. log = tuned.logs.get()
  7. class DiskPlugin(tuned.plugins.Plugin):
  8. _supported_vendors = ["ATA", "SCSI"]
  9. def __init__(self, devices, options):
  10. """
  11. """
  12. super(self.__class__, self).__init__(None, options)
  13. self.devidle = {}
  14. self.stats = {}
  15. self.power = ["255", "225", "195", "165", "145", "125", "105", "85", "70", "55", "30", "20"]
  16. self.spindown = ["0", "250", "230", "210", "190", "170", "150", "130", "110", "90", "70", "60"]
  17. self.levels = len(self.power)
  18. self._elevator_set = False
  19. self._old_elevator = ""
  20. if not tuned.utils.storage.Storage.get_instance().data.has_key("disk"):
  21. tuned.utils.storage.Storage.get_instance().data["disk"] = {}
  22. self._load_monitor = tuned.monitors.get_repository().create("disk", devices)
  23. @classmethod
  24. def tunable_devices(cls):
  25. block_devices = os.listdir("/sys/block")
  26. available = set(filter(cls._is_device_supported, block_devices))
  27. cls._available_devices = available
  28. @classmethod
  29. def _is_device_supported(cls, device):
  30. vendor_file = "/sys/block/%s/device/vendor" % device
  31. try:
  32. vendor = open(vendor_file).read().strip()
  33. except IOError:
  34. return False
  35. return vendor in cls._supported_vendors
  36. @classmethod
  37. def _get_default_options(cls):
  38. return {
  39. "elevator" : "",
  40. }
  41. def _apply_elevator(self, dev):
  42. storage = tuned.utils.storage.Storage.get_instance()
  43. if storage.data["disk"].has_key(dev):
  44. self._old_elevator = storage.data["disk"][dev]
  45. self._revert_elevator(dev)
  46. del storage.data["disk"][dev]
  47. if len(self._options["elevator"]) == 0:
  48. return False
  49. try:
  50. f = open(os.path.join("/sys/block/", dev, "queue/scheduler"), "r")
  51. self._old_elevator = f.read()
  52. f.close()
  53. except (OSError,IOError) as e:
  54. log.error("Getting elevator of %s error: %s" % (dev, e))
  55. storage = tuned.utils.storage.Storage.get_instance()
  56. storage.data["disk"] = {dev : self._old_elevator}
  57. storage.save()
  58. log.debug("Applying elevator: %s < %s" % (dev, self._options["elevator"]))
  59. try:
  60. f = open(os.path.join("/sys/block/", dev, "queue/scheduler"), "w")
  61. f.write(self._options["elevator"])
  62. f.close()
  63. except (OSError,IOError) as e:
  64. log.error("Setting elevator on %s error: %s" % (dev, e))
  65. return True
  66. def _revert_elevator(self, dev):
  67. if len(self._old_elevator) == 0:
  68. return
  69. log.debug("Applying elevator: %s < %s" % (dev, self._old_elevator))
  70. try:
  71. f = open(os.path.join("/sys/block/", dev, "queue/scheduler"), "w")
  72. f.write(self._old_elevator)
  73. f.close()
  74. except (OSError,IOError) as e:
  75. log.error("Setting elevator on %s error: %s" % (dev, e))
  76. def _update_idle(self, dev):
  77. idle = self.devidle.setdefault(dev, {})
  78. idle.setdefault("LEVEL", 0)
  79. for type in ("read", "write"):
  80. if self.stats[dev][type] == 0.0:
  81. idle.setdefault(type, 0)
  82. idle[type] += 1
  83. else:
  84. idle.setdefault(type, 0)
  85. idle[type] = 0
  86. def _init_stats(self, dev):
  87. if not self.stats.has_key(dev):
  88. self.stats[dev] = {}
  89. self.stats[dev]["new"] = ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0']
  90. self.stats[dev]["old"] = ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0']
  91. self.stats[dev]["max"] = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  92. def _calc_diff(self, dev):
  93. l = []
  94. for i in xrange(len(self.stats[dev]["old"])):
  95. l.append(int(self.stats[dev]["new"][i]) - int(self.stats[dev]["old"][i]))
  96. return l
  97. def _update_stats(self, dev, devload):
  98. self.stats[dev]["old"] = self.stats[dev]["new"]
  99. self.stats[dev]["new"] = devload
  100. l = self._calc_diff(dev)
  101. for i in xrange(len(l)):
  102. if l[i] > self.stats[dev]["max"][i]:
  103. self.stats[dev]["max"][i] = l[i]
  104. self.stats[dev]["diff"] = l
  105. self.stats[dev]["read"] = float(self.stats[dev]["diff"][1]) / float(self.stats[dev]["max"][1])
  106. self.stats[dev]["write"] = float(self.stats[dev]["diff"][5]) / float(self.stats[dev]["max"][5])
  107. def cleanup(self):
  108. log.debug("Cleanup")
  109. tuned.monitors.get_repository().delete(self._load_monitor)
  110. for dev in self.devidle.keys():
  111. if self.devidle[dev]["LEVEL"] > 0:
  112. os.system("hdparm -S0 -B255 /dev/"+dev+" > /dev/null 2>&1")
  113. self._revert_elevator(dev)
  114. def update_tuning(self):
  115. load = self._load_monitor.get_load()
  116. for dev, devload in load.iteritems():
  117. if not self._elevator_set:
  118. self._apply_elevator(dev)
  119. self._init_stats(dev)
  120. self._update_stats(dev, devload)
  121. self._update_idle(dev)
  122. if self.devidle[dev]["LEVEL"] < self.levels-1 and self.devidle[dev]["read"] >= 6 and self.devidle[dev]["write"] >= 6:
  123. self.devidle[dev].setdefault("LEVEL", 0)
  124. self.devidle[dev]["LEVEL"] += 1
  125. level = self.devidle[dev]["LEVEL"]
  126. log.debug("Level changed to %d (power %s, spindown %s)" % (level, self.power[level], self.spindown[level]))
  127. os.system("hdparm -S"+self.power[level]+" -B"+self.spindown[level]+" /dev/"+dev+" > /dev/null 2>&1")
  128. if self.devidle[dev]["LEVEL"] > 0 and (self.devidle[dev]["read"] == 0 or self.devidle[dev]["write"] == 0):
  129. self.devidle[dev].setdefault("LEVEL", 0)
  130. self.devidle[dev]["LEVEL"] -= 2
  131. if self.devidle[dev]["LEVEL"] < 0:
  132. self.devidle[dev]["LEVEL"] = 0
  133. level = self.devidle[dev]["LEVEL"]
  134. log.debug("Level changed to %d (power %s, spindown %s)" % (level, self.power[level], self.spindown[level]))
  135. os.system("hdparm -S"+self.power[level]+" -B"+self.spindown[level]+" /dev/"+dev+" > /dev/null 2>&1")
  136. log.debug("%s load: read %f, write %f" % (dev, self.stats[dev]["read"], self.stats[dev]["write"]))
  137. log.debug("%s idle: read %d, write %d, level %d" % (dev, self.devidle[dev]["read"], self.devidle[dev]["write"], self.devidle[dev]["LEVEL"]))
  138. self._elevator_set = True