From 07077acb1472b871a508d1b4c4f74e4e8eb6f1ae Mon Sep 17 00:00:00 2001 From: "Bjoern B. Brandenburg" Date: Tue, 28 Jun 2011 20:50:08 -0400 Subject: keep track of script used for plotting dissertation results --- dplot.py | 497 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 497 insertions(+) create mode 100755 dplot.py (limited to 'dplot.py') diff --git a/dplot.py b/dplot.py new file mode 100755 index 0000000..9643db6 --- /dev/null +++ b/dplot.py @@ -0,0 +1,497 @@ +#!/usr/bin/env python +import defapp + +from plot import decode, get_data_tmpfile, scenario_heading +from util import load_csv_file, load_binary_file, write_csv_file +from stats import iqr_cutoff + +from binary_data import get_data + +from math import ceil + +import numpy +import csv +from os.path import splitext, basename +from optparse import make_option as o + +from gnuplot import gnuplot, FORMATS, Plot, label, curve + +options = [ + # output options + o('-f', '--format', action='store', dest='format', type='choice', + choices=FORMATS, help='output format'), + o(None, '--save-script', action='store_true', dest='save_script'), + o('-p', '--prefix', action='store', dest='prefix'), + + o('-x', '--xmax', action='store', dest='xmax', type='int', + help='determines x-axis range'), + + o('-y', '--ymax', action='store', dest='ymax', type='float', + help='determines y-axis range'), + + o(None, '--ylog', action='store_true', dest='ylog', + help='use logarithmic y-axis'), + + + o(None, '--pd2-only', action='store_true', dest='pd2_only'), + o(None, '--edf-only', action='store_true', dest='edf_only'), + o(None, '--ed-only', action='store_true', dest='ed_only'), + + + o('-s', '--sched', action='append', dest='schedulers'), + + o(None, '--cpmd', action='append', dest='cpmd', + help='which CPMD cost to use'), + + o('-m', '--max-tardiness', action='store_true', dest='max_tard', + help='plot maximum and not average tardiness'), + + o(None, '--slides', action='store_true', dest='slides'), + o(None, '--smooth', action='store_true', dest='smooth'), + ] + +defaults = { + # output options + 'format' : 'pdf', + 'save_script' : False, + 'prefix' : '', + + 'slides' : False, + 'smooth' : False, + 'lines' : True, + + 'schedulers' : None, + 'pd2_only' : False, + 'edf_only' : False, + 'ed_only' : False, + + 'max_tard' : False, + + 'cpmd' : None, + + + 'xmax' : None, + 'ymax' : None, + 'ylog' : False, + } + +HOST_CPUS = { + 'ludwig' : 24, +} + +HOST_WSS = { + 'ludwig' : 3072 +} + +SCHEDULERS = [ + 'C-EDF-L2', + 'C-EDF-L2-RM', + 'C-EDF-L3', + 'C-EDF-L3-RM', + 'G-EDF', + 'G-EDF-RM', + 'P-EDF', + 'P-EDF-RM', + 'P-FP', + 'P-FP-RM', + 'PD2', + 'PD2-L2', + 'PD2-L2-RM', + 'PD2-L3', + 'PD2-L3-RM', + 'PD2-RM', + 'S-PD2', + 'S-PD2-L2', + 'S-PD2-L2-RM', + 'S-PD2-L3', + 'S-PD2-L3-RM', + 'S-PD2-RM', + ] + +SCHEDPOS = {} +for (i, s) in enumerate(SCHEDULERS): + SCHEDPOS[s] = i + + +DIST_NAME = { + 'bimo-heavy' : '', + 'bimo-heavy-250' : '', + 'bimo-heavy-33' : '', + 'bimo-light' : '', + 'bimo-light-250' : '', + 'bimo-light-33' : '', + 'bimo-medium' : '', + 'bimo-medium-250' : '', + 'bimo-medium-33' : '', + 'exp-10-10-100' : '', + 'exp-25-10-100' : '', + 'exp-50-10-100' : '', + 'uni-heavy' : 'utilization uniformly in []', + 'uni-heavy-250' : '', + 'uni-heavy-33' : '', + 'uni-light' : '', + 'uni-light-250' : '', + 'uni-light-33' : '', + 'uni-medium' : '', + 'uni-medium-250' : '', + 'uni-medium-33' : '', +} + +def sched_name(alg): + staggered = alg.startswith('S-') + dedicated = alg.endswith('-RM') + l3 = 'L3' in alg + l2 = 'L2' in alg + l1 = alg.startswith('P-') + edf = 'EDF' in alg + pd2 = 'PD2' in alg + fp = 'FP' in alg + + if l3: + clust = 'C6-' + elif l2: + clust = 'C2-' + elif l1: + clust = 'P-' + else: + clust = 'G-' + + if edf: + policy = 'EDF' + elif fp: + policy = 'FP' + elif pd2: + if staggered: + policy = 'PD2s' + else: + policy = 'PD2a' + else: + policy = '???' + + if dedicated: + irq = '-R1' + else: + irq = '-Rm' + + return clust + policy + irq + +class DissPlotter(defapp.App): + def __init__(self): + defapp.App.__init__(self, options, defaults, no_std_opts=True) + self.tmpfiles = [] + + def make_plot(self, fname=None): + p = Plot() + p.output = "%s%s.%s" % (self.options.prefix, fname, self.options.format) + p.format = self.options.format + return p + + def setup_png(self, plot): + # standard png options; usually correct; never tweaked for paper + if self.options.format == 'png': + plot.font_size = 'large' + plot.size = (1024, 768) + plot.xticks = (0, 1) + plot.yticks = (0, 0.1) + plot.default_style = "linespoints" + return True + else: + return False + + def write(self, data, name, ext='data'): + if self.options.save_script: + fname = "%s.%s" % (name, ext) + write_csv_file(fname, data) + return fname + else: + tmp = write_csv_file(None, data) + # keep a reference so that it isn't deleted + self.tmpfiles.append(tmp) + return tmp.name + + def prepare(self, name, fname): + data = load_csv_file(fname) + return self.write(data, name) + + def render(self, p): + if self.options.save_script: + p.gnuplot_save(p.output + '.plot') + else: + p.gnuplot_exec() + + def diss_title(self, p, conf): + p.title = scenario_heading(conf, True) + + if 'key' in conf: + p.title += '; WSS=%sKB ' % conf['key'] + + if len(self.options.cpmd) == 1: + p.title += '; %s CPMD' % self.options.cpmd[0] + + + def diss_style(self, p, top_left=False): + if self.options.lines: + marker = 'lines' + else: + marger = 'linespoints' + + if not self.setup_png(p): + p.rounded_caps = True + p.font = 'Helvetica' + + + if len(p.curves) > 2: + p.curves[2].style = marker + " ls 4" + + if len(p.curves) > 3: + p.curves[3].style = marker + " ls 6" + + if False: + for i, c in enumerate(p.curves): + c.style = "linespoints ls %d" % (i + 1) + + p.line_styles = [ + (1, 'lw 8 lc rgbcolor "#000000"'), + (2, 'lw 8 lc rgbcolor "#ff0000"'), + (3, 'lw 8 lc rgbcolor "#0000ff"'), + (4, 'lw 8 lc rgbcolor "#ff910d"'), + # (5, 'lw 2.5 lc rgbcolor "#ff910d"'), + (6, "lw 2.5"), + (7, 'lw 2.5 lc rgbcolor "#000000"'), + (8, "lw 2.5"), + ] + + + p.font_size = '7' + p.size = ('6in', '2.50in') + p.monochrome = True #False + p.dashed_lines = True #True + if top_left: + p.key = 'top left' + else: + p.key = 'top right' + p.default_style = marker + ' lw 1' + p.pointsize = 2 + + if self.options.slides: + p.dashed_lines = False + p.monochrome = False + p.rounded_caps = True + p.default_style = 'lines lw 10' + p.key = 'below' + + if self.options.smooth: + p.default_style += " smooth bezier" + + + def plot_wsched(self, datafile, name, conf): + tmpfile = self.prepare(name, datafile) + + p = self.make_plot(name) + + if len(self.options.cpmd) > 1: + fmts = ['%s (load)', '%s (idle)'] + else: + fmts = ['%s', '%s'] + + for sched in self.options.schedulers: + idx = SCHEDPOS[sched] + + if 'load' in self.options.cpmd: + p.curves += [ + curve(fname=tmpfile, xcol=1, ycol=2 + (idx * 2) + 1, + title=fmts[0] % sched_name(sched)) + ] + + if 'idle' in self.options.cpmd: + p.curves += [ + curve(fname=tmpfile, xcol=1, ycol=2 + (idx * 2) + 2, + title=fmts[1] % sched_name(sched)), + ] + + self.diss_title(p, conf) + p.xlabel = "working set size (WSS) in KB" + p.ylabel = "weighted schedulability score" + + + if 'hard' in conf: + p.ylabel += " [hard]" + else: + p.ylabel += " [soft]" + + if self.options.xmax: + p.xrange = (0, self.options.xmax) + elif 'host' in conf and conf['host'] in HOST_WSS: + p.xrange = (0, HOST_WSS[conf['host']] + 1) + + p.xticks = (0, 64) + + if self.options.ymax: + p.yrange = (-0.05, self.options.ymax) + else: + p.yrange = (-0.05, 1.05) + + p.yticks = (0, 0.1) + + self.diss_style(p) + + self.render(p) + + + def plot_sched(self, datafile, name, conf): + + tmpfile = self.prepare(name, datafile) + + p = self.make_plot(name) + + for sched in self.options.schedulers: + idx = SCHEDPOS[sched] + + if len(self.options.cpmd) > 1: + fmts = ['%s (load)', '%s (idle)'] + else: + fmts = ['%s', '%s'] + + if 'load' in self.options.cpmd: + p.curves += [ + curve(fname=tmpfile, xcol=2, ycol=2 + (idx * 2) + 1, + title=fmts[0] % sched_name(sched)) + ] + + if 'idle' in self.options.cpmd: + p.curves += [ + curve(fname=tmpfile, xcol=2, ycol=2 + (idx * 2) + 2, + title=fmts[1] % sched_name(sched)), + ] + + self.diss_title(p, conf) + p.xlabel = "utilization cap (prior to overhead accounting)" + p.ylabel = "schedulability" + + if 'hard' in conf: + p.ylabel += " [hard]" + else: + p.ylabel += " [soft]" + +# if self.options.xmax: +# p.xrange = (0.5, self.options.xmax) + if 'host' in conf and conf['host'] in HOST_CPUS: + p.xrange = (0.5, HOST_CPUS[conf['host']] + 0.5) + + p.xticks = (0, 2) + + if self.options.ymax: + p.yrange = (-0.05, self.options.ymax) + else: + p.yrange = (-0.05, 1.05) + + self.diss_style(p) + + self.render(p) + + def plot_tardiness(self, datafile, name, conf): + tmpfile = self.prepare(name, datafile) + + p = self.make_plot(name) + + if self.options.max_tard: + offset = [1, 4] # use MAX column + tag = 'max' + else: + offset = [2, 5] # use AVG column + tag = 'avg' + + if len(self.options.cpmd) > 1: + fmts = ['%s (%s, load)', '%s (%s, idle)'] + else: + fmts = ['%s (%s)', '%s (%s)'] + + for sched in self.options.schedulers: + idx = SCHEDPOS[sched] + + if 'load' in self.options.cpmd: + p.curves += [ + curve(fname=tmpfile, xcol=2, ycol=2 + (idx * 6) + offset[0], + title=fmts[0] % (sched_name(sched), tag)) + ] + + if 'idle' in self.options.cpmd: + p.curves += [ + curve(fname=tmpfile, xcol=2, ycol=2 + (idx * 6) + offset[1], + title=fmts[1] % (sched_name(sched), tag)), + ] + + self.diss_title(p, conf) + p.xlabel = "utilization cap (prior to overhead accounting)" + if 'rel-tard' in conf: + p.ylabel = "relative tardiness bound" + else: + p.ylabel = "absolute tardiness bound (in us)" + + if self.options.xmax: + p.xrange = (0.5, self.options.xmax) + elif 'host' in conf and conf['host'] in HOST_CPUS: + p.xrange = (0.5, HOST_CPUS[conf['host']] + 0.5) + + p.xticks = (0, 2) + + if self.options.ymax: + p.yrange = (-0.05, self.options.ymax) + elif 'rel-tard' in conf and not self.options.max_tard: + p.yrange = (-0.05, 5) + p.yticks = (0, 0.5) + + self.diss_style(p, top_left=True) + + self.render(p) + + + def plot_file(self, datafile): + bname = basename(datafile) + name, ext = splitext(bname) + conf = decode(name) + plotters = { + 'wsched' : self.plot_wsched, + 'sched' : self.plot_sched, + 'rel-tard' : self.plot_tardiness, + 'abs-tard' : self.plot_tardiness, + } + + for plot_type in plotters: + if plot_type in conf: + try: + plotters[plot_type](datafile, name, conf) + except IOError as err: + self.err("Skipped '%s' (%s)." % (datafile, err)) + break + else: + self.err("Skipped '%s'; unkown experiment type." + % bname) + # release all tmp files + self.tmpfiles = [] + + def default(self, _): + if self.options.schedulers is None: + self.options.schedulers = SCHEDULERS + + if self.options.cpmd is None: + self.options.cpmd = ['load', 'idle'] + + if self.options.pd2_only: + self.options.schedulers = [s for s in self.options.schedulers + if 'PD2' in s] + + if self.options.edf_only: + self.options.schedulers = [s for s in self.options.schedulers + if 'EDF' in s] + + if self.options.ed_only: + self.options.schedulers = [s for s in self.options.schedulers + if 'EDF' in s or 'FP' in s] + + for i, datafile in enumerate(self.args): + self.out("[%d/%d] Processing %s ..." % (i + 1, len(self.args), datafile)) + self.plot_file(datafile) + +if __name__ == "__main__": + DissPlotter().launch() -- cgit v1.2.2