#!/usr/bin/env python import defapp from os.path import splitext, basename from optparse import make_option as o from tempfile import NamedTemporaryFile as Tmp import csv from plot import decode from gnuplot import gnuplot, FORMATS MACHINE_TOPOLOGY = { 'jupiter-cs' : (4, [('preempt', lambda x, y: x == y), ('mem', lambda x, y: x != y)]) } PMO_PARAM = { 'wss' : 'WSS', 'host' : 'host', 'wcycle' : 'write-cycle' } PMO_MEM = { 'mem' : 'a migration through main memory', 'preempt' : 'a preemption', 'all' : 'either a migration or preemption', } PMO_SUBPLOTS = [ # x, y, y-delta, split according to mem-hierarchy? (0, 6, None, False), (0, 7, None, False), (0, 8, None, False), (0, 9, None, False), (0, 10, None, True), (3, 10, None, True), (0, 10, 9, True), (3, 10, 9, True), ] PMO_COL_LABEL = [('measurement', 'sample', 'index'), ('write cycles', 'wcycle', 'every nth access'), ('WSS', 'wcc', 'kilobytes'), ('suspension length', 'delay', 'microseconds'), ('CPU (preempted on)', 'from', 'processor'), ('CPU (resumed on)', 'to', 'processor'), ('cold access', 'cold', 'cycles'), ('first hot access', 'hot1', 'cycles'), ('second hot access', 'hot2', 'cycles'), ('third hot access', 'hot3', 'cycles'), ('access after resuming', 'after', 'cycles') ] PMO_FROM_CPU = 4 PMO_TO_CPU = 5 options = [ o('-f', '--format', action='store', dest='format', type='choice', choices=FORMATS, help='output format'), o(None, '--paper', action='store_true', dest='paper'), o(None, '--wide', action='store_true', dest='wide'), o(None, '--split', action='store_true', dest='split'), ] defaults = { 'format' : 'show', 'paper' : False, 'split' : False, 'wide' : False, } def extract_cols(data, xcol, ycol1, ycol2, cast=int, cpu_filter=lambda x, y: True): for row in data: fcpu = int(row[PMO_FROM_CPU]) tcpu = int(row[PMO_TO_CPU]) if cpu_filter(fcpu, tcpu): if ycol2 is None: yield (row[xcol], cast(row[ycol1])) else: yield (row[xcol], cast(row[ycol1]) - cast(row[ycol2])) class CyclePlotter(defapp.App): def __init__(self): defapp.App.__init__(self, options, defaults, no_std_opts=True) def setup_pmo_graphs(self, datafile, conf): host = conf['host'] if host in MACHINE_TOPOLOGY: (cpus, hier) = MACHINE_TOPOLOGY[host] plots = [] data = list(csv.reader(open(datafile))) for (xcol, ycol, yminus, by_mem_hierarchy) in PMO_SUBPLOTS: sub = [('all', lambda x, y: True)] if by_mem_hierarchy: sub += hier for tag, test in sub: tmp = Tmp() for row in extract_cols(data, xcol, ycol, yminus, cpu_filter=test): tmp.write("%s, %s\n" % row) tmp.flush() plots.append((tmp, xcol, ycol, yminus, tag)) return plots else: self.err('Unkown host: %s' % host) return None def plot_preempt_migrate(self, datafile, name, conf): plots = self.setup_pmo_graphs(datafile, conf) for (tmp, xcol, ycol, yminus, tag) in plots: xtag = PMO_COL_LABEL[xcol][1] ytag = PMO_COL_LABEL[ycol][1] dtag = "-delta-%s" % PMO_COL_LABEL[yminus][1] if not yminus is None else "" figname = "%s_%s%s-vs-%s_%s" % (name, ytag, dtag, xtag, tag) xunit = PMO_COL_LABEL[xcol][2] yunit = PMO_COL_LABEL[ycol][2] ylabel = PMO_COL_LABEL[ycol][0] xlabel = PMO_COL_LABEL[xcol][0] title = "%s" % ylabel if ycol == 10: title += " from %s" % PMO_MEM[tag] for key in conf: if key in PMO_PARAM: title += " %s=%s" % (PMO_PARAM[key], conf[key]) gnuplot([(tmp.name, 1, 2, ylabel)], xlabel="%s (%s)" % (xlabel, xunit), ylabel="%s (%s)" % ("access cost" if yminus is None else "delta to %s" % PMO_COL_LABEL[yminus][0], yunit), title=title, style='points', format=self.options.format, fname=figname) 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) if 'pmo' in conf: self.plot_preempt_migrate(datafile, name, conf) else: self.err("Skipped '%s'; unkown experiment type." % bname) def default(self, _): for datafile in self.args: self.plot_file(datafile) if __name__ == "__main__": CyclePlotter().launch()