aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xdplot.py497
1 files changed, 497 insertions, 0 deletions
diff --git a/dplot.py b/dplot.py
new file mode 100755
index 0000000..9643db6
--- /dev/null
+++ b/dplot.py
@@ -0,0 +1,497 @@
1#!/usr/bin/env python
2import defapp
3
4from plot import decode, get_data_tmpfile, scenario_heading
5from util import load_csv_file, load_binary_file, write_csv_file
6from stats import iqr_cutoff
7
8from binary_data import get_data
9
10from math import ceil
11
12import numpy
13import csv
14from os.path import splitext, basename
15from optparse import make_option as o
16
17from gnuplot import gnuplot, FORMATS, Plot, label, curve
18
19options = [
20 # output options
21 o('-f', '--format', action='store', dest='format', type='choice',
22 choices=FORMATS, help='output format'),
23 o(None, '--save-script', action='store_true', dest='save_script'),
24 o('-p', '--prefix', action='store', dest='prefix'),
25
26 o('-x', '--xmax', action='store', dest='xmax', type='int',
27 help='determines x-axis range'),
28
29 o('-y', '--ymax', action='store', dest='ymax', type='float',
30 help='determines y-axis range'),
31
32 o(None, '--ylog', action='store_true', dest='ylog',
33 help='use logarithmic y-axis'),
34
35
36 o(None, '--pd2-only', action='store_true', dest='pd2_only'),
37 o(None, '--edf-only', action='store_true', dest='edf_only'),
38 o(None, '--ed-only', action='store_true', dest='ed_only'),
39
40
41 o('-s', '--sched', action='append', dest='schedulers'),
42
43 o(None, '--cpmd', action='append', dest='cpmd',
44 help='which CPMD cost to use'),
45
46 o('-m', '--max-tardiness', action='store_true', dest='max_tard',
47 help='plot maximum and not average tardiness'),
48
49 o(None, '--slides', action='store_true', dest='slides'),
50 o(None, '--smooth', action='store_true', dest='smooth'),
51 ]
52
53defaults = {
54 # output options
55 'format' : 'pdf',
56 'save_script' : False,
57 'prefix' : '',
58
59 'slides' : False,
60 'smooth' : False,
61 'lines' : True,
62
63 'schedulers' : None,
64 'pd2_only' : False,
65 'edf_only' : False,
66 'ed_only' : False,
67
68 'max_tard' : False,
69
70 'cpmd' : None,
71
72
73 'xmax' : None,
74 'ymax' : None,
75 'ylog' : False,
76 }
77
78HOST_CPUS = {
79 'ludwig' : 24,
80}
81
82HOST_WSS = {
83 'ludwig' : 3072
84}
85
86SCHEDULERS = [
87 'C-EDF-L2',
88 'C-EDF-L2-RM',
89 'C-EDF-L3',
90 'C-EDF-L3-RM',
91 'G-EDF',
92 'G-EDF-RM',
93 'P-EDF',
94 'P-EDF-RM',
95 'P-FP',
96 'P-FP-RM',
97 'PD2',
98 'PD2-L2',
99 'PD2-L2-RM',
100 'PD2-L3',
101 'PD2-L3-RM',
102 'PD2-RM',
103 'S-PD2',
104 'S-PD2-L2',
105 'S-PD2-L2-RM',
106 'S-PD2-L3',
107 'S-PD2-L3-RM',
108 'S-PD2-RM',
109 ]
110
111SCHEDPOS = {}
112for (i, s) in enumerate(SCHEDULERS):
113 SCHEDPOS[s] = i
114
115
116DIST_NAME = {
117 'bimo-heavy' : '',
118 'bimo-heavy-250' : '',
119 'bimo-heavy-33' : '',
120 'bimo-light' : '',
121 'bimo-light-250' : '',
122 'bimo-light-33' : '',
123 'bimo-medium' : '',
124 'bimo-medium-250' : '',
125 'bimo-medium-33' : '',
126 'exp-10-10-100' : '',
127 'exp-25-10-100' : '',
128 'exp-50-10-100' : '',
129 'uni-heavy' : 'utilization uniformly in []',
130 'uni-heavy-250' : '',
131 'uni-heavy-33' : '',
132 'uni-light' : '',
133 'uni-light-250' : '',
134 'uni-light-33' : '',
135 'uni-medium' : '',
136 'uni-medium-250' : '',
137 'uni-medium-33' : '',
138}
139
140def sched_name(alg):
141 staggered = alg.startswith('S-')
142 dedicated = alg.endswith('-RM')
143 l3 = 'L3' in alg
144 l2 = 'L2' in alg
145 l1 = alg.startswith('P-')
146 edf = 'EDF' in alg
147 pd2 = 'PD2' in alg
148 fp = 'FP' in alg
149
150 if l3:
151 clust = 'C6-'
152 elif l2:
153 clust = 'C2-'
154 elif l1:
155 clust = 'P-'
156 else:
157 clust = 'G-'
158
159 if edf:
160 policy = 'EDF'
161 elif fp:
162 policy = 'FP'
163 elif pd2:
164 if staggered:
165 policy = 'PD2s'
166 else:
167 policy = 'PD2a'
168 else:
169 policy = '???'
170
171 if dedicated:
172 irq = '-R1'
173 else:
174 irq = '-Rm'
175
176 return clust + policy + irq
177
178class DissPlotter(defapp.App):
179 def __init__(self):
180 defapp.App.__init__(self, options, defaults, no_std_opts=True)
181 self.tmpfiles = []
182
183 def make_plot(self, fname=None):
184 p = Plot()
185 p.output = "%s%s.%s" % (self.options.prefix, fname, self.options.format)
186 p.format = self.options.format
187 return p
188
189 def setup_png(self, plot):
190 # standard png options; usually correct; never tweaked for paper
191 if self.options.format == 'png':
192 plot.font_size = 'large'
193 plot.size = (1024, 768)
194 plot.xticks = (0, 1)
195 plot.yticks = (0, 0.1)
196 plot.default_style = "linespoints"
197 return True
198 else:
199 return False
200
201 def write(self, data, name, ext='data'):
202 if self.options.save_script:
203 fname = "%s.%s" % (name, ext)
204 write_csv_file(fname, data)
205 return fname
206 else:
207 tmp = write_csv_file(None, data)
208 # keep a reference so that it isn't deleted
209 self.tmpfiles.append(tmp)
210 return tmp.name
211
212 def prepare(self, name, fname):
213 data = load_csv_file(fname)
214 return self.write(data, name)
215
216 def render(self, p):
217 if self.options.save_script:
218 p.gnuplot_save(p.output + '.plot')
219 else:
220 p.gnuplot_exec()
221
222 def diss_title(self, p, conf):
223 p.title = scenario_heading(conf, True)
224
225 if 'key' in conf:
226 p.title += '; WSS=%sKB ' % conf['key']
227
228 if len(self.options.cpmd) == 1:
229 p.title += '; %s CPMD' % self.options.cpmd[0]
230
231
232 def diss_style(self, p, top_left=False):
233 if self.options.lines:
234 marker = 'lines'
235 else:
236 marger = 'linespoints'
237
238 if not self.setup_png(p):
239 p.rounded_caps = True
240 p.font = 'Helvetica'
241
242
243 if len(p.curves) > 2:
244 p.curves[2].style = marker + " ls 4"
245
246 if len(p.curves) > 3:
247 p.curves[3].style = marker + " ls 6"
248
249 if False:
250 for i, c in enumerate(p.curves):
251 c.style = "linespoints ls %d" % (i + 1)
252
253 p.line_styles = [
254 (1, 'lw 8 lc rgbcolor "#000000"'),
255 (2, 'lw 8 lc rgbcolor "#ff0000"'),
256 (3, 'lw 8 lc rgbcolor "#0000ff"'),
257 (4, 'lw 8 lc rgbcolor "#ff910d"'),
258 # (5, 'lw 2.5 lc rgbcolor "#ff910d"'),
259 (6, "lw 2.5"),
260 (7, 'lw 2.5 lc rgbcolor "#000000"'),
261 (8, "lw 2.5"),
262 ]
263
264
265 p.font_size = '7'
266 p.size = ('6in', '2.50in')
267 p.monochrome = True #False
268 p.dashed_lines = True #True
269 if top_left:
270 p.key = 'top left'
271 else:
272 p.key = 'top right'
273 p.default_style = marker + ' lw 1'
274 p.pointsize = 2
275
276 if self.options.slides:
277 p.dashed_lines = False
278 p.monochrome = False
279 p.rounded_caps = True
280 p.default_style = 'lines lw 10'
281 p.key = 'below'
282
283 if self.options.smooth:
284 p.default_style += " smooth bezier"
285
286
287 def plot_wsched(self, datafile, name, conf):
288 tmpfile = self.prepare(name, datafile)
289
290 p = self.make_plot(name)
291
292 if len(self.options.cpmd) > 1:
293 fmts = ['%s (load)', '%s (idle)']
294 else:
295 fmts = ['%s', '%s']
296
297 for sched in self.options.schedulers:
298 idx = SCHEDPOS[sched]
299
300 if 'load' in self.options.cpmd:
301 p.curves += [
302 curve(fname=tmpfile, xcol=1, ycol=2 + (idx * 2) + 1,
303 title=fmts[0] % sched_name(sched))
304 ]
305
306 if 'idle' in self.options.cpmd:
307 p.curves += [
308 curve(fname=tmpfile, xcol=1, ycol=2 + (idx * 2) + 2,
309 title=fmts[1] % sched_name(sched)),
310 ]
311
312 self.diss_title(p, conf)
313 p.xlabel = "working set size (WSS) in KB"
314 p.ylabel = "weighted schedulability score"
315
316
317 if 'hard' in conf:
318 p.ylabel += " [hard]"
319 else:
320 p.ylabel += " [soft]"
321
322 if self.options.xmax:
323 p.xrange = (0, self.options.xmax)
324 elif 'host' in conf and conf['host'] in HOST_WSS:
325 p.xrange = (0, HOST_WSS[conf['host']] + 1)
326
327 p.xticks = (0, 64)
328
329 if self.options.ymax:
330 p.yrange = (-0.05, self.options.ymax)
331 else:
332 p.yrange = (-0.05, 1.05)
333
334 p.yticks = (0, 0.1)
335
336 self.diss_style(p)
337
338 self.render(p)
339
340
341 def plot_sched(self, datafile, name, conf):
342
343 tmpfile = self.prepare(name, datafile)
344
345 p = self.make_plot(name)
346
347 for sched in self.options.schedulers:
348 idx = SCHEDPOS[sched]
349
350 if len(self.options.cpmd) > 1:
351 fmts = ['%s (load)', '%s (idle)']
352 else:
353 fmts = ['%s', '%s']
354
355 if 'load' in self.options.cpmd:
356 p.curves += [
357 curve(fname=tmpfile, xcol=2, ycol=2 + (idx * 2) + 1,
358 title=fmts[0] % sched_name(sched))
359 ]
360
361 if 'idle' in self.options.cpmd:
362 p.curves += [
363 curve(fname=tmpfile, xcol=2, ycol=2 + (idx * 2) + 2,
364 title=fmts[1] % sched_name(sched)),
365 ]
366
367 self.diss_title(p, conf)
368 p.xlabel = "utilization cap (prior to overhead accounting)"
369 p.ylabel = "schedulability"
370
371 if 'hard' in conf:
372 p.ylabel += " [hard]"
373 else:
374 p.ylabel += " [soft]"
375
376# if self.options.xmax:
377# p.xrange = (0.5, self.options.xmax)
378 if 'host' in conf and conf['host'] in HOST_CPUS:
379 p.xrange = (0.5, HOST_CPUS[conf['host']] + 0.5)
380
381 p.xticks = (0, 2)
382
383 if self.options.ymax:
384 p.yrange = (-0.05, self.options.ymax)
385 else:
386 p.yrange = (-0.05, 1.05)
387
388 self.diss_style(p)
389
390 self.render(p)
391
392 def plot_tardiness(self, datafile, name, conf):
393 tmpfile = self.prepare(name, datafile)
394
395 p = self.make_plot(name)
396
397 if self.options.max_tard:
398 offset = [1, 4] # use MAX column
399 tag = 'max'
400 else:
401 offset = [2, 5] # use AVG column
402 tag = 'avg'
403
404 if len(self.options.cpmd) > 1:
405 fmts = ['%s (%s, load)', '%s (%s, idle)']
406 else:
407 fmts = ['%s (%s)', '%s (%s)']
408
409 for sched in self.options.schedulers:
410 idx = SCHEDPOS[sched]
411
412 if 'load' in self.options.cpmd:
413 p.curves += [
414 curve(fname=tmpfile, xcol=2, ycol=2 + (idx * 6) + offset[0],
415 title=fmts[0] % (sched_name(sched), tag))
416 ]
417
418 if 'idle' in self.options.cpmd:
419 p.curves += [
420 curve(fname=tmpfile, xcol=2, ycol=2 + (idx * 6) + offset[1],
421 title=fmts[1] % (sched_name(sched), tag)),
422 ]
423
424 self.diss_title(p, conf)
425 p.xlabel = "utilization cap (prior to overhead accounting)"
426 if 'rel-tard' in conf:
427 p.ylabel = "relative tardiness bound"
428 else:
429 p.ylabel = "absolute tardiness bound (in us)"
430
431 if self.options.xmax:
432 p.xrange = (0.5, self.options.xmax)
433 elif 'host' in conf and conf['host'] in HOST_CPUS:
434 p.xrange = (0.5, HOST_CPUS[conf['host']] + 0.5)
435
436 p.xticks = (0, 2)
437
438 if self.options.ymax:
439 p.yrange = (-0.05, self.options.ymax)
440 elif 'rel-tard' in conf and not self.options.max_tard:
441 p.yrange = (-0.05, 5)
442 p.yticks = (0, 0.5)
443
444 self.diss_style(p, top_left=True)
445
446 self.render(p)
447
448
449 def plot_file(self, datafile):
450 bname = basename(datafile)
451 name, ext = splitext(bname)
452 conf = decode(name)
453 plotters = {
454 'wsched' : self.plot_wsched,
455 'sched' : self.plot_sched,
456 'rel-tard' : self.plot_tardiness,
457 'abs-tard' : self.plot_tardiness,
458 }
459
460 for plot_type in plotters:
461 if plot_type in conf:
462 try:
463 plotters[plot_type](datafile, name, conf)
464 except IOError as err:
465 self.err("Skipped '%s' (%s)." % (datafile, err))
466 break
467 else:
468 self.err("Skipped '%s'; unkown experiment type."
469 % bname)
470 # release all tmp files
471 self.tmpfiles = []
472
473 def default(self, _):
474 if self.options.schedulers is None:
475 self.options.schedulers = SCHEDULERS
476
477 if self.options.cpmd is None:
478 self.options.cpmd = ['load', 'idle']
479
480 if self.options.pd2_only:
481 self.options.schedulers = [s for s in self.options.schedulers
482 if 'PD2' in s]
483
484 if self.options.edf_only:
485 self.options.schedulers = [s for s in self.options.schedulers
486 if 'EDF' in s]
487
488 if self.options.ed_only:
489 self.options.schedulers = [s for s in self.options.schedulers
490 if 'EDF' in s or 'FP' in s]
491
492 for i, datafile in enumerate(self.args):
493 self.out("[%d/%d] Processing %s ..." % (i + 1, len(self.args), datafile))
494 self.plot_file(datafile)
495
496if __name__ == "__main__":
497 DissPlotter().launch()