diff options
author | Björn B. Brandenburg <bbb@cs.unc.edu> | 2010-03-27 11:46:37 -0400 |
---|---|---|
committer | Björn B. Brandenburg <bbb@cs.unc.edu> | 2010-03-27 11:46:37 -0400 |
commit | 137365d1ea9c736f67184b6ed0bb683326a55243 (patch) | |
tree | de589a286e99f460c559184a21bb10c9fa4a88df | |
parent | ebb62de88cf64ba87bcb332625cc9d75a88c7257 (diff) |
First steps in aggregate plotting.
-rwxr-xr-x | plot_pm2.py | 139 |
1 files changed, 130 insertions, 9 deletions
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 | |||
3 | from optparse import make_option as o | 3 | from optparse import make_option as o |
4 | from tempfile import NamedTemporaryFile as Tmp | 4 | from tempfile import NamedTemporaryFile as Tmp |
5 | 5 | ||
6 | from collections import defaultdict | ||
7 | |||
6 | import numpy as np | 8 | import numpy as np |
7 | from util import load_csv_file, select | 9 | from util import load_csv_file, select |
8 | 10 | ||
@@ -61,6 +63,19 @@ PMO_SUBPLOTS = [ | |||
61 | (3, 10, 9, True), | 63 | (3, 10, 9, True), |
62 | ] | 64 | ] |
63 | 65 | ||
66 | PMO_AGGR_SUBPLOTS = [ | ||
67 | # x, y, y-delta, split according to mem-hierarchy? | ||
68 | (0, 6, None, False), | ||
69 | (0, 7, None, False), | ||
70 | (0, 8, None, False), | ||
71 | (0, 9, None, False), | ||
72 | (0, 10, None, True), | ||
73 | (0, 10, 6, True), | ||
74 | (0, 10, 7, True), | ||
75 | (0, 10, 9, True), | ||
76 | (0, 10, 8, True), | ||
77 | ] | ||
78 | |||
64 | PMO_COL_LABEL = [('measurement', 'sample', 'index'), | 79 | PMO_COL_LABEL = [('measurement', 'sample', 'index'), |
65 | ('write cycles', 'wcycle', 'every nth access'), | 80 | ('write cycles', 'wcycle', 'every nth access'), |
66 | ('WSS', 'wcc', 'kilobytes'), | 81 | ('WSS', 'wcc', 'kilobytes'), |
@@ -84,6 +99,7 @@ options = [ | |||
84 | o(None, '--wide', action='store_true', dest='wide'), | 99 | o(None, '--wide', action='store_true', dest='wide'), |
85 | o(None, '--split', action='store_true', dest='split'), | 100 | o(None, '--split', action='store_true', dest='split'), |
86 | o(None, '--extend', action='store', type='float', dest='extend'), | 101 | o(None, '--extend', action='store', type='float', dest='extend'), |
102 | o(None, '--aggregate', action='store_true', dest='aggregate'), | ||
87 | ] | 103 | ] |
88 | 104 | ||
89 | defaults = { | 105 | defaults = { |
@@ -91,6 +107,7 @@ defaults = { | |||
91 | 'paper' : False, | 107 | 'paper' : False, |
92 | 'split' : False, | 108 | 'split' : False, |
93 | 'wide' : False, | 109 | 'wide' : False, |
110 | 'aggregate' : False, | ||
94 | 'extend' : 1.5, | 111 | 'extend' : 1.5, |
95 | } | 112 | } |
96 | 113 | ||
@@ -105,37 +122,94 @@ def extract_cols(data, xcol, ycol1, ycol2, cast=int, cpu_filter=lambda x, y: Tru | |||
105 | class CyclePlotter(defapp.App): | 122 | class CyclePlotter(defapp.App): |
106 | def __init__(self): | 123 | def __init__(self): |
107 | defapp.App.__init__(self, options, defaults, no_std_opts=True) | 124 | defapp.App.__init__(self, options, defaults, no_std_opts=True) |
125 | self.aggregate_data = [] | ||
108 | 126 | ||
109 | def setup_pmo_graphs(self, datafile, conf): | 127 | def setup_pmo_graphs(self, datafile, conf, subplots=PMO_SUBPLOTS): |
110 | host = conf['host'] | 128 | host = conf['host'] |
111 | if host in MACHINE_TOPOLOGY: | 129 | if host in MACHINE_TOPOLOGY: |
112 | (cpus, hier) = MACHINE_TOPOLOGY[host] | 130 | (cpus, hier) = MACHINE_TOPOLOGY[host] |
113 | plots = [] | 131 | plots = [] |
114 | data = load_csv_file(datafile, dtype=int) | 132 | data = load_csv_file(datafile, dtype=int) |
115 | for (xcol, ycol, yminus, by_mem_hierarchy) in PMO_SUBPLOTS: | 133 | for (xcol, ycol, yminus, by_mem_hierarchy) in subplots: |
116 | sub = [('all', lambda x, y: True)] | 134 | sub = [('all', lambda x, y: True)] |
117 | if by_mem_hierarchy: | 135 | if by_mem_hierarchy: |
118 | sub += hier | 136 | sub += hier |
119 | for tag, test in sub: | 137 | for tag, test in sub: |
120 | tmp = Tmp() | ||
121 | rows = extract_cols(data, | 138 | rows = extract_cols(data, |
122 | xcol, ycol, yminus, | 139 | xcol, ycol, yminus, |
123 | cpu_filter=test) | 140 | cpu_filter=test) |
124 | for row in rows: | 141 | plots.append((rows, xcol, ycol, yminus, tag)) |
125 | tmp.write("%s, %s\n" % (row[0], row[1])) | ||
126 | tmp.flush() | ||
127 | plots.append((tmp, xcol, ycol, yminus, tag, rows)) | ||
128 | return plots | 142 | return plots |
129 | else: | 143 | else: |
130 | self.err('Unkown host: %s' % host) | 144 | self.err('Unkown host: %s' % host) |
131 | return None | 145 | return None |
132 | 146 | ||
147 | def write_aggregate(self, datafiles): | ||
148 | # (wss, avg, wc, #avg, #wc) | ||
149 | # by tag -> by wcycle -> list of data points) | ||
150 | by_tag = defaultdict(lambda: defaultdict(list)) | ||
151 | |||
152 | for i, datafile in enumerate(datafiles): | ||
153 | print '[%d/%d] Processing %s...' % (i + 1, len(datafiles), datafile) | ||
154 | bname = basename(datafile) | ||
155 | name, ext = splitext(bname) | ||
156 | if ext != '.csv': | ||
157 | self.err("Warning: '%s' doesn't look like a CSV file." | ||
158 | % bname) | ||
159 | conf = decode(name) | ||
160 | if 'pmo' in conf: | ||
161 | plots = self.setup_pmo_graphs(datafile, conf, PMO_AGGR_SUBPLOTS) | ||
162 | if plots is None: | ||
163 | print "Skipping %s..." % datafile | ||
164 | return | ||
165 | wss = int(conf['wss']) | ||
166 | wcycle = int(conf['wcycle']) | ||
167 | host = conf['host'] | ||
168 | for (rows, xcol, ycol, yminus, tag) in plots: | ||
169 | clean = stats.iqr_remove_outliers(rows, extend=self.options.extend) | ||
170 | vals = clean[:,1] | ||
171 | avg = np.mean(vals) | ||
172 | std = np.std(vals, ddof=1) | ||
173 | wc = np.max(vals) | ||
174 | n = len(vals) | ||
175 | |||
176 | xtag = PMO_COL_LABEL[xcol][1] | ||
177 | ytag = PMO_COL_LABEL[ycol][1] | ||
178 | dtag = "-delta-%s" % PMO_COL_LABEL[yminus][1] if not yminus is None else "" | ||
179 | code = "code=%s-%s-%s-%s" % \ | ||
180 | (xcol, ycol, yminus, tag) | ||
181 | figname = "host=%s_%s%s-vs-%s_%s_%s" % \ | ||
182 | (host, ytag, dtag, xtag, tag, code) | ||
183 | by_tag[figname][wcycle].append((wss, avg, std, wc, n, len(rows) - n)) | ||
184 | del plots | ||
185 | else: | ||
186 | self.err("Warning: '%s' is not a PMO experiment; skipping." % bname) | ||
187 | |||
188 | for figname in by_tag: | ||
189 | for wcycle in by_tag[figname]: | ||
190 | data = by_tag[figname][wcycle] | ||
191 | # sort by increasing WSS | ||
192 | data.sort(key=lambda row: row[0]) | ||
193 | f = open('pmo-aggr_wcycle=%d_%s.csv' % (wcycle, figname), 'w') | ||
194 | for row in data: | ||
195 | f.write(", ".join([str(x) for x in row])) | ||
196 | f.write('\n') | ||
197 | f.close() | ||
198 | |||
133 | def plot_preempt_migrate(self, datafile, name, conf): | 199 | def plot_preempt_migrate(self, datafile, name, conf): |
134 | plots = self.setup_pmo_graphs(datafile, conf) | 200 | plots = self.setup_pmo_graphs(datafile, conf) |
135 | if plots is None: | 201 | if plots is None: |
136 | print "Skipping %s..." % datafile | 202 | print "Skipping %s..." % datafile |
137 | return | 203 | return |
138 | for (tmp, xcol, ycol, yminus, tag, rows) in plots: | 204 | else: |
205 | print 'Plotting %s...' % datafile | ||
206 | for (rows, xcol, ycol, yminus, tag) in plots: | ||
207 | # Write it to a temp file. | ||
208 | tmp = Tmp() | ||
209 | for row in rows: | ||
210 | tmp.write("%s, %s\n" % (row[0], row[1])) | ||
211 | tmp.flush() | ||
212 | |||
139 | xtag = PMO_COL_LABEL[xcol][1] | 213 | xtag = PMO_COL_LABEL[xcol][1] |
140 | ytag = PMO_COL_LABEL[ycol][1] | 214 | ytag = PMO_COL_LABEL[ycol][1] |
141 | dtag = "-delta-%s" % PMO_COL_LABEL[yminus][1] if not yminus is None else "" | 215 | dtag = "-delta-%s" % PMO_COL_LABEL[yminus][1] if not yminus is None else "" |
@@ -147,7 +221,6 @@ class CyclePlotter(defapp.App): | |||
147 | title = "%s" % ylabel | 221 | title = "%s" % ylabel |
148 | if ycol == 10: | 222 | if ycol == 10: |
149 | title += " from %s" % PMO_MEM[tag] | 223 | title += " from %s" % PMO_MEM[tag] |
150 | title += "\\n" | ||
151 | for key in conf: | 224 | for key in conf: |
152 | if key in PMO_PARAM: | 225 | if key in PMO_PARAM: |
153 | title += " %s=%s" % (PMO_PARAM[key], conf[key]) | 226 | title += " %s=%s" % (PMO_PARAM[key], conf[key]) |
@@ -169,6 +242,49 @@ class CyclePlotter(defapp.App): | |||
169 | style='points', | 242 | style='points', |
170 | format=self.options.format, | 243 | format=self.options.format, |
171 | fname=figname) | 244 | fname=figname) |
245 | del tmp # delete temporary file | ||
246 | |||
247 | def plot_pmo_aggr(self, datafile, name, conf): | ||
248 | fname = datafile | ||
249 | code = conf['code'] | ||
250 | (xcol, ycol, yminus, tag) = code.split('-') | ||
251 | |||
252 | xcol = int(xcol) | ||
253 | ycol = int(ycol) | ||
254 | if yminus != "None": | ||
255 | yminus = int(ycol) | ||
256 | else: | ||
257 | yminus = None | ||
258 | |||
259 | xtag = PMO_COL_LABEL[xcol][1] | ||
260 | ytag = PMO_COL_LABEL[ycol][1] | ||
261 | dtag = "-delta-%s" % PMO_COL_LABEL[yminus][1] if not yminus is None else "" | ||
262 | figname = "%s_%s%s-vs-%s_%s" % (name, ytag, dtag, xtag, tag) | ||
263 | xunit = PMO_COL_LABEL[xcol][2] | ||
264 | yunit = PMO_COL_LABEL[ycol][2] | ||
265 | ylabel = PMO_COL_LABEL[ycol][0] | ||
266 | xlabel = PMO_COL_LABEL[xcol][0] | ||
267 | title = "%s" % ylabel | ||
268 | |||
269 | ylabel="%s (%s)" % ("access cost" if yminus is None | ||
270 | else "delta to %s" % PMO_COL_LABEL[yminus][0], | ||
271 | yunit), | ||
272 | if ycol == 10: | ||
273 | title += " from %s" % PMO_MEM[tag] | ||
274 | for key in conf: | ||
275 | if key in PMO_PARAM: | ||
276 | title += " %s=%s" % (PMO_PARAM[key], conf[key]) | ||
277 | |||
278 | graphs = [ | ||
279 | #(fname, 1, 2, "average"), | ||
280 | "'%s' using 1:2:3 title 'average' with errorbars" % (fname), | ||
281 | (fname, 1, 4, "maximum"), | ||
282 | ] | ||
283 | xlabel = "working set size (kilobytes)" | ||
284 | |||
285 | gnuplot(graphs, xlabel=xlabel, ylabel=ylabel, title=title, fname=figname, | ||
286 | logscale="xy 2" if yminus is None else "x 2", | ||
287 | format=self.options.format) | ||
172 | 288 | ||
173 | def plot_file(self, datafile): | 289 | def plot_file(self, datafile): |
174 | bname = basename(datafile) | 290 | bname = basename(datafile) |
@@ -179,6 +295,8 @@ class CyclePlotter(defapp.App): | |||
179 | conf = decode(name) | 295 | conf = decode(name) |
180 | if 'pmo' in conf: | 296 | if 'pmo' in conf: |
181 | self.plot_preempt_migrate(datafile, name, conf) | 297 | self.plot_preempt_migrate(datafile, name, conf) |
298 | elif 'pmo-aggr' in conf: | ||
299 | self.plot_pmo_aggr(datafile, name, conf) | ||
182 | else: | 300 | else: |
183 | self.err("Skipped '%s'; unkown experiment type." | 301 | self.err("Skipped '%s'; unkown experiment type." |
184 | % bname) | 302 | % bname) |
@@ -187,5 +305,8 @@ class CyclePlotter(defapp.App): | |||
187 | for datafile in self.args: | 305 | for datafile in self.args: |
188 | self.plot_file(datafile) | 306 | self.plot_file(datafile) |
189 | 307 | ||
308 | def do_aggregate(self, _): | ||
309 | self.write_aggregate(self.args[1:]) | ||
310 | |||
190 | if __name__ == "__main__": | 311 | if __name__ == "__main__": |
191 | CyclePlotter().launch() | 312 | CyclePlotter().launch() |