1 |
#! /usr/bin/env python |
2 |
# $Id$ |
3 |
# Source: $URL$ |
4 |
# J. A. Templon, NIKHEF/PDP 2011 |
5 |
|
6 |
import optparse |
7 |
|
8 |
p = optparse.OptionParser(description="Program to make rrdtool plots " + \ |
9 |
"of job running jobs by unix group") |
10 |
|
11 |
# p.add_option("-r",action="store",dest="minsize",default='0',help="minimum size of dirs considered; can use suffixes k,M,G for multiples of 1000**{1,2,3} bytes") |
12 |
# p.add_option("--qdel",action="store_true",dest="deljobs",help="delete jobs for which TMPDIR is larger than MINSIZE",default=False) |
13 |
|
14 |
p.add_option("--rank-only",action="store_true",dest="rankonly", |
15 |
help="don't plot, just print ranking of groups",default=False) |
16 |
|
17 |
debug = 0 |
18 |
|
19 |
opts, args = p.parse_args() |
20 |
|
21 |
import os |
22 |
|
23 |
NUMGROUPS=8 |
24 |
DATADIR=os.environ['HOME'] + '/ndpfdata/' |
25 |
PLOTDIR=os.environ['HOME'] + '/public_html/' |
26 |
# 8 class qualitative paired color scheme |
27 |
|
28 |
colors = [ "#A6CEE3", "#1F77B4", "#B2DF8A", "#33A02C", |
29 |
"#FB9A99", "#E31A1C", "#FDBF6F", "#FF7F00" ] |
30 |
|
31 |
colors.reverse() |
32 |
|
33 |
# for reference : ranges of the RRAs |
34 |
# base step size 60 sec |
35 |
# step 1 : 60 sec x 1600 points : 1600 min : 26,67 hr : 1.11 days |
36 |
# step 2 : 120 sec x 1200 points : 2400 min : 40 hr : 1,67 days |
37 |
# step 10 : 600 sec x 1800 points : 18 000 min : 300 hr : 12,5 days |
38 |
# step 30 : 1800 sec x 2500 points : 75 000 min : 1250 hr : 52.08 days |
39 |
# step 120 : 7200 sec x 1000 points : 120 000 min : 2000 hr : 83.33 days |
40 |
# step 480 : 28800 sec x 1000 points : 480 000 min : 8000 hr : 333.33 days |
41 |
# step 1440 : 86400 sec x 3650 points : 3650 days : 10 years |
42 |
|
43 |
# resolutions of RRAs |
44 |
|
45 |
# 1 : 60 sec : 1 min |
46 |
# 2 : 120 sec : 2 min |
47 |
# 3 : 600 sec : 10 min |
48 |
# 4 : 1 800 sec : 30 min |
49 |
# 5 : 7 200 sec : 120 min : 2 hr |
50 |
# 6 : 28 800 sec : 480 min : 8 hr |
51 |
# 7 : 86 400 sec : 1440 min : 24 hr : 1 day |
52 |
|
53 |
plotrangedef = { |
54 |
'hr' : { 'timeargs' : [ '-s', 'n-200min', '-e', 'n' ], |
55 |
'timetag' : 'hr', |
56 |
'avrange' : 24*3600, |
57 |
'avres' : 60, |
58 |
'sizeargs' : { 'small' : [ '--width', '200', '--height', '125', |
59 |
'--x-grid', |
60 |
'MINUTE:20:HOUR:1:HOUR:1:0:%H:00' |
61 |
], |
62 |
'large' : [ '--width', '800', '--height', '500' ] |
63 |
}, |
64 |
}, |
65 |
'day' : { 'timeargs' : [ '-s', 'n-2000min', '-e', 'n' ], |
66 |
'timetag' : 'day', |
67 |
'avrange' : 24*3600, |
68 |
'avres' : 60, |
69 |
'sizeargs' : { 'small' : [ '--width', '200', '--height', '125', |
70 |
'--x-grid', |
71 |
'HOUR:6:DAY:1:HOUR:12:0:%a %H:00' |
72 |
], |
73 |
'large' : [ '--width', '1000', '--height', '625' ] |
74 |
}, |
75 |
}, |
76 |
'week' : { 'timeargs' : [ '-s', 'n-288hr', '-e', 'n' ], |
77 |
'timetag' : 'week', |
78 |
'avrange' : 7*24*3600, |
79 |
'avres' : 600, |
80 |
'sizeargs' : { 'small' : [ '--width', '576', '--height', '125' ], |
81 |
'large' : [ '--width', '1728', '--height', '375', |
82 |
'-n', 'DEFAULT:16:'] |
83 |
}, |
84 |
}, |
85 |
|
86 |
# note the construction "repr(576*n)" here --- this is because the plot is |
87 |
# (a multiple of) 576 pixels, and 120 min is one of the RRAs, so choosing |
88 |
# a lower limit of 576*120 gives us a plot with one pixel per RRA bin. |
89 |
|
90 |
'month' : { 'timeargs' : [ '-s', 'n-'+repr(576*120)+'min', '-e', 'n'], |
91 |
'timetag' : 'month', |
92 |
'avrange' : 31*24*3600, |
93 |
'avres' : 1800, |
94 |
'sizeargs' : { 'small' : [ '--width', '576', '--height', '105'], |
95 |
'large' : [ '--width', '2304', '--height', '420', |
96 |
'-n', 'DEFAULT:18:', |
97 |
'--x-grid', |
98 |
'HOUR:12:DAY:1:DAY:3:86400:%d-%b' |
99 |
] |
100 |
}, |
101 |
}, |
102 |
|
103 |
'year' : { 'timeargs' : [ '-s', 'n-'+repr((576/2)*1440)+'min', '-e', 'n'], |
104 |
'timetag' : 'year', |
105 |
'avrange' : 365*24*3600, |
106 |
'avres' : 86400, |
107 |
'sizeargs' : { 'small' : [ '--width', '576', '--height', '105'], |
108 |
'large' : [ '--width', '2304', '--height', '420'] |
109 |
}, |
110 |
}, |
111 |
} |
112 |
|
113 |
commonargs = ['--imgformat', 'PNG', |
114 |
'--legend-position=east', '--legend-direction=bottomup'] |
115 |
|
116 |
import rrdtool |
117 |
import time |
118 |
import glob |
119 |
|
120 |
### function definitions |
121 |
|
122 |
def doplot(grouplist, dbtype, psize, timetag, sizeargs, timeargs, pcents): |
123 |
|
124 |
defs = list() |
125 |
plots = list() |
126 |
|
127 |
data_defs = list() |
128 |
plot_defs = list() |
129 |
|
130 |
for group in (grouplist + ['total']): |
131 |
data_defs.append('DEF:'+group+'='+DATADIR+group+'.'+dbtype+'.rrd:'+dbtype+':AVERAGE') |
132 |
|
133 |
for idx in range(len(grouplist)): |
134 |
group = grouplist[idx] |
135 |
pdefstr = 'AREA' ':' + group + colors[idx] + ':' + group |
136 |
if pcents: |
137 |
pdefstr = pdefstr + ' (' + "%4.1f" % (pcents[group]) + ')' |
138 |
pdefstr = pdefstr + '\\n' |
139 |
if idx > 0: |
140 |
pdefstr = pdefstr + ':STACK' |
141 |
plot_defs.append(pdefstr) |
142 |
|
143 |
plot_defs.append('LINE:total#000000:total') |
144 |
|
145 |
pargs = [ PLOTDIR + dbtype + '-' + timetag + '-' + psize + '.png'] + \ |
146 |
commonargs + ['-l', '0'] + sizeargs[psize] + timeargs + \ |
147 |
data_defs + plot_defs |
148 |
rrdtool.graph( *pargs ) |
149 |
|
150 |
def doplot_wait(grouplist, dbtype, psize, timetag, sizeargs, timeargs): |
151 |
|
152 |
defs = list() |
153 |
plots = list() |
154 |
|
155 |
data_defs = list() |
156 |
plot_defs = list() |
157 |
|
158 |
for group in (grouplist + ['rollover','lastroll']): |
159 |
data_defs.append('DEF:'+group+'='+DATADIR+group+'.'+dbtype+'.rrd:'+dbtype+':AVERAGE') |
160 |
|
161 |
for idx in range(len(grouplist)): |
162 |
group = grouplist[idx] |
163 |
pdefstr = 'LINE3' ':' + group + colors[idx] + ':' + group |
164 |
pdefstr = pdefstr + '\\n' |
165 |
plot_defs.append(pdefstr) |
166 |
|
167 |
plot_defs.append('LINE2:rollover#660198') |
168 |
plot_defs.append('LINE2:lastroll#000000') |
169 |
|
170 |
pargs = [ PLOTDIR + dbtype + '-' + timetag + '-' + psize + '.png'] + \ |
171 |
['--slope-mode', '-o'] + \ |
172 |
commonargs + sizeargs[psize] + timeargs + \ |
173 |
data_defs + plot_defs |
174 |
rrdtool.graph( *pargs ) |
175 |
|
176 |
def makeplots(prangedef): |
177 |
|
178 |
resolu = prangedef['avres'] |
179 |
|
180 |
# first need to find "top eight" list |
181 |
# base it on running jobs |
182 |
|
183 |
now=int(time.mktime(time.localtime())) |
184 |
end = (now / resolu) * resolu |
185 |
start = end - (prangedef['avrange']) + resolu |
186 |
|
187 |
### block finding 'top N' group list ### |
188 |
|
189 |
tgroup = dict() # structure tgroup[groupname] = total of hourly average |
190 |
|
191 |
running_files = glob.glob(DATADIR+'*.running.rrd') |
192 |
for db in running_files: |
193 |
group = db[len(DATADIR):db.find('.running.rrd')] |
194 |
tup = rrdtool.fetch(db,'AVERAGE','-r', repr(resolu), |
195 |
'-s', repr(start), '-e', repr(end)) |
196 |
vallist = [0] # start with zero, in case no vals returned, get zero as answer |
197 |
for tup2 in tup[2]: |
198 |
val = tup2[0] |
199 |
if val: |
200 |
vallist.append(val) |
201 |
if group == "total": |
202 |
totval = sum(vallist) |
203 |
else: |
204 |
tgroup[group] = sum(vallist) |
205 |
|
206 |
pgroup = dict() |
207 |
for g in tgroup.keys(): |
208 |
pgroup[g] = 100*tgroup[g]/totval |
209 |
|
210 |
groups_sorted = sorted(tgroup, key=tgroup.get, reverse=False) |
211 |
topgroups=groups_sorted[-NUMGROUPS:] |
212 |
|
213 |
if opts.rankonly: |
214 |
print "Ranks for", prangedef['timetag'], " resolution is", resolu |
215 |
for g in reversed(groups_sorted): |
216 |
if tgroup[g] > 0: |
217 |
print "%10s %12d" % (g, tgroup[g]) |
218 |
return |
219 |
|
220 |
### end block 'top N' group list ### |
221 |
|
222 |
### block generating plots ### |
223 |
|
224 |
|
225 |
for dbtype in ['queued', 'running', 'waittime']: |
226 |
|
227 |
### this is a bit of a hack : we only want pgroups for when it's |
228 |
### a 'running' database and we don't want it for timetag hour. |
229 |
### fix this up here |
230 |
|
231 |
if dbtype == 'running' and prangedef['timetag'] != 'hr': |
232 |
percents = pgroup |
233 |
else: |
234 |
percents = None |
235 |
for psize in ['small', 'large']: |
236 |
if dbtype == 'waittime': |
237 |
doplot_wait(topgroups, dbtype, psize, prangedef['timetag'], |
238 |
prangedef['sizeargs'], |
239 |
prangedef['timeargs'], |
240 |
) |
241 |
else: |
242 |
doplot(topgroups, dbtype, psize, prangedef['timetag'], |
243 |
prangedef['sizeargs'], |
244 |
prangedef['timeargs'], |
245 |
percents |
246 |
) |
247 |
|
248 |
for k in plotrangedef.keys(): |
249 |
makeplots(plotrangedef[k]) |
250 |
|
251 |
import sys |
252 |
sys.exit(0) |