]> git.ipfire.org Git - collecty.git/blob - src/collecty/plugins/cpufreq.py
Catch exception when cpufreq is not supported on a system
[collecty.git] / src / collecty / plugins / cpufreq.py
1 #!/usr/bin/python3
2 ###############################################################################
3 # #
4 # collecty - A system statistics collection daemon for IPFire #
5 # Copyright (C) 2015 IPFire development team #
6 # #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
11 # #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
16 # #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 # #
20 ###############################################################################
21
22 import os
23 import re
24
25 from . import base
26
27 from ..i18n import _
28
29 class GraphTemplateCPUFreq(base.GraphTemplate):
30 name = "cpufreq"
31
32 lower_limit = 0
33
34 @property
35 def graph_title(self):
36 return _("CPU usage")
37
38 @property
39 def graph_vertical_label(self):
40 return "%s [%s]" % (_("Frequency"), _("Hz"))
41
42 def get_object_table(self):
43 objects_table = {}
44
45 for processor in self.plugin.objects:
46 objects_table[processor.id] = processor
47
48 return objects_table
49
50 core_colours = {
51 "cpu0" : "#ff000066",
52 "cpu1" : "#00ff0066",
53 "cpu2" : "#0000ff66",
54 "cpu3" : "#ffff0066",
55 }
56
57 @property
58 def rrd_graph(self):
59 rrd_graph = []
60
61 for core, processor in sorted(self.object_table.items()):
62 i = {
63 "core" : core,
64 "colour" : self.core_colours.get(core, "#000000"),
65 "name" : processor.name,
66 }
67
68 core_graph = [
69 "DEF:current_%(core)s=%%(%(core)s)s:current:AVERAGE",
70 "DEF:minimum_%(core)s=%%(%(core)s)s:minimum:AVERAGE",
71 "DEF:maximum_%(core)s=%%(%(core)s)s:maximum:AVERAGE",
72
73 "VDEF:avg_%(core)s=current_%(core)s,AVERAGE",
74
75 "LINE2:current_%(core)s%(colour)s:%(name)-10s",
76 "GPRINT:avg_%(core)s:%%6.2lf %%sHz\l",
77 ]
78
79 rrd_graph += [line % i for line in core_graph]
80
81 return rrd_graph
82
83 rrd_graph_args = [
84 "--base", "1000", # Hz
85 ]
86
87
88 class CPUFreqObject(base.Object):
89 rrd_schema = [
90 "DS:current:GAUGE:0:U",
91 "DS:minimum:GAUGE:0:U",
92 "DS:maximum:GAUGE:0:U",
93 ]
94
95 def __repr__(self):
96 return "<%s %s>" % (self.__class__.__name__, self.cpuid)
97
98 def init(self, cpuid):
99 self.cpuid = cpuid
100
101 self.sys_path = os.path.join("/sys/devices/system/cpu", self.cpuid)
102
103 @property
104 def name(self):
105 return "Core %s" % self.core_id
106
107 @property
108 def id(self):
109 return self.cpuid
110
111 @property
112 def core_id(self):
113 return self.read_file("topology/core_id")
114
115 def is_cpufreq_supported(self):
116 path = os.path.join(self.sys_path, "cpufreq")
117
118 return os.path.exists(path)
119
120 def collect(self):
121 return (
122 self.read_frequency("cpufreq/cpuinfo_cur_freq"),
123 self.read_frequency("cpufreq/cpuinfo_min_freq"),
124 self.read_frequency("cpufreq/cpuinfo_max_freq"),
125 )
126
127 def read_file(self, filename):
128 file = os.path.join(self.sys_path, filename)
129
130 with open(file, "r") as f:
131 return f.read().strip()
132
133 def read_frequency(self, filename):
134 val = self.read_file(filename)
135
136 # Convert from kHz to Hz
137 return int(val) * 1000
138
139
140 class CPUFreqPlugin(base.Plugin):
141 name = "cpufreq"
142 description = "cpufreq Plugin"
143
144 templates = [GraphTemplateCPUFreq]
145
146 cpuid_pattern = re.compile(r"cpu[0-9]+")
147
148 @property
149 def objects(self):
150 core_ids = []
151
152 for cpuid in os.listdir("/sys/devices/system/cpu"):
153 if not self.cpuid_pattern.match(cpuid):
154 continue
155
156 o = CPUFreqObject(self, cpuid)
157
158 # If we have already seen a virtual core of the processor,
159 # we will skip any others.
160 if o.core_id in core_ids:
161 continue
162
163 # Check if this processor is supported by cpufreq
164 if not o.is_cpufreq_supported():
165 continue
166
167 # Save the ID of the added core
168 core_ids.append(o.core_id)
169
170 yield o