#!/usr/bin/env python import defapp import re from os.path import splitext, basename from optparse import make_option as o from tempfile import NamedTemporaryFile as Tmp 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('-e', '--experiment', action='store', dest='experiment', help="override auto-detection of experiment"), # formatting options # These may or may not be supported by a particular experiment plotter. o(None, '--smooth', action='store_true', dest='smooth'), o(None, '--paper', action='store_true', dest='paper'), o(None, '--wide', action='store_true', dest='wide'), o(None, '--column', action='store_true', dest='column'), o(None, '--split', action='store_true', dest='split'), o(None, '--alternate', action='store_true', dest='alternate'), o(None, '--slides', action='store_true', dest='slides'), o(None, '--appendix', action='store_true', dest='appendix'), ] defaults = { # output options 'format' : 'show', 'experiment' : None, 'save_script' : False, 'prefix' : '', # formatting options 'paper' : False, 'split' : False, 'wide' : False, 'alternate' : False, 'column' : False, 'slides' : False, 'smooth' : False, 'appendix' : False, # legacy "options" that are not actually options. 'xrange' : (0.5, 32.5), 'yrange' : (-0.05, 1.05), 'xticks' : (0, 2), 'yticks' : (0, 0.1), 'title' : None, 'xlabel' : 'task set utilization cap (prior to inflation)', 'ylabel' : 'ratio of schedulable task sets', } def decode(name): params = {} parts = name.split('_') for p in parts: kv = p.split('=') k = kv[0] v = kv[1] if len(kv) > 1 else None params[k] = v return params def get_data_tmpfile(datafile, target=None): """Removes all comments form datafile, stores result in a temp file. The temp file is returned.""" count = 0 f = open(datafile, 'r') if target: d = open(target, 'w') else: d = Tmp() for line in f: if len(line) > 1 and line[0] != '#': d.write(line) count += 1 f.close() d.flush() if count > 0: return d else: del d # removes temp file return None def scenario_heading(conf, want_period=False): dist = 'unknown distribution' period = None if 'dist' in conf: if conf['dist'] == 'uni': dist = 'utilization uniformly ' if 'light' in conf: dist = dist + 'in [0.001, 0.1]' elif 'medium' in conf: dist = dist + 'in [0.1, 0.4]' elif 'heavy' in conf: dist = dist + 'in [0.5, 0.9]' elif 'mixed' in conf: dist = dist + 'in [0.05, 0.95]' elif conf['dist'] == 'bimo': dist = 'util. bimodally ' if 'light' in conf: dist = dist + 'in [0.001, 0.5] (8/9) and [0.5, 0.9] (1/9)' elif 'medium' in conf: dist = dist + 'in [0.001, 0.5] (6/9) and [0.5, 0.9] (3/9)' elif 'heavy' in conf: dist = dist + 'in [0.001, 0.5] (4/9) and [0.5, 0.9] (5/9)' else: # try regular expressions m = re.match('uni-(\d\.\d+)-(\d\.\d+)', conf['dist']) if m: dist = "utilization uniformly in [%s, %s]" % (m.group(1), m.group(2)) m = re.match('bimo-([^-]+)-(\d\.\d+)', conf['dist']) if m: weight = m.group(1) cap = m.group(2) dist = 'util. bimodally ' if 'light' == weight: dist = dist + 'in [0.001, 0.5] (8/9) and [0.5, %s] (1/9)' % cap elif 'medium' == weight: dist = dist + 'in [0.001, 0.5] (6/9) and [0.5, %s] (3/9)' % cap elif 'heavy' == weight: dist = dist + 'in [0.001, 0.5] (4/9) and [0.5, %s] (5/9)' % cap m = re.match('exp-(\d+)-(\d+)-(\d+)', conf['dist']) if m: mean = (float(m.group(1)) / 100) period = (m.group(2), m.group(3)) dist = "util. exponentially in [0, 1] with mean %.2f" % mean if want_period: if period: dist += '; period uniformly in [%s, %s]' % period elif '33' in conf: dist += '; period uniformly in [3, 33]' elif '250' in conf: dist += '; period uniformly in [50, 250]' else: dist += '; period uniformly in [10, 100]' return dist class SchedPlotter(defapp.App): def __init__(self): defapp.App.__init__(self, options, defaults, no_std_opts=True) def plot(self, graphs, title, name, conf, **xtra): gnuplot(graphs, title=title, xlabel=self.options.xlabel, ylabel=self.options.ylabel + (' [soft]' if 'soft' in conf else ' [hard]'), xrange=self.options.xrange, yrange=self.options.yrange, xticks=self.options.xticks, yticks=self.options.yticks, format=self.options.format, fname=name, **xtra) def plot_wide(self, graphs, title, name, conf, **xtra): tops = 'rounded size 16cm,6.5cm' gnuplot(graphs, title=title, xlabel=self.options.xlabel, ylabel=self.options.ylabel + (' [soft]' if 'soft' in conf else ' [hard]'), xrange=self.options.xrange, yrange=self.options.yrange, xticks=self.options.xticks, yticks=self.options.yticks, format=self.options.format, fname=name, term_opts=tops, **xtra) # width = 3.4in # height = 2.0in def plot_column(self, graphs, title, name, conf, **xtra): scale = 1.0 tops = 'color solid font "Helvetica,8" linewidth 1.0 ' \ 'rounded size %.1fin,%.1fin' % (scale * 7.0, scale * 2.0) gnuplot(graphs, title=title, xlabel=self.options.xlabel, ylabel=self.options.ylabel + (' [soft]' if 'soft' in conf else ' [hard]'), xrange=self.options.xrange, yrange=self.options.yrange, xticks=self.options.xticks, yticks=self.options.yticks, format=self.options.format, fname=name, key='right bottom' if '250' in conf else 'right top', term_opts=tops) def plot_paper(self, graphs, title, name, conf, **xtra): tops = 'color solid font "Helvetica,10" linewidth 1.0 rounded size 16cm,8.5cm' gnuplot(graphs, title=title, xlabel=self.options.xlabel, ylabel=self.options.ylabel + (' [soft]' if 'soft' in conf else ' [hard]'), xrange=self.options.xrange, yrange=self.options.yrange, xticks=self.options.xticks, yticks=self.options.yticks, format=self.options.format, fname=name, key='off', style='lines lw 7', term_opts=tops) def plot_spec(self, tmpfile, name, conf): title = 'G-EDF overhead speculation: ' + scenario_heading(conf) graphs = [ (tmpfile, 1, 2, 'G-EDF (100% release)'), (tmpfile, 1, 3, 'G-EDF ( 75% release)'), (tmpfile, 1, 4, 'G-EDF ( 50% release)'), (tmpfile, 1, 5, 'G-EDF ( 25% release)'), (tmpfile, 1, 6, 'G-EDF ( 0% release)'), (tmpfile, 1, 7, 'G-EDF (no overheads)'), ] if self.options.paper and self.options.format == 'pdf': self.plot_paper(graphs, title, name, conf) else: self.plot(graphs, title, name, conf) def plot_spec2(self, tmpfile, name, conf): title = 'service processor speculation: ' + scenario_heading(conf) graphs = [ (tmpfile, 1, 2, 'G-EDF ( 25% release, 100% rest)'), (tmpfile, 1, 3, 'G-EDF (100% release, 0% rest)'), (tmpfile, 1, 4, 'G-EDF (service cpu, 100% preempt)'), (tmpfile, 1, 5, 'G-EDF (service cpu, 150% preempt)'), ] self.plot(graphs, title, name, conf) def plot_spec3(self, tmpfile, name, conf): title = 'linear overhead charge speculation: ' + scenario_heading(conf) graphs = [ (tmpfile, 1, 2, 'G-EDF (100% release)'), (tmpfile, 1, 3, 'G-EDF ( 25% release)'), (tmpfile, 1, 4, 'G-EDF ( Lin release)'), ] self.plot(graphs, title, name, conf) def plot_spec4(self, tmpfile, name, conf): title = 'linear overhead charge speculation: ' + scenario_heading(conf) graphs = [ (tmpfile, 1, 2, 'G-EDF (100% release)'), (tmpfile, 1, 3, 'G-EDF-S (100% release, all cpus)'), (tmpfile, 1, 4, 'G-EDF-S (100% release, one cpu)'), (tmpfile, 1, 5, 'G-EDF (25% release)'), (tmpfile, 1, 6, 'G-EDF-S (25% release, all cpus)'), (tmpfile, 1, 7, 'G-EDF-S (25% release, one cpu)'), ] self.plot(graphs, title, name, conf) 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 plot_irq(self, tmpfile, name, conf): p = self.make_plot(name) #### Data. titles = ['quantum-centric', 'task-centric', 'processor-centric', 'dedicated processor', 'dedicated proc. + timer multiplexing'] if self.options.alternate: extra = '; 20% ISR costs' cols = [8, 9, 10, 12, 14] p.output = 'alt_' + p.output else: extra = '; 100% ISR costs' cols = [1, 2, 3, 5, 7] p.curves += [ curve(fname=tmpfile, xcol=1, ycol=(y + 1), title=t) for (y, t) in zip(cols, titles) ] #### Styling. if not self.setup_png(p): # eps or pdf p.rounded_caps = True p.font = 'Helvetica' if self.options.paper: # workaround strange font-size bug if self.options.format == 'eps': p.font_size = '9.5pt' else: p.font_size = '5pt' p.size = ('6.5cm', '5.25cm') p.monochrome = True p.dashed_lines = True p.key = 'off' p.xticks = (0, 2) p.yrange = (-0.1, 1.1) p.yticks = (0, 0.2) p.xlabel = "task set utilization cap (prior to overhead accounting)" p.default_style = 'lines lw 2.5' else: p.font_size = '10' p.size = ('20cm', '10cm') p.monochrome = False p.dashed_lines = False p.key = 'below' p.xticks = (0, 1) p.yrange = (-0.05, 1.05) p.yticks = (0, 0.1) p.xlabel = "ucap (prior to inflation)" p.default_style = 'lines lw 6' p.ylabel = "schedulability " + (' [soft]' if 'soft' in conf else ' [hard]') p.xrange = (0.5, 32.5) p.title = scenario_heading(conf) + extra if not self.options.paper: p.title = 'Interrupt accounting under G-EDF: utilization ' + p.title if self.options.save_script: p.gnuplot_save(p.output + '.plot') else: p.gnuplot_exec() def plot_rtss08(self, tmpfile, name, conf): p = self.make_plot(name) #### Data. titles = ['P-EDF', 'C-EDF', 'G-EDF', 'PFAIR', 'S-PFAIR', 'G-NP-EDF'] if 'hard' in conf: del titles[-1] p.curves += [curve(fname=tmpfile, xcol=1, ycol=(y + 2), title=t) for (y, t) in enumerate(titles)] #### Styling. if not self.setup_png(p): # eps or pdf if self.options.slides: # for Jim's slides if self.options.format == 'eps': p.font_size = 'large' p.dashed_lines = False p.monochrome = False p.rounded_caps = True p.default_style = 'lines lw 10' p.xticks = (0, 1) p.yticks = (0, 0.1) p.yrange = (-0.05, 1.05) p.key = 'below' p.xlabel = "task set utilization cap (prior to overhead accounting)" else: p.rounded_caps = True p.font = 'Helvetica' p.font_size = '10' p.size = ('20cm', '10cm') p.monochrome = False p.dashed_lines = True p.key = 'below' p.xticks = (0, 1) p.yrange = (-0.05, 1.05) p.yticks = (0, 0.1) p.xlabel = "ucap (prior to inflation)" p.default_style = 'lines lw 6' if self.options.smooth: p.default_style += " smooth bezier" p.ylabel = "schedulability " + (' [soft]' if 'soft' in conf else ' [hard]') if self.options.alternate: p.xrange = (0.5, 32.5) else: p.xrange = (0.5, 32.5) p.title = scenario_heading(conf, True) if not (self.options.paper or self.options.slides): p.title = "RTSS'08 " + p.title if self.options.save_script: p.gnuplot_save(p.output + '.plot') else: p.gnuplot_exec() def plot_rtss09(self, tmpfile, name, conf): title = scenario_heading(conf, want_period=True) graphs = [ (tmpfile, 1, 2, 'G-EDF'), (tmpfile, 1, 3, 'CEm'), (tmpfile, 1, 4, 'CE1'), (tmpfile, 1, 5, 'FEm'), (tmpfile, 1, 6, 'FE1'), (tmpfile, 1, 7, 'HEm'), (tmpfile, 1, 8, 'CQm'), (tmpfile, 1, 9, 'CQ1'), ] staggered = [ (tmpfile, 1, 10, 'S-CQm'), (tmpfile, 1, 11, 'S-CQ1'), ] if 'hard' in conf: graphs += staggered if self.options.paper and self.options.format == 'pdf': self.plot_paper(graphs, title, name, conf) elif self.options.wide and self.options.format == 'pdf': self.plot_wide(graphs, title, name, conf) else: self.plot(graphs, title, name, conf) def plot_rtss09_split(self, tmpfile, name, conf): title = scenario_heading(conf, want_period=True) ideal = (tmpfile, 1, 2, 'G-EDF') subgraphs = [ # dedicated vs. non-dedicated [(tmpfile, 1, 3, 'CEm'), (tmpfile, 1, 4, 'CE1')], [(tmpfile, 1, 5, 'FEm'), (tmpfile, 1, 6, 'FE1')], [(tmpfile, 1, 8, 'CQm'), (tmpfile, 1, 9, 'CQ1')], # fine-grained vs. sequential [(tmpfile, 1, 3, 'CEm'), (tmpfile, 1, 5, 'FEm')], [(tmpfile, 1, 4, 'CE1'), (tmpfile, 1, 6, 'FE1')], # hierarchical vs. sequential [(tmpfile, 1, 3, 'CEm'), (tmpfile, 1, 7, 'HEm')], # quantum vs. event [(tmpfile, 1, 3, 'CEm'), (tmpfile, 1, 8, 'CQm')], [(tmpfile, 1, 6, 'FE1'), (tmpfile, 1, 9, 'CQ1')], ] staggered = [ # dedicated vs. non-dedicated [(tmpfile, 1, 10, 'S-CQm'), (tmpfile, 1, 11, 'S-CQ1')], # staggered vs. non-staggered [(tmpfile, 1, 8, 'CQm'), (tmpfile, 1, 10, 'S-CQm')], [(tmpfile, 1, 9, 'CQ1'), (tmpfile, 1, 11, 'S-CQ1')], # quantum vs. event [(tmpfile, 1, 3, 'CEm'), (tmpfile, 1, 10, 'S-CQm')], [(tmpfile, 1, 6, 'FE1'), (tmpfile, 1, 11, 'S-CQ1')], ] if 'hard' in conf: subgraphs += staggered for g in subgraphs: graphs = [ideal] + g xname = name + '_' + '-vs-'.join([x[3] for x in g]) if self.options.paper and self.options.format == 'pdf': self.plot_paper(graphs, title, xname, conf) elif self.options.wide and self.options.format == 'pdf': self.plot_wide(graphs, title, xname, conf) else: self.plot(graphs, title, xname, conf) def plot_ospert10(self, tmpfile, name, conf): title = scenario_heading(conf, want_period=True) # cumulative graphs graphs = [ (tmpfile, 1, 2, 'G-EDF'), (tmpfile, 1, 4, 'C-EDF (L3)'), (tmpfile, 1, 6, 'C-EDF (L2)'), (tmpfile, 1, 8, 'P-EDF'), ] # weighted graphs graphs_w = [ (tmpfile, 1, 3, 'G-EDF'), (tmpfile, 1, 5, 'C-EDF (L3)'), (tmpfile, 1, 7, 'C-EDF (L2)'), (tmpfile, 1, 9, 'P-EDF'), ] self.options.xrange = (-5, 5005) self.options.xticks = (0, 250) self.options.xlabel = "cache-related preemption/migration delay (in us)" for (tag, gs) in [('cumulative', graphs), ('weighted', graphs_w)]: xname = name + '_' + tag self.options.ylabel = tag + ' schedulability' if self.options.paper and self.options.format == 'pdf': self.plot_paper(gs, title, xname, conf) elif self.options.wide and self.options.format == 'pdf': self.plot_wide(gs, title, xname, conf) elif self.options.column and self.options.format == 'pdf': self.plot_column(gs, title, xname, conf) else: self.plot(gs, title, xname, conf) def plot_semipart(self, tmpfile, name, conf): if not 'soft' in conf: cedf_titles = [('P-EDF (load)', 3), ('P-EDF (idle)', 4)] else: cedf_titles = [('C-EDF (load)', 3), ('C-EDF (idle)', 4)] edfwm_titles = [ ('EDF-WM (load)', 5), ('EDF-WM (idle)', 6) ] npsf_titles = [ ('NPS-F (load, delta=1)', 7), ('NPS-F (idle, delta=1)', 9), ('NPS-F (load, delta=4)', 8), ('NPS-F (idle, delta=4)', 10), ] cnpsf_titles = [ ('C-NPS-F (load, delta=1)', 11), ('C-NPS-F (idle, delta=1)', 13), ('C-NPS-F (load, delta=4)', 12), ('C-NPS-F (idle, delta=4)', 14), ] npsf_comp = [ ('NPS-F (idle, delta=1)', 9), ('C-NPS-F (idle, delta=1)', 13), ('NPS-F (idle, delta=4)', 10), ('C-NPS-F (idle, delta=4)', 14), ('NPS-F (load, delta=1)', 7), ('C-NPS-F (load, delta=1)', 11), ('NPS-F (load, delta=4)', 8), ('C-NPS-F (load, delta=4)', 12), ] edffm_titles = [ ('EDF-fm (load)', 15), ('EDF-fm (idle)', 16), ] npsf_paper = [ ('NPS-F (idle, delta=1)', 9), ('NPS-F (load, delta=1)', 7), ] paper_titles = cedf_titles + edfwm_titles + npsf_paper if self.options.alternate: # NPS-F comparison titles = npsf_comp else: # all if self.options.paper: titles = paper_titles else: titles = cedf_titles + edfwm_titles + npsf_titles + cnpsf_titles if 'soft' in conf: titles += edffm_titles if self.options.slides: # remove all idle configurations titles = [t for i, t in enumerate(titles) if i % 2 == 0] p = self.make_plot(name) p.title = scenario_heading(conf, True) if 'sched' in conf: p.ylabel = "ratio of schedulable task sets" p.xlabel = "task set utilization cap (prior to overhead accounting)" p.xticks = (0, 1) p.xrange = (0.95, 24.05) p.title += "; WSS = %skB" % conf['key'] xcol = 2 elif 'wsched' in conf: xcol = 1 p.xlabel = "working set size (WSS)" p.ylabel = "weighted schedulability" if self.options.wide: # tail plot WSS > 1024 p.xticks = (0, 256) p.xrange = (1023, 3073) elif self.options.alternate: # NPS-F comparison p.xrange = (-1, 257) p.xticks = (0, 32) else: # regular plot p.xticks = (0, 64) p.xrange = (-1, 1025) else: self.err("What kind of semipart experiment is this?") return p.curves += [curve(fname=tmpfile, xcol=xcol, ycol=idx, title=t) for (i, (t, idx)) in enumerate(titles)] p.yrange = (-0.05, 1.05) p.yticks = (0, 0.1) #### Styling. if not self.setup_png(p): p.rounded_caps = True p.font = 'Helvetica' if self.options.paper or self.options.appendix: for i, c in enumerate(p.curves): c.style = "linespoints ls %d" % (i + 1) p.line_styles = [ (1, "lw 2.5"), (2, "lw 2.5"), (3, "lw 2.5"), (4, "lw 2.5"), (5, 'lw 2.5 lc rgbcolor "#ff910d"'), (6, "lw 2.5"), (7, 'lw 2.5 lc rgbcolor "#000000"'), (8, "lw 2.5"), ] if self.options.paper: p.default_style = 'lines lw 2.5' p.font_size = '5pt' p.size = ('8.5cm', '5.25cm') p.monochrome = False p.dashed_lines = False if not self.options.alternate: p.key ='off' p.size = ('8.5cm', '5.5cm') p.yticks = (0, 0.1) p.key = 'below' p.default_style = 'linespoints lw 2.5' elif self.options.slides: p.dashed_lines = False p.monochrome = False p.rounded_caps = True p.default_style = 'lines lw 10' p.key = 'below' elif self.options.appendix: # for the appendix p.font_size = '8' if 'wsched' in conf: p.size = ('17cm', '6cm') p.key = 'off' else: p.size = ('17cm', '9cm') p.key = 'below' p.monochrome = False p.dashed_lines = False p.default_style = 'linespoints lw 1' else: p.font_size = '10' p.size = ('20cm', '10cm') p.monochrome = False p.dashed_lines = False p.key = 'below' p.default_style = 'linespoints lw 1' if self.options.smooth: p.default_style += " smooth bezier" p.ylabel += (' [soft]' if 'soft' in conf else ' [hard]') if self.options.save_script: p.gnuplot_save(p.output + '.plot') else: p.gnuplot_exec() def plot_mpcp_omlp(self, tmpfile, name, conf): curves = [ ('MPCP (virtual spinning)', 5), ('MPCP (suspension-based)', 4), ('OMLP (mutex, c=1)', 6), ] p = self.make_plot(name) if 'ucap' in conf and 'pacc' in conf: xcol = 1 p.xlabel = 'resource probability' p.xrange = (0, 1) tinfo = ' utilization=%s request-probability=%s' % \ (conf['ucap'], conf['pacc']) elif 'ucap' in conf and 'pres' in conf: xcol = 2 p.xlabel = 'request probability' p.xrange = (0, 0.8) tinfo = ' utilization=%s resource-probability=%s' % \ (conf['ucap'], conf['pres']) else: xcol = 3 p.xlabel = 'per-processor utilization (prior to blocking accounting)' p.xrange = (0.2, 1) tinfo = ' request-probability=%s resource-probability=%s' % \ (conf['pacc'], conf['pres']) pinfo = " m=%s" % conf['m'] p.title = scenario_heading(conf, True) + r'\n' + tinfo + pinfo p.ylabel = "ratio of schedulable task sets" p.yrange = (-0.05, 1.05) p.yticks = (0, 0.1) p.xticks = (0, 0.1) p.curves += [curve(fname=tmpfile, xcol=xcol, ycol=idx, title=t) for (t, idx) in curves] #### Styling. if not self.setup_png(p): p.rounded_caps = True p.font = 'Helvetica' if self.options.paper: p.default_style = 'lines lw 2.5' p.font_size = '5pt' p.size = ('8.5cm', '5.25cm') p.monochrome = False p.dashed_lines = False if not self.options.alternate: p.key ='off' p.size = ('9cm', '4.0cm') p.yticks = (0, 0.1) p.key = 'bottom left' p.default_style = 'linespoints lw 3.5' elif self.options.slides: p.dashed_lines = False p.monochrome = False p.rounded_caps = True p.default_style = 'lines lw 10' p.key = 'below' elif self.options.appendix: # for the appendix p.font_size = '8' p.size = ('17cm', '9cm') p.key = 'below' p.monochrome = False p.dashed_lines = False p.default_style = 'linespoints lw 3.5' else: p.font_size = '10' p.size = ('20cm', '10cm') p.monochrome = False p.dashed_lines = False p.key = 'below' p.default_style = 'linespoints lw 1' if self.options.smooth: p.default_style += " smooth bezier" if self.options.save_script: p.gnuplot_save(p.output + '.plot') else: p.gnuplot_exec() def plot_file(self, datafile): bname = basename(datafile) name, ext = splitext(bname) if ext != '.csv': self.err("Warning: '%s' doesn't look like a CSV file." % bname) conf = decode(name) try: if self.options.save_script: tmpfile = get_data_tmpfile(datafile, target = "%s.data" % name ) else: tmpfile = get_data_tmpfile(datafile) except IOError: tmpfile = None if tmpfile: plotters = { 'spec' : self.plot_spec, 'spec2' : self.plot_spec2, 'spec3' : self.plot_spec3, 'spec4' : self.plot_spec4, 'irq' : self.plot_irq, 'rtss08' : self.plot_rtss08, 'rtss09' : self.plot_rtss09_split if self.options.split else self.plot_rtss09, 'ospert10' : self.plot_ospert10, 'eurosys11' : self.plot_semipart, 'emsoft11-part' : self.plot_mpcp_omlp, } if self.options.experiment: # override provided plot_type = self.options.experiment else: # no type provided, try each plotter for plot_type in plotters: if plot_type in conf: break if not plot_type in conf: plot_type = 'unknown' if plot_type in plotters: plotters[plot_type](tmpfile.name, name, conf) else: self.err("Skipped '%s'; unkown experiment type." % bname) del tmpfile # removes temp file else: self.err("Skipped '%s'; it dosn't appear to contain data." % bname) def default(self, _): 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__": SchedPlotter().launch()