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(
71 float(row[self.end_time_index])
72 - float(row[self.start_time_index])
74 self.used_ram_col.append(float(row[self.used_ram_index]))
75 self.iowait_col.append(
76 float(row[self.end_iowait_index])
77 - float(row[self.start_iowait_index])
79 self.steal_time_col.append(
80 float(row[self.end_steal_time_index])
81 - float(row[self.start_steal_time_index])
83 self.one_load_col.append(float(row[self.one_load_index]))
84 self.five_load_col.append(float(row[self.five_load_index]))
85 self.fifteen_load_col.append(float(row[self.fifteen_load_index]))
90 def compute_avg_flow_stats(self):
91 """Compute CBench average flows/second stats."""
92 self.compute_generic_stats("flows", self.avg_flows_col)
94 def build_avg_flow_graph(self, total_gcount, graph_num):
95 """Plot average flows/sec data.
97 :param total_gcount: Total number of graphs to render.
98 :type total_gcount: int
99 :param graph_num: Number for this graph, <= total_gcount.
103 self.build_generic_graph(
104 total_gcount, graph_num, "Average Flows per Second", self.avg_flows_col
107 def compute_min_flow_stats(self):
108 """Compute CBench min flows/second stats."""
109 self.compute_generic_stats("min_flows", self.min_flows_col)
111 def build_min_flow_graph(self, total_gcount, graph_num):
112 """Plot min flows/sec data.
114 :param total_gcount: Total number of graphs to render.
115 :type total_gcount: int
116 :param graph_num: Number for this graph, <= total_gcount.
120 self.build_generic_graph(
121 total_gcount, graph_num, "Minimum Flows per Second", self.min_flows_col
124 def compute_max_flow_stats(self):
125 """Compute CBench max flows/second stats."""
126 self.compute_generic_stats("max_flows", self.max_flows_col)
128 def build_max_flow_graph(self, total_gcount, graph_num):
129 """Plot max flows/sec data.
131 :param total_gcount: Total number of graphs to render.
132 :type total_gcount: int
133 :param graph_num: Number for this graph, <= total_gcount.
137 self.build_generic_graph(
138 total_gcount, graph_num, "Maximum Flows per Second", self.max_flows_col
141 def compute_ram_stats(self):
142 """Compute used RAM stats."""
143 self.compute_generic_stats("used_ram", self.used_ram_col)
145 def build_ram_graph(self, total_gcount, graph_num):
146 """Plot used RAM data.
148 :param total_gcount: Total number of graphs to render.
149 :type total_gcount: int
150 :param graph_num: Number for this graph, <= total_gcount.
154 self.build_generic_graph(
155 total_gcount, graph_num, "Used RAM (MB)", self.used_ram_col
158 def compute_runtime_stats(self):
159 """Compute CBench runtime length stats."""
160 self.compute_generic_stats("runtime", self.runtime_col)
162 def build_runtime_graph(self, total_gcount, graph_num):
163 """Plot CBench runtime length data.
165 :param total_gcount: Total number of graphs to render.
166 :type total_gcount: int
167 :param graph_num: Number for this graph, <= total_gcount.
171 self.build_generic_graph(
172 total_gcount, graph_num, "CBench Runtime (sec)", self.runtime_col
175 def compute_iowait_stats(self):
176 """Compute iowait stats."""
177 self.compute_generic_stats("iowait", self.iowait_col)
179 def build_iowait_graph(self, total_gcount, graph_num):
182 :param total_gcount: Total number of graphs to render.
183 :type total_gcount: int
184 :param graph_num: Number for this graph, <= total_gcount.
188 self.build_generic_graph(
189 total_gcount, graph_num, "IOWait Time (sec)", self.iowait_col
192 def compute_steal_time_stats(self):
193 """Compute steal time stats."""
194 self.compute_generic_stats("steal_time", self.steal_time_col)
196 def build_steal_time_graph(self, total_gcount, graph_num):
197 """Plot steal time data.
199 :param total_gcount: Total number of graphs to render.
200 :type total_gcount: int
201 :param graph_num: Number for this graph, <= total_gcount.
205 self.build_generic_graph(
206 total_gcount, graph_num, "Steal Time (sec)", self.steal_time_col
209 def compute_one_load_stats(self):
210 """Compute one minute load stats."""
211 self.compute_generic_stats("one_load", self.one_load_col)
213 def build_one_load_graph(self, total_gcount, graph_num):
214 """Plot one minute load data.
216 :param total_gcount: Total number of graphs to render.
217 :type total_gcount: int
218 :param graph_num: Number for this graph, <= total_gcount.
222 self.build_generic_graph(
223 total_gcount, graph_num, "One Minute Load", self.one_load_col
226 def compute_five_load_stats(self):
227 """Compute five minute load stats."""
228 self.compute_generic_stats("five_load", self.five_load_col)
230 def build_five_load_graph(self, total_gcount, graph_num):
231 """Plot five minute load data.
233 :param total_gcount: Total number of graphs to render.
234 :type total_gcount: int
235 :param graph_num: Number for this graph, <= total_gcount.
239 self.build_generic_graph(
240 total_gcount, graph_num, "Five Minute Load", self.five_load_col
243 def compute_fifteen_load_stats(self):
244 """Compute fifteen minute load stats."""
245 self.compute_generic_stats("fifteen_load", self.fifteen_load_col)
247 def build_fifteen_load_graph(self, total_gcount, graph_num):
248 """Plot fifteen minute load data.
250 :param total_gcount: Total number of graphs to render.
251 :type total_gcount: int
252 :param graph_num: Number for this graph, <= total_gcount.
256 self.build_generic_graph(
257 total_gcount, graph_num, "Fifteen Minute Load", self.fifteen_load_col
260 def compute_generic_stats(self, stats_name, stats_col):
261 """Helper for computing generic stats."""
263 generic_stats["min"] = int(numpy.amin(stats_col))
264 generic_stats["max"] = int(numpy.amax(stats_col))
265 generic_stats["mean"] = round(numpy.mean(stats_col), self.precision)
266 generic_stats["stddev"] = round(numpy.std(stats_col), self.precision)
268 generic_stats["relstddev"] = round(
269 generic_stats["stddev"] / generic_stats["mean"] * 100, self.precision
271 except ZeroDivisionError:
272 generic_stats["relstddev"] = 0.0
273 self.results[stats_name] = generic_stats
275 def build_generic_graph(self, total_gcount, graph_num, y_label, data_col):
276 """Helper for plotting generic data.
278 :param total_gcount: Total number of graphs to render.
279 :type total_gcount: int
280 :param graph_num: Number for this graph, <= total_gcount.
282 :param y_label: Lable of Y axis.
283 :type y_label: string
284 :param data_col: Data to graph.
288 # Pagenerics are numrows, numcols, fignum
289 pyplot.subplot(total_gcount, 1, graph_num)
290 # "go" means green O's
291 pyplot.plot(self.run_col, data_col, "go")
292 pyplot.xlabel("Run Number")
293 pyplot.ylabel(y_label)
299 # Map of graph names to the Stats.fns that build them
301 "min_flows": stats.build_min_flow_graph,
302 "max_flows": stats.build_max_flow_graph,
303 "flows": stats.build_avg_flow_graph,
304 "runtime": stats.build_runtime_graph,
305 "iowait": stats.build_iowait_graph,
306 "steal_time": stats.build_steal_time_graph,
307 "one_load": stats.build_one_load_graph,
308 "five_load": stats.build_five_load_graph,
309 "fifteen_load": stats.build_fifteen_load_graph,
310 "ram": stats.build_ram_graph,
313 "min_flows": stats.compute_min_flow_stats,
314 "max_flows": stats.compute_max_flow_stats,
315 "flows": stats.compute_avg_flow_stats,
316 "runtime": stats.compute_runtime_stats,
317 "iowait": stats.compute_iowait_stats,
318 "steal_time": stats.compute_steal_time_stats,
319 "one_load": stats.compute_one_load_stats,
320 "five_load": stats.compute_five_load_stats,
321 "fifteen_load": stats.compute_fifteen_load_stats,
322 "ram": stats.compute_ram_stats,
325 # Build argument parser
326 parser = argparse.ArgumentParser(description="Compute stats about CBench data")
327 parser.add_argument("-S", "--all-stats", action="store_true", help="compute all stats")
331 choices=stats_map.keys(),
332 help="compute stats on specified data",
335 parser.add_argument("-G", "--all-graphs", action="store_true", help="graph all data")
337 "-g", "--graphs", choices=graph_map.keys(), help="graph specified data", nargs="+"
341 # Print help if no arguments are given
342 if len(sys.argv) == 1:
346 # Parse the given args
347 args = parser.parse_args()
351 graphs_to_build = graph_map.keys()
353 graphs_to_build = args.graphs
356 for graph, graph_num in zip(graphs_to_build, range(len(graphs_to_build))):
357 graph_map[graph](len(graphs_to_build), graph_num + 1)
361 stats_to_compute = stats_map.keys()
363 stats_to_compute = args.stats
365 stats_to_compute = []
366 for stat in stats_to_compute:
370 if args.graphs or args.all_graphs:
371 # Attempt to adjust plot spacing, just a simple heuristic
372 if len(graphs_to_build) <= 3:
373 pyplot.subplots_adjust(hspace=0.2)
374 elif len(graphs_to_build) <= 6:
375 pyplot.subplots_adjust(hspace=0.4)
376 elif len(graphs_to_build) <= 9:
377 pyplot.subplots_adjust(hspace=0.7)
379 pyplot.subplots_adjust(hspace=0.7)
380 print("WARNING: That's a lot of graphs. Add a second column?")
384 if args.stats or args.all_stats:
385 pprint.pprint(stats.results)