Skip to content

Commit a486471

Browse files
committed
CPU / softirq stats
1 parent ed79625 commit a486471

3 files changed

Lines changed: 332 additions & 0 deletions

File tree

system/cpu_stats/README.mkdn

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
cpu_stats
2+
===============
3+
4+
Python module for ganglia 3.1.
5+
6+
This module allows you to collect CPU stats that have been left out of stock
7+
Ganglia gmond.
8+
9+
/proc/meminfo
10+
11+
12+
Install
13+
===============
14+
15+
Copy cpu_stats.py from python_modules to your python modules directory e.g.
16+
17+
/usr/lib64/ganglia/python_modules
18+
19+
and cpu_stats.pyconf to
20+
21+
/etc/ganglia/conf.d/
22+
23+
Restart Gmond and you should be set. If you would like only specific metrics
24+
instead of all replace the name_match stanza with entries like these
25+
26+
metric {
27+
name = "procs_blocked"
28+
title = "Blocked processes"
29+
value_threshold = 1.0
30+
}
31+
32+
Restart Gmond and you are done.
33+
34+
## AUTHOR
35+
36+
Author: Vladimir Vuksan https://github.com/vvuksan
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
modules {
2+
module {
3+
name = "cpu_stats"
4+
language = "python"
5+
}
6+
}
7+
8+
collection_group {
9+
collect_every = 10
10+
time_threshold = 45
11+
metric {
12+
name = "procs_blocked"
13+
title = "Processes blocked"
14+
value_threshold = 0.0
15+
}
16+
17+
metric {
18+
name_match = "softirq_(.+)"
19+
value_threshold = 1.0
20+
}
21+
22+
metric {
23+
name_match = "cpu_(.+)"
24+
value_threshold = 1.0
25+
}
26+
27+
28+
}
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
import sys
2+
import traceback
3+
import os
4+
import re
5+
import time
6+
7+
METRICS = {
8+
'time' : 0,
9+
'data' : {}
10+
}
11+
12+
# Got these from /proc/softirqs
13+
softirq_pos = {
14+
'hi' : 1,
15+
'timer' : 2,
16+
'nettx' : 3,
17+
'netrx' : 4,
18+
'block' : 5,
19+
'blockiopoll' : 6,
20+
'tasklet' : 7,
21+
'sched' : 8,
22+
'hrtimer' : 9,
23+
'rcu' : 10
24+
}
25+
26+
LAST_METRICS = dict(METRICS)
27+
METRICS_CACHE_MAX = 5
28+
29+
stat_file = "/proc/stat"
30+
31+
###############################################################################
32+
#
33+
###############################################################################
34+
def get_metrics():
35+
"""Return all metrics"""
36+
37+
global METRICS, LAST_METRICS
38+
39+
if (time.time() - METRICS['time']) > METRICS_CACHE_MAX:
40+
41+
try:
42+
file = open(stat_file, 'r')
43+
44+
except IOError:
45+
return 0
46+
47+
# convert to dict
48+
metrics = {}
49+
for line in file:
50+
parts = re.split("\s+", line)
51+
metrics[parts[0]] = list(parts[1:])
52+
53+
# update cache
54+
LAST_METRICS = dict(METRICS)
55+
METRICS = {
56+
'time': time.time(),
57+
'data': metrics
58+
}
59+
60+
return [METRICS, LAST_METRICS]
61+
62+
63+
def get_value(name):
64+
"""Return a value for the requested metric"""
65+
66+
metrics = get_metrics()[0]
67+
68+
NAME_PREFIX="cpu_"
69+
70+
name = name.replace(NAME_PREFIX,"") # remove prefix from name
71+
72+
try:
73+
result = metrics['data'][name][0]
74+
except StandardError:
75+
result = 0
76+
77+
return result
78+
79+
80+
def get_delta(name):
81+
"""Return change over time for the requested metric"""
82+
83+
# get metrics
84+
[curr_metrics, last_metrics] = get_metrics()
85+
86+
NAME_PREFIX="cpu_"
87+
88+
name = name.replace(NAME_PREFIX,"") # remove prefix from name
89+
90+
try:
91+
delta = (float(curr_metrics['data'][name][0]) - float(last_metrics['data'][name][0])) /(curr_metrics['time'] - last_metrics['time'])
92+
if delta < 0:
93+
print name + " is less 0"
94+
delta = 0
95+
except KeyError:
96+
delta = 0.0
97+
98+
return delta
99+
100+
##############################################################################
101+
# SoftIRQ has multiple values which are defined in a dictionary at the top
102+
##############################################################################
103+
def get_softirq_delta(name):
104+
"""Return change over time for the requested metric"""
105+
106+
# get metrics
107+
[curr_metrics, last_metrics] = get_metrics()
108+
109+
NAME_PREFIX="softirq_"
110+
111+
name = name[len(NAME_PREFIX):] # remove prefix from name
112+
113+
index = softirq_pos[name]
114+
115+
try:
116+
delta = (float(curr_metrics['data']['softirq'][index]) - float(last_metrics['data']['softirq'][index])) /(curr_metrics['time'] - last_metrics['time'])
117+
if delta < 0:
118+
print name + " is less 0"
119+
delta = 0
120+
except KeyError:
121+
delta = 0.0
122+
123+
return delta
124+
125+
126+
127+
def create_desc(skel, prop):
128+
d = skel.copy()
129+
for k,v in prop.iteritems():
130+
d[k] = v
131+
return d
132+
133+
def metric_init(params):
134+
global descriptors, metric_map, Desc_Skel
135+
136+
descriptors = []
137+
138+
Desc_Skel = {
139+
'name' : 'XXX',
140+
'orig_name' : 'XXX',
141+
'call_back' : get_delta,
142+
'time_max' : 60,
143+
'value_type' : 'float',
144+
'format' : '%.0f',
145+
'units' : 'XXX',
146+
'slope' : 'both', # zero|positive|negative|both
147+
'description' : '',
148+
'groups' : 'cpu',
149+
}
150+
151+
descriptors.append(create_desc(Desc_Skel, {
152+
"name" : "cpu_ctxt",
153+
"units" : "ctxs/sec",
154+
"description": "Context Switches",
155+
}))
156+
157+
descriptors.append(create_desc(Desc_Skel, {
158+
"name" : "cpu_intr",
159+
"units" : "intr/sec",
160+
"description": "Interrupts serviced",
161+
}))
162+
163+
descriptors.append(create_desc(Desc_Skel, {
164+
"name" : "procs_blocked",
165+
"units" : "processes",
166+
"call_back" : get_value,
167+
"description": "Processes blocked",
168+
}))
169+
170+
descriptors.append(create_desc(Desc_Skel, {
171+
"name" : "softirq",
172+
"units" : "ops/s",
173+
"description": "Soft IRQs",
174+
}))
175+
176+
descriptors.append(create_desc(Desc_Skel, {
177+
"name" : "softirq_hi",
178+
"units" : "ops/s",
179+
'groups' : 'softirq',
180+
"call_back" : get_softirq_delta
181+
}))
182+
183+
descriptors.append(create_desc(Desc_Skel, {
184+
"name" : "softirq_timer",
185+
"units" : "ops/s",
186+
'groups' : 'softirq',
187+
"call_back" : get_softirq_delta
188+
}))
189+
190+
descriptors.append(create_desc(Desc_Skel, {
191+
"name" : "softirq_nettx",
192+
"units" : "ops/s",
193+
'groups' : 'softirq',
194+
"call_back" : get_softirq_delta
195+
}))
196+
197+
descriptors.append(create_desc(Desc_Skel, {
198+
"name" : "softirq_netrx",
199+
"units" : "ops/s",
200+
'groups' : 'softirq',
201+
"call_back" : get_softirq_delta
202+
}))
203+
204+
descriptors.append(create_desc(Desc_Skel, {
205+
"name" : "softirq_block",
206+
"units" : "ops/s",
207+
'groups' : 'softirq',
208+
"call_back" : get_softirq_delta
209+
}))
210+
211+
descriptors.append(create_desc(Desc_Skel, {
212+
"name" : "softirq_blockiopoll",
213+
"units" : "ops/s",
214+
'groups' : 'softirq',
215+
"call_back" : get_softirq_delta
216+
}))
217+
218+
descriptors.append(create_desc(Desc_Skel, {
219+
"name" : "softirq_tasklet",
220+
"units" : "ops/s",
221+
'groups' : 'softirq',
222+
"call_back" : get_softirq_delta
223+
}))
224+
225+
descriptors.append(create_desc(Desc_Skel, {
226+
"name" : "softirq_sched",
227+
"units" : "ops/s",
228+
'groups' : 'softirq',
229+
"call_back" : get_softirq_delta
230+
}))
231+
232+
descriptors.append(create_desc(Desc_Skel, {
233+
"name" : "softirq_hrtimer",
234+
"units" : "ops/s",
235+
'groups' : 'softirq',
236+
"call_back" : get_softirq_delta
237+
}))
238+
239+
descriptors.append(create_desc(Desc_Skel, {
240+
"name" : "softirq_rcu",
241+
"units" : "ops/s",
242+
'groups' : 'softirq',
243+
"call_back" : get_softirq_delta
244+
}))
245+
246+
247+
# We need a metric_map that maps metric_name to the index in /proc/meminfo
248+
metric_map = {}
249+
250+
for d in descriptors:
251+
metric_name = d['name']
252+
metric_map[metric_name] = { "name": d['orig_name'], "units": d['units'] }
253+
254+
return descriptors
255+
256+
def metric_cleanup():
257+
'''Clean up the metric module.'''
258+
pass
259+
260+
#This code is for debugging and unit testing
261+
if __name__ == '__main__':
262+
metric_init({})
263+
while True:
264+
for d in descriptors:
265+
v = d['call_back'](d['name'])
266+
print '%s = %s' % (d['name'], v)
267+
print 'Sleeping 15 seconds'
268+
time.sleep(5)

0 commit comments

Comments
 (0)