From 8d97233c9bc7bcbeb27c38bf7481d4831c75cf8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20B=2E=20Brandenburg?= Date: Fri, 26 Mar 2010 08:53:45 -0400 Subject: pm2: don't crash if host is unknown --- plot_pm2.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'plot_pm2.py') diff --git a/plot_pm2.py b/plot_pm2.py index d53a6da..fd3270e 100755 --- a/plot_pm2.py +++ b/plot_pm2.py @@ -108,6 +108,9 @@ class CyclePlotter(defapp.App): def plot_preempt_migrate(self, datafile, name, conf): plots = self.setup_pmo_graphs(datafile, conf) + if plots is None: + print "Skipping %s..." % datafile + return for (tmp, xcol, ycol, yminus, tag) in plots: xtag = PMO_COL_LABEL[xcol][1] ytag = PMO_COL_LABEL[ycol][1] -- cgit v1.2.2 From 174498f1daa9ccd46323c63b030175e4646afcd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20B=2E=20Brandenburg?= Date: Fri, 26 Mar 2010 09:47:52 -0400 Subject: Add Ludwig machine topology based on Andrea's diagram. --- plot_pm2.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'plot_pm2.py') diff --git a/plot_pm2.py b/plot_pm2.py index fd3270e..d7d6536 100755 --- a/plot_pm2.py +++ b/plot_pm2.py @@ -10,8 +10,26 @@ 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)]) + 'jupiter-cs' : (4, [('preempt', lambda x, y: x == y), + ('mem', lambda x, y: x != y)]), + + # Socket0 Socket1 Socket2 Socket3 + # ------ ------- ------- ------- + # | 0, 4| | 1, 5| | 2, 6| | 3, 7| + # | 8,12| | 9,13| |10,14| |11,15| + # |16,20| |17,21| |18,22| |19,23| + # ------- ------- ------- ------- + 'ludwig.cs.unc.edu' : (24, [('preempt', lambda x, y: x == y), + ('l2', + lambda x, y: abs(y - x) == 4), + ('l3', + lambda x, y: + abs(y - x) > 4 and \ + abs(y - x) % 4 == 0), + ('mem', lambda x, y: abs(y - x) % 4 != 0)]) } PMO_PARAM = { @@ -22,6 +40,8 @@ PMO_PARAM = { PMO_MEM = { 'mem' : 'a migration through main memory', + 'l3' : 'a migration through a shared L3 cache', + 'l2' : 'a migration through a shared L2 cache', 'preempt' : 'a preemption', 'all' : 'either a migration or preemption', } -- cgit v1.2.2 From 4c52a0fd68f117669f79cdd89848db3581349c0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20B=2E=20Brandenburg?= Date: Fri, 26 Mar 2010 14:56:12 -0400 Subject: Switch to numpy-based loading and plot outlier thresholds. --- plot_pm2.py | 50 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 18 deletions(-) (limited to 'plot_pm2.py') diff --git a/plot_pm2.py b/plot_pm2.py index d7d6536..866b4b2 100755 --- a/plot_pm2.py +++ b/plot_pm2.py @@ -1,10 +1,13 @@ #!/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 +import numpy as np +from util import load_csv_file, select + +import stats +import defapp from plot import decode from gnuplot import gnuplot, FORMATS @@ -80,6 +83,7 @@ options = [ o(None, '--paper', action='store_true', dest='paper'), o(None, '--wide', action='store_true', dest='wide'), o(None, '--split', action='store_true', dest='split'), + o(None, '--extend', action='store', type='float', dest='extend'), ] defaults = { @@ -87,17 +91,16 @@ defaults = { 'paper' : False, 'split' : False, 'wide' : False, + 'extend' : 1.5, } 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])) + def matching_cpus(row): + return cpu_filter(row[PMO_FROM_CPU], row[PMO_TO_CPU]) + rows = select(matching_cpus, data) + if not (ycol2 is None): + rows[:,ycol1] -= rows[:,ycol2] + return rows[:,(xcol, ycol1)] class CyclePlotter(defapp.App): def __init__(self): @@ -108,19 +111,20 @@ class CyclePlotter(defapp.App): if host in MACHINE_TOPOLOGY: (cpus, hier) = MACHINE_TOPOLOGY[host] plots = [] - data = list(csv.reader(open(datafile))) + data = load_csv_file(datafile, dtype=int) 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) + rows = extract_cols(data, + xcol, ycol, yminus, + cpu_filter=test) + for row in rows: + tmp.write("%s, %s\n" % (row[0], row[1])) tmp.flush() - plots.append((tmp, xcol, ycol, yminus, tag)) + plots.append((tmp, xcol, ycol, yminus, tag, rows)) return plots else: self.err('Unkown host: %s' % host) @@ -131,7 +135,7 @@ class CyclePlotter(defapp.App): if plots is None: print "Skipping %s..." % datafile return - for (tmp, xcol, ycol, yminus, tag) in plots: + for (tmp, xcol, ycol, yminus, tag, rows) 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 "" @@ -143,10 +147,20 @@ class CyclePlotter(defapp.App): title = "%s" % ylabel if ycol == 10: title += " from %s" % PMO_MEM[tag] + title += "\\n" for key in conf: if key in PMO_PARAM: title += " %s=%s" % (PMO_PARAM[key], conf[key]) - gnuplot([(tmp.name, 1, 2, ylabel)], + graphs = [(tmp.name, 1, 2, ylabel)] + # plot cutoff + (s, lo, hi) = stats.iqr(rows[:,1]) + lo -= s * self.options.extend + hi += s * self.options.extend + m99 = stats.cutoff_max(rows[:, 1]) + graphs += [(lo, 'IQR cutoff (%d)' % lo, 'line'), + (hi, 'IQR cutoff (%d)' % hi, 'line'), + (m99,'99%% cutoff (%d)' % m99, 'line lw 2')] + gnuplot(graphs, xlabel="%s (%s)" % (xlabel, xunit), ylabel="%s (%s)" % ("access cost" if yminus is None else "delta to %s" % PMO_COL_LABEL[yminus][0], -- cgit v1.2.2 From 137365d1ea9c736f67184b6ed0bb683326a55243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20B=2E=20Brandenburg?= Date: Sat, 27 Mar 2010 11:46:37 -0400 Subject: First steps in aggregate plotting. --- plot_pm2.py | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 130 insertions(+), 9 deletions(-) (limited to 'plot_pm2.py') diff --git a/plot_pm2.py b/plot_pm2.py index 866b4b2..3c0174d 100755 --- a/plot_pm2.py +++ b/plot_pm2.py @@ -3,6 +3,8 @@ from os.path import splitext, basename from optparse import make_option as o from tempfile import NamedTemporaryFile as Tmp +from collections import defaultdict + import numpy as np from util import load_csv_file, select @@ -61,6 +63,19 @@ PMO_SUBPLOTS = [ (3, 10, 9, True), ] +PMO_AGGR_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), + (0, 10, 6, True), + (0, 10, 7, True), + (0, 10, 9, True), + (0, 10, 8, True), +] + PMO_COL_LABEL = [('measurement', 'sample', 'index'), ('write cycles', 'wcycle', 'every nth access'), ('WSS', 'wcc', 'kilobytes'), @@ -84,6 +99,7 @@ options = [ o(None, '--wide', action='store_true', dest='wide'), o(None, '--split', action='store_true', dest='split'), o(None, '--extend', action='store', type='float', dest='extend'), + o(None, '--aggregate', action='store_true', dest='aggregate'), ] defaults = { @@ -91,6 +107,7 @@ defaults = { 'paper' : False, 'split' : False, 'wide' : False, + 'aggregate' : False, 'extend' : 1.5, } @@ -105,37 +122,94 @@ def extract_cols(data, xcol, ycol1, ycol2, cast=int, cpu_filter=lambda x, y: Tru class CyclePlotter(defapp.App): def __init__(self): defapp.App.__init__(self, options, defaults, no_std_opts=True) + self.aggregate_data = [] - def setup_pmo_graphs(self, datafile, conf): + def setup_pmo_graphs(self, datafile, conf, subplots=PMO_SUBPLOTS): host = conf['host'] if host in MACHINE_TOPOLOGY: (cpus, hier) = MACHINE_TOPOLOGY[host] plots = [] data = load_csv_file(datafile, dtype=int) - for (xcol, ycol, yminus, by_mem_hierarchy) in PMO_SUBPLOTS: + for (xcol, ycol, yminus, by_mem_hierarchy) in subplots: sub = [('all', lambda x, y: True)] if by_mem_hierarchy: sub += hier for tag, test in sub: - tmp = Tmp() rows = extract_cols(data, xcol, ycol, yminus, cpu_filter=test) - for row in rows: - tmp.write("%s, %s\n" % (row[0], row[1])) - tmp.flush() - plots.append((tmp, xcol, ycol, yminus, tag, rows)) + plots.append((rows, xcol, ycol, yminus, tag)) return plots else: self.err('Unkown host: %s' % host) return None + def write_aggregate(self, datafiles): + # (wss, avg, wc, #avg, #wc) + # by tag -> by wcycle -> list of data points) + by_tag = defaultdict(lambda: defaultdict(list)) + + for i, datafile in enumerate(datafiles): + print '[%d/%d] Processing %s...' % (i + 1, len(datafiles), 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: + plots = self.setup_pmo_graphs(datafile, conf, PMO_AGGR_SUBPLOTS) + if plots is None: + print "Skipping %s..." % datafile + return + wss = int(conf['wss']) + wcycle = int(conf['wcycle']) + host = conf['host'] + for (rows, xcol, ycol, yminus, tag) in plots: + clean = stats.iqr_remove_outliers(rows, extend=self.options.extend) + vals = clean[:,1] + avg = np.mean(vals) + std = np.std(vals, ddof=1) + wc = np.max(vals) + n = len(vals) + + 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 "" + code = "code=%s-%s-%s-%s" % \ + (xcol, ycol, yminus, tag) + figname = "host=%s_%s%s-vs-%s_%s_%s" % \ + (host, ytag, dtag, xtag, tag, code) + by_tag[figname][wcycle].append((wss, avg, std, wc, n, len(rows) - n)) + del plots + else: + self.err("Warning: '%s' is not a PMO experiment; skipping." % bname) + + for figname in by_tag: + for wcycle in by_tag[figname]: + data = by_tag[figname][wcycle] + # sort by increasing WSS + data.sort(key=lambda row: row[0]) + f = open('pmo-aggr_wcycle=%d_%s.csv' % (wcycle, figname), 'w') + for row in data: + f.write(", ".join([str(x) for x in row])) + f.write('\n') + f.close() + def plot_preempt_migrate(self, datafile, name, conf): plots = self.setup_pmo_graphs(datafile, conf) if plots is None: print "Skipping %s..." % datafile return - for (tmp, xcol, ycol, yminus, tag, rows) in plots: + else: + print 'Plotting %s...' % datafile + for (rows, xcol, ycol, yminus, tag) in plots: + # Write it to a temp file. + tmp = Tmp() + for row in rows: + tmp.write("%s, %s\n" % (row[0], row[1])) + tmp.flush() + 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 "" @@ -147,7 +221,6 @@ class CyclePlotter(defapp.App): title = "%s" % ylabel if ycol == 10: title += " from %s" % PMO_MEM[tag] - title += "\\n" for key in conf: if key in PMO_PARAM: title += " %s=%s" % (PMO_PARAM[key], conf[key]) @@ -169,6 +242,49 @@ class CyclePlotter(defapp.App): style='points', format=self.options.format, fname=figname) + del tmp # delete temporary file + + def plot_pmo_aggr(self, datafile, name, conf): + fname = datafile + code = conf['code'] + (xcol, ycol, yminus, tag) = code.split('-') + + xcol = int(xcol) + ycol = int(ycol) + if yminus != "None": + yminus = int(ycol) + else: + yminus = None + + 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 + + ylabel="%s (%s)" % ("access cost" if yminus is None + else "delta to %s" % PMO_COL_LABEL[yminus][0], + yunit), + 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]) + + graphs = [ + #(fname, 1, 2, "average"), + "'%s' using 1:2:3 title 'average' with errorbars" % (fname), + (fname, 1, 4, "maximum"), + ] + xlabel = "working set size (kilobytes)" + + gnuplot(graphs, xlabel=xlabel, ylabel=ylabel, title=title, fname=figname, + logscale="xy 2" if yminus is None else "x 2", + format=self.options.format) def plot_file(self, datafile): bname = basename(datafile) @@ -179,6 +295,8 @@ class CyclePlotter(defapp.App): conf = decode(name) if 'pmo' in conf: self.plot_preempt_migrate(datafile, name, conf) + elif 'pmo-aggr' in conf: + self.plot_pmo_aggr(datafile, name, conf) else: self.err("Skipped '%s'; unkown experiment type." % bname) @@ -187,5 +305,8 @@ class CyclePlotter(defapp.App): for datafile in self.args: self.plot_file(datafile) + def do_aggregate(self, _): + self.write_aggregate(self.args[1:]) + if __name__ == "__main__": CyclePlotter().launch() -- cgit v1.2.2 From 031d41687127b7eb074229dbc114eb52340472c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20B=2E=20Brandenburg?= Date: Sat, 27 Mar 2010 20:10:00 -0400 Subject: More work on aggregate plotting. --- plot_pm2.py | 196 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 175 insertions(+), 21 deletions(-) (limited to 'plot_pm2.py') diff --git a/plot_pm2.py b/plot_pm2.py index 3c0174d..1332825 100755 --- a/plot_pm2.py +++ b/plot_pm2.py @@ -4,9 +4,10 @@ from optparse import make_option as o from tempfile import NamedTemporaryFile as Tmp from collections import defaultdict +from itertools import izip import numpy as np -from util import load_csv_file, select +from util import * import stats import defapp @@ -70,10 +71,14 @@ PMO_AGGR_SUBPLOTS = [ (0, 8, None, False), (0, 9, None, False), (0, 10, None, True), - (0, 10, 6, True), - (0, 10, 7, True), +# (0, 10, 6, True), +# (0, 10, 7, True), +# (0, 10, 8, True), (0, 10, 9, True), - (0, 10, 8, True), +] + +PMO_AGGR_COMBINE = [ + [(6, 'all'), (7, 'all'), (8, 'all'), (9, 'all')] ] PMO_COL_LABEL = [('measurement', 'sample', 'index'), @@ -100,6 +105,7 @@ options = [ o(None, '--split', action='store_true', dest='split'), o(None, '--extend', action='store', type='float', dest='extend'), o(None, '--aggregate', action='store_true', dest='aggregate'), + o('-c', '--cycles-per-usec', action='store', type='float', dest='cycles_per_usec'), ] defaults = { @@ -109,6 +115,7 @@ defaults = { 'wide' : False, 'aggregate' : False, 'extend' : 1.5, + 'cycles_per_usec' : None, } def extract_cols(data, xcol, ycol1, ycol2, cast=int, cpu_filter=lambda x, y: True): @@ -149,6 +156,8 @@ class CyclePlotter(defapp.App): # by tag -> by wcycle -> list of data points) by_tag = defaultdict(lambda: defaultdict(list)) + host = None + for i, datafile in enumerate(datafiles): print '[%d/%d] Processing %s...' % (i + 1, len(datafiles), datafile) bname = basename(datafile) @@ -162,9 +171,14 @@ class CyclePlotter(defapp.App): if plots is None: print "Skipping %s..." % datafile return + if not host: + host = conf['host'] + if host != conf['host']: + self.err('Mixing data from two hosts! (%s, %s)' % (host, conf['host'])) + self.err('Aborting.') + return wss = int(conf['wss']) wcycle = int(conf['wcycle']) - host = conf['host'] for (rows, xcol, ycol, yminus, tag) in plots: clean = stats.iqr_remove_outliers(rows, extend=self.options.extend) vals = clean[:,1] @@ -173,28 +187,64 @@ class CyclePlotter(defapp.App): wc = np.max(vals) n = len(vals) - 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 "" - code = "code=%s-%s-%s-%s" % \ - (xcol, ycol, yminus, tag) - figname = "host=%s_%s%s-vs-%s_%s_%s" % \ - (host, ytag, dtag, xtag, tag, code) - by_tag[figname][wcycle].append((wss, avg, std, wc, n, len(rows) - n)) + key = (xcol, ycol, yminus, tag) + by_tag[key][wcycle].append((wss, avg, std, wc, n, len(rows) - n)) del plots else: self.err("Warning: '%s' is not a PMO experiment; skipping." % bname) - for figname in by_tag: - for wcycle in by_tag[figname]: - data = by_tag[figname][wcycle] + all_wss = set() + all_wcycle = set() + + for key in by_tag: + for wcycle in by_tag[key]: + all_wcycle.add(wcycle) + + data = by_tag[key][wcycle] # sort by increasing WSS data.sort(key=lambda row: row[0]) - f = open('pmo-aggr_wcycle=%d_%s.csv' % (wcycle, figname), 'w') for row in data: - f.write(", ".join([str(x) for x in row])) - f.write('\n') - f.close() + all_wss.add(row[0]) + + (xcol, ycol, yminus, tag) = key + + 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 "" + code = "code=%s-%s-%s-%s" % key + figname = "host=%s_%s%s-vs-%s_%s_%s" % \ + (host, ytag, dtag, xtag, tag, code) + + write_csv_file('pmo-aggr_wcycle=%d_%s.csv' % (wcycle, figname), data) + + + mems = [tag for (tag, _) in MACHINE_TOPOLOGY[host][1]] + + for wcycle in all_wcycle: + try: + rows = [[wss] for wss in sorted(all_wss)] + header = ['wss'] + for (x, y, yminus, split) in PMO_AGGR_SUBPLOTS: + tags = ['all'] + if split: + tags += mems + for tag in tags: + col_name = "%s %s" % (PMO_COL_LABEL[ycol][1], tag) + if not yminus is None: + col_name += ' - ' + PMO_COL_LABEL[yminus][1] + header += [col_name + " avg", col_name + " std", col_name + " wc"] + key = (x, y, yminus, tag) + data = by_tag[key][wcycle] + for r, d in izip(rows, data): + if r[0] != d[0]: + print "mismatch", r[0], d[0], key, wcycle + assert r[0] == d[0] # working set size must match + r += d[1:4] # (average, std, wc) + write_csv_file('pmo-all_wcycle=%d_host=%s.csv' % (wcycle, host), + rows, header, width=max([len(h) for h in header])) + except AssertionError: + self.err("Data missing for wcycle=%d!" % wcycle) + def plot_preempt_migrate(self, datafile, name, conf): plots = self.setup_pmo_graphs(datafile, conf) @@ -259,7 +309,7 @@ class CyclePlotter(defapp.App): 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) + figname = name #"%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] @@ -282,10 +332,112 @@ class CyclePlotter(defapp.App): ] xlabel = "working set size (kilobytes)" + yrange = (4096, 2**26) if yminus is None else None + gnuplot(graphs, xlabel=xlabel, ylabel=ylabel, title=title, fname=figname, + yrange=yrange, logscale="xy 2" if yminus is None else "x 2", format=self.options.format) + def plot_pmo_all(self, datafile, name, conf): + host = conf['host'] + mems = [tag for (tag, _) in MACHINE_TOPOLOGY[host][1]] + columns = [] + idx = 2 + for (x, y, yminus, split) in PMO_AGGR_SUBPLOTS: + tags = ['all'] + if split: + tags += mems + for tag in tags: + columns.append((x, y, yminus, tag, idx)) + idx += 3 + + data = load_csv_file(datafile) + if self.options.cycles_per_usec: + yunit = "(us)" + data[:, 1:] /= self.options.cycles_per_usec + else: + yunit = "(cycles)" + tmp = write_csv_file(None, data) + + rw = int(conf['wcycle']) + rw = 1.0 / rw * 100 if rw != 0 else 0 + + # raw measures + for offset, kind, long in [(0, 'avg', 'average'), (2, 'wc', 'maximum')]: + graphs = [] + for (x, y, yminus, tag, idx) in columns: + if yminus is None: + label = PMO_COL_LABEL[y][0] + if y == 10: + label += " from %s" % PMO_MEM[tag] + graphs += [ + (tmp.name, 1, idx + offset, label), + ] + xlabel = "working set size (kilobytes)" + ylabel = "time to complete access " + yunit + title = "measured %s WSS access time (%.2f%% writes)" % (long, rw) + yrange = None #(4096, 2**26) + + fname = "%s_full_%s" % (name, kind) + gnuplot(graphs, xlabel=xlabel, ylabel=ylabel, title=title, fname=fname, + yrange=yrange, logscale=("x 2", "y 10"), format=self.options.format) + + # per-sample delta measures + for offset, kind, long in [(0, 'avg', 'average'), (2, 'wc', 'maximum')]: + graphs = [] + for (x, y, yminus, tag, idx) in columns: + if not (yminus is None) and tag != 'all': + label = "%s" % PMO_MEM[tag] + graphs += [ + (tmp.name, 1, idx + offset, label), + ] + xlabel = "working set size (kilobytes)" + ylabel = "per-sample delta to hot access " + yunit + title = "measured %s overhead (%.2f%% writes)" % (long, rw) + yrange = None + + fname = "%s_delta_%s" % (name, kind) + gnuplot(graphs, xlabel=xlabel, ylabel=ylabel, title=title, fname=fname, + yrange=yrange, logscale=("x 2", "y 10"), format=self.options.format) + del tmp + + # stats delta + # find hot column + col = None + for (x, y, yminus, tag, idx) in columns: + if x == 0 and y == 9 and yminus is None and tag == 'all': + col = idx + break + # normalize based on third hot access + # +1/-1 to get zero-based indices; Gnuplot wants 1-based indices + hot_avg = data[:,col - 1].copy() + hot_wc = data[:,col + 1].copy() + for (x, y, yminus, tag, idx) in columns: + data[:,idx - 1] -= hot_avg + data[:,idx + 1] -= hot_wc + + tmp = write_csv_file(None, data) + + for offset, kind, long in [(0, 'avg', 'average'), (2, 'wc', 'maximum')]: + graphs = [] + for (x, y, yminus, tag, idx) in columns: + if yminus is None and tag != 'all': + label = PMO_COL_LABEL[y][0] + label = PMO_MEM[tag] + graphs += [ + (tmp.name, 1, idx + offset, label), + ] + xlabel = "working set size (kilobytes)" + ylabel = "delta to third hot access " + yunit + title = "difference of %s access costs (%.2f%% writes)" % (long, rw) + yrange = None + + fname = "%s_diff_%s" % (name, kind) + gnuplot(graphs, xlabel=xlabel, ylabel=ylabel, title=title, fname=fname, + yrange=yrange, logscale=("x 2", "y 10"), format=self.options.format) + del tmp + def plot_file(self, datafile): bname = basename(datafile) name, ext = splitext(bname) @@ -297,6 +449,8 @@ class CyclePlotter(defapp.App): self.plot_preempt_migrate(datafile, name, conf) elif 'pmo-aggr' in conf: self.plot_pmo_aggr(datafile, name, conf) + elif 'pmo-all' in conf: + self.plot_pmo_all(datafile, name, conf) else: self.err("Skipped '%s'; unkown experiment type." % bname) -- cgit v1.2.2 From 4bff8dc35059f69e79d75b679a0e28cca5322785 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20B=2E=20Brandenburg?= Date: Sat, 27 Mar 2010 20:18:17 -0400 Subject: make y-axis logarithmic on demand --- plot_pm2.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'plot_pm2.py') diff --git a/plot_pm2.py b/plot_pm2.py index 1332825..09b2d49 100755 --- a/plot_pm2.py +++ b/plot_pm2.py @@ -103,6 +103,7 @@ options = [ o(None, '--paper', action='store_true', dest='paper'), o(None, '--wide', action='store_true', dest='wide'), o(None, '--split', action='store_true', dest='split'), + o(None, '--log-y', action='store_true', dest='logy'), o(None, '--extend', action='store', type='float', dest='extend'), o(None, '--aggregate', action='store_true', dest='aggregate'), o('-c', '--cycles-per-usec', action='store', type='float', dest='cycles_per_usec'), @@ -116,6 +117,7 @@ defaults = { 'aggregate' : False, 'extend' : 1.5, 'cycles_per_usec' : None, + 'logy' : False, } def extract_cols(data, xcol, ycol1, ycol2, cast=int, cpu_filter=lambda x, y: True): @@ -363,6 +365,11 @@ class CyclePlotter(defapp.App): rw = int(conf['wcycle']) rw = 1.0 / rw * 100 if rw != 0 else 0 + if self.options.logy: + axis = ("x 2", "y 10") + else: + axis = "x 2" + # raw measures for offset, kind, long in [(0, 'avg', 'average'), (2, 'wc', 'maximum')]: graphs = [] @@ -380,8 +387,9 @@ class CyclePlotter(defapp.App): yrange = None #(4096, 2**26) fname = "%s_full_%s" % (name, kind) + gnuplot(graphs, xlabel=xlabel, ylabel=ylabel, title=title, fname=fname, - yrange=yrange, logscale=("x 2", "y 10"), format=self.options.format) + yrange=yrange, logscale=axis, format=self.options.format) # per-sample delta measures for offset, kind, long in [(0, 'avg', 'average'), (2, 'wc', 'maximum')]: @@ -399,7 +407,7 @@ class CyclePlotter(defapp.App): fname = "%s_delta_%s" % (name, kind) gnuplot(graphs, xlabel=xlabel, ylabel=ylabel, title=title, fname=fname, - yrange=yrange, logscale=("x 2", "y 10"), format=self.options.format) + yrange=yrange, logscale=axis, format=self.options.format) del tmp # stats delta @@ -435,7 +443,7 @@ class CyclePlotter(defapp.App): fname = "%s_diff_%s" % (name, kind) gnuplot(graphs, xlabel=xlabel, ylabel=ylabel, title=title, fname=fname, - yrange=yrange, logscale=("x 2", "y 10"), format=self.options.format) + yrange=yrange, logscale=axis, format=self.options.format) del tmp def plot_file(self, datafile): -- cgit v1.2.2 From 98ce8d88ca3d8476759c006a9ba8262beb045c5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20B=2E=20Brandenburg?= Date: Sun, 28 Mar 2010 00:20:56 -0400 Subject: improve pm2 plotter: - error bars - hot vs. hot error - keep aggregate CSVs around. --- plot_pm2.py | 58 ++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 14 deletions(-) (limited to 'plot_pm2.py') diff --git a/plot_pm2.py b/plot_pm2.py index 09b2d49..40e6a63 100755 --- a/plot_pm2.py +++ b/plot_pm2.py @@ -13,7 +13,7 @@ import stats import defapp from plot import decode -from gnuplot import gnuplot, FORMATS +from gnuplot import gnuplot, FileGraph, FORMATS @@ -75,6 +75,8 @@ PMO_AGGR_SUBPLOTS = [ # (0, 10, 7, True), # (0, 10, 8, True), (0, 10, 9, True), + (0, 8, 7, False), # difference of second to first hot access + (0, 9, 8, False), # difference of third to second hot access ] PMO_AGGR_COMBINE = [ @@ -104,6 +106,7 @@ options = [ o(None, '--wide', action='store_true', dest='wide'), o(None, '--split', action='store_true', dest='split'), o(None, '--log-y', action='store_true', dest='logy'), + o(None, '--errorbar', action='store_true', dest='errbar'), o(None, '--extend', action='store', type='float', dest='extend'), o(None, '--aggregate', action='store_true', dest='aggregate'), o('-c', '--cycles-per-usec', action='store', type='float', dest='cycles_per_usec'), @@ -117,7 +120,8 @@ defaults = { 'aggregate' : False, 'extend' : 1.5, 'cycles_per_usec' : None, - 'logy' : False, + 'logy' : False, + 'errbar' : False, } def extract_cols(data, xcol, ycol1, ycol2, cast=int, cpu_filter=lambda x, y: True): @@ -346,11 +350,16 @@ class CyclePlotter(defapp.App): mems = [tag for (tag, _) in MACHINE_TOPOLOGY[host][1]] columns = [] idx = 2 + header = ["wss"] for (x, y, yminus, split) in PMO_AGGR_SUBPLOTS: tags = ['all'] if split: tags += mems for tag in tags: + col_name = "%s %s" % (PMO_COL_LABEL[y][1], tag) + if not yminus is None: + col_name += ' - ' + PMO_COL_LABEL[yminus][1] + header += [col_name + " avg", col_name + " std", col_name + " wc"] columns.append((x, y, yminus, tag, idx)) idx += 3 @@ -360,7 +369,10 @@ class CyclePlotter(defapp.App): data[:, 1:] /= self.options.cycles_per_usec else: yunit = "(cycles)" - tmp = write_csv_file(None, data) + + csvfile = "xxx-%s" % datafile + + write_csv_file(csvfile, data, header, width=max([len(h) for h in header])) rw = int(conf['wcycle']) rw = 1.0 / rw * 100 if rw != 0 else 0 @@ -378,9 +390,10 @@ class CyclePlotter(defapp.App): label = PMO_COL_LABEL[y][0] if y == 10: label += " from %s" % PMO_MEM[tag] - graphs += [ - (tmp.name, 1, idx + offset, label), - ] + graphs.append( + FileGraph( + csvfile, xcol=1, ycol=idx + offset, title=label, + error=idx + offset + 1 if kind == 'avg' and self.options.errbar else None)) xlabel = "working set size (kilobytes)" ylabel = "time to complete access " + yunit title = "measured %s WSS access time (%.2f%% writes)" % (long, rw) @@ -397,9 +410,10 @@ class CyclePlotter(defapp.App): for (x, y, yminus, tag, idx) in columns: if not (yminus is None) and tag != 'all': label = "%s" % PMO_MEM[tag] - graphs += [ - (tmp.name, 1, idx + offset, label), - ] + graphs.append( + FileGraph( + csvfile, xcol=1, ycol=idx + offset, title=label, + error=idx + offset + 1 if kind == 'avg' and self.options.errbar else None)) xlabel = "working set size (kilobytes)" ylabel = "per-sample delta to hot access " + yunit title = "measured %s overhead (%.2f%% writes)" % (long, rw) @@ -408,7 +422,25 @@ class CyclePlotter(defapp.App): fname = "%s_delta_%s" % (name, kind) gnuplot(graphs, xlabel=xlabel, ylabel=ylabel, title=title, fname=fname, yrange=yrange, logscale=axis, format=self.options.format) - del tmp + + graphs = [] + for (x, y, yminus, tag, idx) in columns: + if y in [8, 9] and yminus in [7, 8] and tag == 'all': + label = "%s to %s" % (PMO_COL_LABEL[yminus][0], PMO_COL_LABEL[y][0]) + graphs.append( + FileGraph( + csvfile, xcol=1, ycol=idx + offset, title=label, + error=idx + offset + 1 if kind == 'avg' and self.options.errbar else None)) + xlabel = "working set size (kilobytes)" + ylabel = "per-sample delta to previous hot access " + yunit + title = "measured %s differences (%.2f%% writes)" % (long, rw) + yrange = None + + fname = "%s_delta-h_%s" % (name, kind) + gnuplot(graphs, xlabel=xlabel, ylabel=ylabel, title=title, fname=fname, + yrange=yrange, logscale=axis, format=self.options.format) + +# del tmp # stats delta # find hot column @@ -433,9 +465,7 @@ class CyclePlotter(defapp.App): if yminus is None and tag != 'all': label = PMO_COL_LABEL[y][0] label = PMO_MEM[tag] - graphs += [ - (tmp.name, 1, idx + offset, label), - ] + graphs.append(FileGraph(tmp.name, xcol=1, ycol=idx+offset, title=label)) xlabel = "working set size (kilobytes)" ylabel = "delta to third hot access " + yunit title = "difference of %s access costs (%.2f%% writes)" % (long, rw) @@ -444,7 +474,7 @@ class CyclePlotter(defapp.App): fname = "%s_diff_%s" % (name, kind) gnuplot(graphs, xlabel=xlabel, ylabel=ylabel, title=title, fname=fname, yrange=yrange, logscale=axis, format=self.options.format) - del tmp +# del tmp def plot_file(self, datafile): bname = basename(datafile) -- cgit v1.2.2 From de8026e4f74d56b6b1a88e09a9dcc155525d7b6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20B=2E=20Brandenburg?= Date: Sun, 28 Mar 2010 01:40:53 -0400 Subject: Fix stupid, stupid bug that assigned some samples incorrectly to L2 sharing. --- plot_pm2.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'plot_pm2.py') diff --git a/plot_pm2.py b/plot_pm2.py index 40e6a63..c2fcbf3 100755 --- a/plot_pm2.py +++ b/plot_pm2.py @@ -17,6 +17,19 @@ from gnuplot import gnuplot, FileGraph, FORMATS +def ludwig_l2(x, y): + # x left column, y right column, or # y left column, x, right column + return (x % 8 < 4 and x + 4 == y) or \ + (y % 8 < 4 and x - 4 == y) + +def ludwig_l3(x, y): + # same socket + # not a a shared L2 + # not identical + return (y % 4) == (x % 4) and \ + not ludwig_l2(x, y) and \ + x != y + MACHINE_TOPOLOGY = { 'jupiter-cs' : (4, [('preempt', lambda x, y: x == y), @@ -29,12 +42,8 @@ MACHINE_TOPOLOGY = { # |16,20| |17,21| |18,22| |19,23| # ------- ------- ------- ------- 'ludwig.cs.unc.edu' : (24, [('preempt', lambda x, y: x == y), - ('l2', - lambda x, y: abs(y - x) == 4), - ('l3', - lambda x, y: - abs(y - x) > 4 and \ - abs(y - x) % 4 == 0), + ('l2', ludwig_l2), + ('l3', ludwig_l3), ('mem', lambda x, y: abs(y - x) % 4 != 0)]) } -- cgit v1.2.2