# -*- coding: utf-8 -*-
# Description: cpufreq netdata python.d module
-# Author: Pawel Krupa (paulfantom)
+# Author: Pawel Krupa (paulfantom) and Steven Noonan (tycho)
+import glob
import os
+import time
from base import SimpleService
# default module values (can be overridden per job in `config`)
]}
}
-
class Service(SimpleService):
def __init__(self, configuration=None, name=None):
- self.sys_dir = "/sys/devices"
- self.filename = "scaling_cur_freq"
+ 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.paths = []
+ self.accurate_exists = True
+ self.accurate_last = {}
def _get_data(self):
- raw = {}
- for path in self.paths:
- with open(path, 'r') as f:
- raw[path] = f.read()
data = {}
- for path in self.paths:
- data[self.assignment[path]] = raw[path]
+
+ 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
- for dirpath, _, filenames in os.walk(self.sys_dir):
- if self.filename in filenames:
- self.paths.append(dirpath + "/" + self.filename)
+ 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
- if len(self.paths) == 0:
- return False
+ 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
- self.paths.sort()
- i = 0
- for path in self.paths:
- self.assignment[path] = "cpu" + str(i)
- i += 1
+ 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