2 """Compute basic stats about CBench data."""
7 import matplotlib.pyplot as pyplot
14 """Compute stats and/or graph data.
16 I know I could convert these fns that simply punt to a helper
17 to a dict/list data structure, but that would remove some of the
18 flexabilty I get by simply calling a graph/stat fn for each
19 graph/stat arg. All current fns just punt to helpers, but future
24 results_file = "results.csv"
25 log_file = "cbench.log"
33 start_steal_time_index = 12
34 end_steal_time_index = 13
38 fifteen_load_index = 20
39 start_iowait_index = 22
43 """Setup some flags and data structures, kick off build_cols call."""
46 self.results["sample_size"] = len(self.run_col)
49 """Parse results file into lists of values, one per column."""
51 self.min_flows_col = []
52 self.max_flows_col = []
53 self.avg_flows_col = []
55 self.used_ram_col = []
57 self.steal_time_col = []
58 self.one_load_col = []
59 self.five_load_col = []
60 self.fifteen_load_col = []
62 with open(self.results_file, "rb") as results_fd:
63 results_reader = csv.reader(results_fd)
64 for row in results_reader:
66 self.run_col.append(float(row[self.run_index]))
67 self.min_flows_col.append(float(row[self.min_flow_index]))
68 self.max_flows_col.append(float(row[self.max_flow_index]))
69 self.avg_flows_col.append(float(row[self.avg_flow_index]))
70 self.runtime_col.append(float(row[self.end_time_index]) -
71 float(row[self.start_time_index]))
72 self.used_ram_col.append(float(row[self.used_ram_index]))
73 self.iowait_col.append(float(row[self.end_iowait_index]) -
74 float(row[self.start_iowait_index]))
75 self.steal_time_col.append(
76 float(row[self.end_steal_time_index]) -
77 float(row[self.start_steal_time_index]))
78 self.one_load_col.append(float(row[self.one_load_index]))
79 self.five_load_col.append(float(row[self.five_load_index]))
80 self.fifteen_load_col.append(
81 float(row[self.fifteen_load_index]))
86 def compute_avg_flow_stats(self):
87 """Compute CBench average flows/second stats."""
88 self.compute_generic_stats("flows", self.avg_flows_col)
90 def build_avg_flow_graph(self, total_gcount, graph_num):
91 """Plot average flows/sec data.
93 :param total_gcount: Total number of graphs to render.
94 :type total_gcount: int
95 :param graph_num: Number for this graph, <= total_gcount.
99 self.build_generic_graph(total_gcount, graph_num,
100 "Average Flows per Second", self.avg_flows_col)
102 def compute_min_flow_stats(self):
103 """Compute CBench min flows/second stats."""
104 self.compute_generic_stats("min_flows", self.min_flows_col)
106 def build_min_flow_graph(self, total_gcount, graph_num):
107 """Plot min flows/sec data.
109 :param total_gcount: Total number of graphs to render.
110 :type total_gcount: int
111 :param graph_num: Number for this graph, <= total_gcount.
115 self.build_generic_graph(total_gcount, graph_num,
116 "Minimum Flows per Second", self.min_flows_col)
118 def compute_max_flow_stats(self):
119 """Compute CBench max flows/second stats."""
120 self.compute_generic_stats("max_flows", self.max_flows_col)
122 def build_max_flow_graph(self, total_gcount, graph_num):
123 """Plot max flows/sec data.
125 :param total_gcount: Total number of graphs to render.
126 :type total_gcount: int
127 :param graph_num: Number for this graph, <= total_gcount.
131 self.build_generic_graph(total_gcount, graph_num,
132 "Maximum Flows per Second", self.max_flows_col)
134 def compute_ram_stats(self):
135 """Compute used RAM stats."""
136 self.compute_generic_stats("used_ram", self.used_ram_col)
138 def build_ram_graph(self, total_gcount, graph_num):
139 """Plot used RAM data.
141 :param total_gcount: Total number of graphs to render.
142 :type total_gcount: int
143 :param graph_num: Number for this graph, <= total_gcount.
147 self.build_generic_graph(total_gcount, graph_num,
148 "Used RAM (MB)", self.used_ram_col)
150 def compute_runtime_stats(self):
151 """Compute CBench runtime length stats."""
152 self.compute_generic_stats("runtime", self.runtime_col)
154 def build_runtime_graph(self, total_gcount, graph_num):
155 """Plot CBench runtime length data.
157 :param total_gcount: Total number of graphs to render.
158 :type total_gcount: int
159 :param graph_num: Number for this graph, <= total_gcount.
163 self.build_generic_graph(total_gcount, graph_num,
164 "CBench Runtime (sec)", self.runtime_col)
166 def compute_iowait_stats(self):
167 """Compute iowait stats."""
168 self.compute_generic_stats("iowait", self.iowait_col)
170 def build_iowait_graph(self, total_gcount, graph_num):
173 :param total_gcount: Total number of graphs to render.
174 :type total_gcount: int
175 :param graph_num: Number for this graph, <= total_gcount.
179 self.build_generic_graph(total_gcount, graph_num,
180 "IOWait Time (sec)", self.iowait_col)
182 def compute_steal_time_stats(self):
183 """Compute steal time stats."""
184 self.compute_generic_stats("steal_time", self.steal_time_col)
186 def build_steal_time_graph(self, total_gcount, graph_num):
187 """Plot steal time data.
189 :param total_gcount: Total number of graphs to render.
190 :type total_gcount: int
191 :param graph_num: Number for this graph, <= total_gcount.
195 self.build_generic_graph(total_gcount, graph_num,
196 "Steal Time (sec)", self.steal_time_col)
198 def compute_one_load_stats(self):
199 """Compute one minute load stats."""
200 self.compute_generic_stats("one_load", self.one_load_col)
202 def build_one_load_graph(self, total_gcount, graph_num):
203 """Plot one minute load data.
205 :param total_gcount: Total number of graphs to render.
206 :type total_gcount: int
207 :param graph_num: Number for this graph, <= total_gcount.
211 self.build_generic_graph(total_gcount, graph_num,
212 "One Minute Load", self.one_load_col)
214 def compute_five_load_stats(self):
215 """Compute five minute load stats."""
216 self.compute_generic_stats("five_load", self.five_load_col)
218 def build_five_load_graph(self, total_gcount, graph_num):
219 """Plot five minute load data.
221 :param total_gcount: Total number of graphs to render.
222 :type total_gcount: int
223 :param graph_num: Number for this graph, <= total_gcount.
227 self.build_generic_graph(total_gcount, graph_num,
228 "Five Minute Load", self.five_load_col)
230 def compute_fifteen_load_stats(self):
231 """Compute fifteen minute load stats."""
232 self.compute_generic_stats("fifteen_load", self.fifteen_load_col)
234 def build_fifteen_load_graph(self, total_gcount, graph_num):
235 """Plot fifteen minute load data.
237 :param total_gcount: Total number of graphs to render.
238 :type total_gcount: int
239 :param graph_num: Number for this graph, <= total_gcount.
243 self.build_generic_graph(total_gcount, graph_num,
244 "Fifteen Minute Load", self.fifteen_load_col)
246 def compute_generic_stats(self, stats_name, stats_col):
247 """Helper for computing generic stats."""
249 generic_stats["min"] = int(numpy.amin(stats_col))
250 generic_stats["max"] = int(numpy.amax(stats_col))
251 generic_stats["mean"] = round(numpy.mean(stats_col), self.precision)
252 generic_stats["stddev"] = round(numpy.std(stats_col), self.precision)
254 generic_stats["relstddev"] = round(generic_stats["stddev"] /
255 generic_stats["mean"] *
257 except ZeroDivisionError:
258 generic_stats["relstddev"] = 0.
259 self.results[stats_name] = generic_stats
261 def build_generic_graph(self, total_gcount, graph_num, y_label, data_col):
262 """Helper for plotting generic data.
264 :param total_gcount: Total number of graphs to render.
265 :type total_gcount: int
266 :param graph_num: Number for this graph, <= total_gcount.
268 :param y_label: Lable of Y axis.
269 :type y_label: string
270 :param data_col: Data to graph.
274 # Pagenerics are numrows, numcols, fignum
275 pyplot.subplot(total_gcount, 1, graph_num)
276 # "go" means green O's
277 pyplot.plot(self.run_col, data_col, "go")
278 pyplot.xlabel("Run Number")
279 pyplot.ylabel(y_label)
285 # Map of graph names to the Stats.fns that build them
286 graph_map = {"min_flows": stats.build_min_flow_graph,
287 "max_flows": stats.build_max_flow_graph,
288 "flows": stats.build_avg_flow_graph,
289 "runtime": stats.build_runtime_graph,
290 "iowait": stats.build_iowait_graph,
291 "steal_time": stats.build_steal_time_graph,
292 "one_load": stats.build_one_load_graph,
293 "five_load": stats.build_five_load_graph,
294 "fifteen_load": stats.build_fifteen_load_graph,
295 "ram": stats.build_ram_graph}
296 stats_map = {"min_flows": stats.compute_min_flow_stats,
297 "max_flows": stats.compute_max_flow_stats,
298 "flows": stats.compute_avg_flow_stats,
299 "runtime": stats.compute_runtime_stats,
300 "iowait": stats.compute_iowait_stats,
301 "steal_time": stats.compute_steal_time_stats,
302 "one_load": stats.compute_one_load_stats,
303 "five_load": stats.compute_five_load_stats,
304 "fifteen_load": stats.compute_fifteen_load_stats,
305 "ram": stats.compute_ram_stats}
307 # Build argument parser
308 parser = argparse.ArgumentParser(description="Compute stats about CBench data")
309 parser.add_argument("-S", "--all-stats", action="store_true",
310 help="compute all stats")
311 parser.add_argument("-s", "--stats", choices=stats_map.keys(),
312 help="compute stats on specified data", nargs="+")
313 parser.add_argument("-G", "--all-graphs", action="store_true",
314 help="graph all data")
315 parser.add_argument("-g", "--graphs", choices=graph_map.keys(),
316 help="graph specified data", nargs="+")
319 # Print help if no arguments are given
320 if len(sys.argv) == 1:
324 # Parse the given args
325 args = parser.parse_args()
329 graphs_to_build = graph_map.keys()
331 graphs_to_build = args.graphs
334 for graph, graph_num in zip(graphs_to_build, range(len(graphs_to_build))):
335 graph_map[graph](len(graphs_to_build), graph_num+1)
339 stats_to_compute = stats_map.keys()
341 stats_to_compute = args.stats
343 stats_to_compute = []
344 for stat in stats_to_compute:
348 if args.graphs or args.all_graphs:
349 # Attempt to adjust plot spacing, just a simple heuristic
350 if len(graphs_to_build) <= 3:
351 pyplot.subplots_adjust(hspace=.2)
352 elif len(graphs_to_build) <= 6:
353 pyplot.subplots_adjust(hspace=.4)
354 elif len(graphs_to_build) <= 9:
355 pyplot.subplots_adjust(hspace=.7)
357 pyplot.subplots_adjust(hspace=.7)
358 print "WARNING: That's a lot of graphs. Add a second column?"
362 if args.stats or args.all_stats:
363 pprint.pprint(stats.results)