# -*- coding: utf-8 -*-
-# Description: cpufreq netdata python.d plugin
-# Author: Pawel Krupa (paulfantom)
+# Description: cpufreq netdata python.d module
+# Author: Pawel Krupa (paulfantom) and Steven Noonan (tycho)
-from base import SysFileService
+import glob
+import os
+import time
+from base import SimpleService
# default module values (can be overridden per job in `config`)
# update_every = 2
]}
}
-
-class Service(SysFileService):
+class Service(SimpleService):
def __init__(self, configuration=None, name=None):
- SysFileService.__init__(self, configuration=configuration, name=name)
+ prefix = os.getenv('NETDATA_HOST_PREFIX', "")
+ if prefix.endswith('/'):
+ prefix = prefix[:-1]
+ self.sys_dir = prefix + "/sys/devices"
+ SimpleService.__init__(self, configuration=configuration, name=name)
self.order = ORDER
self.definitions = CHARTS
self._orig_name = ""
+ self.assignment = {}
+ self.accurate_exists = True
+ self.accurate_last = {}
+
+ def _get_data(self):
+ data = {}
+
+ if self.accurate_exists:
+ elapsed = time.time() - self.timetable['last']
+
+ accurate_ok = True
+
+ for name, paths in self.assignment.items():
+ last = self.accurate_last[name]
+ current = 0
+ for line in open(paths['accurate'], 'r'):
+ line = list(map(int, line.split()))
+ current += (line[0] * line[1]) / 100
+ delta = current - last
+ data[name] = delta
+ self.accurate_last[name] = current
+ if delta == 0 or abs(delta) > 1e7:
+ # Delta is either too large or nonexistent, fall back to
+ # less accurate reading. This can happen if we switch
+ # to/from the 'schedutil' governor, which doesn't report
+ # stats.
+ accurate_ok = False
+
+ if accurate_ok:
+ return data
+ else:
+ self.alert("accurate method failed, falling back")
+
+
+ for name, paths in self.assignment.items():
+ data[name] = open(paths['inaccurate'], 'r').read()
+
+ return data
def check(self):
+ try:
+ self.sys_dir = str(self.configuration['sys_dir'])
+ except (KeyError, TypeError):
+ self.error("No path specified. Using: '" + self.sys_dir + "'")
+
self._orig_name = self.chart_name
- self.paths = self._find("scaling_cur_freq")
- if len(self.paths) == 0:
- return False
+ for path in glob.glob(self.sys_dir + '/system/cpu/cpu*/cpufreq/stats/time_in_state'):
+ path_elem = path.split('/')
+ cpu = path_elem[-4]
+ if cpu not in self.assignment:
+ self.assignment[cpu] = {}
+ self.assignment[cpu]['accurate'] = path
+ self.accurate_last[cpu] = 0
- self.paths.sort()
- i = 0
- for path in self.paths:
- self.assignment[path] = "cpu" + str(i)
- i += 1
+ if len(self.assignment) == 0:
+ self.accurate_exists = False
+
+ for path in glob.glob(self.sys_dir + '/system/cpu/cpu*/cpufreq/scaling_cur_freq'):
+ path_elem = path.split('/')
+ cpu = path_elem[-3]
+ if cpu not in self.assignment:
+ self.assignment[cpu] = {}
+ self.assignment[cpu]['inaccurate'] = path
+
+ if len(self.assignment) == 0:
+ self.error("couldn't find a method to read cpufreq statistics")
+ return False
- for name in self.assignment:
- dim = self.assignment[name]
- self.definitions[ORDER[0]]['lines'].append([dim, dim, 'absolute', 1, 1000])
+ for name in self.assignment.keys():
+ self.definitions[ORDER[0]]['lines'].append([name, name, 'absolute', 1, 1000])
return True
def create(self):
self.chart_name = "cpu"
- status = SysFileService.create(self)
+ status = SimpleService.create(self)
self.chart_name = self._orig_name
return status
def update(self, interval):
self.chart_name = "cpu"
- status = SysFileService.update(self, interval=interval)
+ status = SimpleService.update(self, interval=interval)
self.chart_name = self._orig_name
return status