mirror of
https://github.com/netdata/netdata.git
synced 2025-05-05 01:30:32 +00:00

There were two major problems with this module: - The 'cpuN' names weren't accurate. The 'self.paths.sort()' was trying to compensate for os.walk() enumerating the CPUs out of order (as any directory enumeration will do). Unfortunately the sort() function is alphabetical, so it would result in a list of paths like this: [ '/sys/.../cpu0/...' '/sys/.../cpu1/...' '/sys/.../cpu11/...' '/sys/.../cpu12/...' ... ] So the chart for cpu2 would actually map to cpu11's stats. This can be corrected by extracting the 'cpuN' value that's already inside the path anyway. - The scaling_cur_freq value is an instantaneous value. It only represents the current processor P-state at the time it was read, and doesn't account for the other 999ms that netdata wasn't looking at the value. This can be corrected by using data from cpufreq_stats, which includes P-state residency statistics. Note that the values in cpufreq_stats aren't always valid (e.g. if the cpufreq governor is set to 'schedutil', the statistic files exist but are are empty), so we can just fall back to the inaccurate scaling_cur_freq method if necessary. Signed-off-by: Steven Noonan <steven@uplinklabs.net>
99 lines
3.1 KiB
Python
99 lines
3.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Description: cpufreq netdata python.d module
|
|
# Author: Pawel Krupa (paulfantom) and Steven Noonan (tycho)
|
|
|
|
import glob
|
|
import os
|
|
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 = True
|
|
|
|
def _get_data(self):
|
|
data = {}
|
|
if self.accurate:
|
|
for name, path in self.assignment.items():
|
|
total = 0
|
|
for line in open(path, 'r'):
|
|
line = list(map(int, line.split()))
|
|
total += (line[0] * line[1]) / 100
|
|
data[name] = total
|
|
else:
|
|
for name, path in self.assignment.items():
|
|
data[name] = open(path, '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'):
|
|
if len(open(path, 'rb').read().rstrip()) == 0:
|
|
self.alert("time_in_state is empty, broken cpufreq_stats data")
|
|
self.assignment = {}
|
|
break
|
|
path_elem = path.split('/')
|
|
cpu = path_elem[-4]
|
|
self.assignment[cpu] = path
|
|
|
|
if len(self.assignment) == 0:
|
|
self.alert("trying less accurate scaling_cur_freq method")
|
|
self.accurate = False
|
|
|
|
for path in glob.glob(self.sys_dir + '/system/cpu/cpu*/cpufreq/scaling_cur_freq'):
|
|
path_elem = path.split('/')
|
|
cpu = path_elem[-3]
|
|
self.assignment[cpu] = path
|
|
|
|
if len(self.assignment) == 0:
|
|
self.error("couldn't find a method to read cpufreq statistics")
|
|
return False
|
|
|
|
if self.accurate:
|
|
algo = 'incremental'
|
|
else:
|
|
algo = 'absolute'
|
|
|
|
for name in self.assignment.keys():
|
|
self.definitions[ORDER[0]]['lines'].append([name, name, algo, 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
|