cpufreq.chart.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. # -*- coding: utf-8 -*-
  2. # Description: cpufreq netdata python.d module
  3. # Author: Pawel Krupa (paulfantom) and Steven Noonan (tycho)
  4. import glob
  5. import os
  6. from bases.FrameworkServices.SimpleService import SimpleService
  7. # default module values (can be overridden per job in `config`)
  8. # update_every = 2
  9. ORDER = ['cpufreq']
  10. CHARTS = {
  11. 'cpufreq': {
  12. 'options': [None, 'CPU Clock', 'MHz', 'cpufreq', 'cpufreq.cpufreq', 'line'],
  13. 'lines': [
  14. # lines are created dynamically in `check()` method
  15. ]}
  16. }
  17. class Service(SimpleService):
  18. def __init__(self, configuration=None, name=None):
  19. prefix = os.getenv('NETDATA_HOST_PREFIX', "")
  20. if prefix.endswith('/'):
  21. prefix = prefix[:-1]
  22. self.sys_dir = prefix + "/sys/devices"
  23. SimpleService.__init__(self, configuration=configuration, name=name)
  24. self.order = ORDER
  25. self.definitions = CHARTS
  26. self.fake_name = 'cpu'
  27. self.assignment = {}
  28. self.accurate_exists = True
  29. self.accurate_last = {}
  30. def _get_data(self):
  31. data = {}
  32. if self.accurate_exists:
  33. accurate_ok = True
  34. for name, paths in self.assignment.items():
  35. last = self.accurate_last[name]
  36. current = {}
  37. deltas = {}
  38. ticks_since_last = 0
  39. for line in open(paths['accurate'], 'r'):
  40. line = list(map(int, line.split()))
  41. current[line[0]] = line[1]
  42. ticks = line[1] - last.get(line[0], 0)
  43. ticks_since_last += ticks
  44. deltas[line[0]] = line[1] - last.get(line[0], 0)
  45. avg_freq = 0
  46. if ticks_since_last != 0:
  47. for frequency, ticks in deltas.items():
  48. avg_freq += frequency * ticks
  49. avg_freq /= ticks_since_last
  50. data[name] = avg_freq
  51. self.accurate_last[name] = current
  52. if avg_freq == 0 or ticks_since_last == 0:
  53. # Delta is either too large or nonexistent, fall back to
  54. # less accurate reading. This can happen if we switch
  55. # to/from the 'schedutil' governor, which doesn't report
  56. # stats.
  57. accurate_ok = False
  58. if accurate_ok:
  59. return data
  60. for name, paths in self.assignment.items():
  61. data[name] = open(paths['inaccurate'], 'r').read()
  62. return data
  63. def check(self):
  64. try:
  65. self.sys_dir = str(self.configuration['sys_dir'])
  66. except (KeyError, TypeError):
  67. self.error("No path specified. Using: '" + self.sys_dir + "'")
  68. for path in glob.glob(self.sys_dir + '/system/cpu/cpu*/cpufreq/stats/time_in_state'):
  69. path_elem = path.split('/')
  70. cpu = path_elem[-4]
  71. if cpu not in self.assignment:
  72. self.assignment[cpu] = {}
  73. self.assignment[cpu]['accurate'] = path
  74. self.accurate_last[cpu] = {}
  75. if len(self.assignment) == 0:
  76. self.accurate_exists = False
  77. for path in glob.glob(self.sys_dir + '/system/cpu/cpu*/cpufreq/scaling_cur_freq'):
  78. path_elem = path.split('/')
  79. cpu = path_elem[-3]
  80. if cpu not in self.assignment:
  81. self.assignment[cpu] = {}
  82. self.assignment[cpu]['inaccurate'] = path
  83. if len(self.assignment) == 0:
  84. self.error("couldn't find a method to read cpufreq statistics")
  85. return False
  86. for name in sorted(self.assignment, key=lambda v: int(v[3:])):
  87. self.definitions[ORDER[0]]['lines'].append([name, name, 'absolute', 1, 1000])
  88. return True