mirror of
https://github.com/netdata/netdata.git
synced 2025-05-11 04:10:55 +00:00

It needs to fail one iteration so there's something to calculate deltas against (the first iteration has no prior data). Once it has the first pass, all future iterations will use the accurate mode data, if it's available. Signed-off-by: Steven Noonan <steven@uplinklabs.net>
115 lines
3.7 KiB
Python
115 lines
3.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Description: cpufreq netdata python.d module
|
|
# 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`)
|
|
# update_every = 2
|
|
|
|
ORDER = ['cpufreq']
|
|
|
|
CHARTS = {
|
|
'cpufreq': {
|
|
'options': [None, 'CPU Clock', 'MHz', 'cpufreq', None, 'line'],
|
|
'lines': [
|
|
# lines are created dynamically in `check()` method
|
|
]}
|
|
}
|
|
|
|
class Service(SimpleService):
|
|
def __init__(self, configuration=None, name=None):
|
|
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
|
|
|
|
|
|
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 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.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 sorted(self.assignment, key=lambda v: int(v[3:])):
|
|
self.definitions[ORDER[0]]['lines'].append([name, name, 'absolute', 1, 1000])
|
|
|
|
return True
|
|
|
|
def create(self):
|
|
self.chart_name = "cpu"
|
|
status = SimpleService.create(self)
|
|
self.chart_name = self._orig_name
|
|
return status
|
|
|
|
def update(self, interval):
|
|
self.chart_name = "cpu"
|
|
status = SimpleService.update(self, interval=interval)
|
|
self.chart_name = self._orig_name
|
|
return status
|