1 # Copyright (c) 2018 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
6 # http://www.apache.org/licenses/LICENSE-2.0
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
14 """Algorithms to generate plots.
20 import plotly.offline as ploff
21 import plotly.graph_objs as plgo
23 from plotly.exceptions import PlotlyError
25 from utils import mean
28 def generate_plots(spec, data):
29 """Generate all plots specified in the specification file.
31 :param spec: Specification read from the specification file.
32 :param data: Data to process.
33 :type spec: Specification
37 logging.info("Generating the plots ...")
38 for index, plot in enumerate(spec.plots):
40 logging.info(" Plot nr {0}:".format(index + 1))
41 eval(plot["algorithm"])(plot, data)
42 except NameError as err:
43 logging.error("Probably algorithm '{alg}' is not defined: {err}".
44 format(alg=plot["algorithm"], err=repr(err)))
48 def plot_performance_box(plot, input_data):
49 """Generate the plot(s) with algorithm: plot_performance_box
50 specified in the specification file.
52 :param plot: Plot to generate.
53 :param input_data: Data to process.
54 :type plot: pandas.Series
55 :type input_data: InputData
58 logging.info(" Generating the plot {0} ...".
59 format(plot.get("title", "")))
62 plot_title = plot.get("title", "")
63 logging.info(" Creating the data set for the {0} '{1}'.".
64 format(plot.get("type", ""), plot_title))
65 data = input_data.filter_data(plot)
67 logging.error("No data.")
70 # Prepare the data for the plot
75 if y_vals.get(test["parent"], None) is None:
76 y_vals[test["parent"]] = list()
78 # TODO: Remove when definitely no NDRPDRDISC tests are used:
79 if test["type"] in ("NDR", "PDR"):
80 y_vals[test["parent"]].\
81 append(test["throughput"]["value"])
82 elif test["type"] in ("NDRPDR", ):
83 if "-pdr" in plot_title.lower():
84 y_vals[test["parent"]].\
85 append(test["throughput"]["PDR"]["LOWER"])
86 elif "-ndr" in plot_title.lower():
87 y_vals[test["parent"]]. \
88 append(test["throughput"]["NDR"]["LOWER"])
93 except (KeyError, TypeError):
94 y_vals[test["parent"]].append(None)
96 # Add None to the lists with missing data
98 for val in y_vals.values():
99 if len(val) > max_len:
101 for key, val in y_vals.items():
102 if len(val) < max_len:
103 val.extend([None for _ in range(max_len - len(val))])
107 df = pd.DataFrame(y_vals)
109 for i, col in enumerate(df.columns):
110 name = "{0}. {1}".format(i + 1, col.lower().replace('-ndrpdrdisc', '').
111 replace('-ndrpdr', ''))
112 traces.append(plgo.Box(x=[str(i + 1) + '.'] * len(df[col]),
119 plpl = plgo.Figure(data=traces, layout=plot["layout"])
122 logging.info(" Writing file '{0}{1}'.".
123 format(plot["output-file"], plot["output-file-type"]))
125 show_link=False, auto_open=False,
126 filename='{0}{1}'.format(plot["output-file"],
127 plot["output-file-type"]))
128 except PlotlyError as err:
129 logging.error(" Finished with error: {}".
130 format(str(err).replace("\n", " ")))
133 logging.info(" Done.")
136 def plot_latency_box(plot, input_data):
137 """Generate the plot(s) with algorithm: plot_latency_box
138 specified in the specification file.
140 :param plot: Plot to generate.
141 :param input_data: Data to process.
142 :type plot: pandas.Series
143 :type input_data: InputData
146 logging.info(" Generating the plot {0} ...".
147 format(plot.get("title", "")))
150 plot_title = plot.get("title", "")
151 logging.info(" Creating the data set for the {0} '{1}'.".
152 format(plot.get("type", ""), plot_title))
153 data = input_data.filter_data(plot)
155 logging.error("No data.")
158 # Prepare the data for the plot
163 if y_tmp_vals.get(test["parent"], None) is None:
164 y_tmp_vals[test["parent"]] = [
165 list(), # direction1, min
166 list(), # direction1, avg
167 list(), # direction1, max
168 list(), # direction2, min
169 list(), # direction2, avg
170 list() # direction2, max
173 # TODO: Remove when definitely no NDRPDRDISC tests are used:
174 if test["type"] in ("NDR", "PDR"):
175 y_tmp_vals[test["parent"]][0].append(
176 test["latency"]["direction1"]["50"]["min"])
177 y_tmp_vals[test["parent"]][1].append(
178 test["latency"]["direction1"]["50"]["avg"])
179 y_tmp_vals[test["parent"]][2].append(
180 test["latency"]["direction1"]["50"]["max"])
181 y_tmp_vals[test["parent"]][3].append(
182 test["latency"]["direction2"]["50"]["min"])
183 y_tmp_vals[test["parent"]][4].append(
184 test["latency"]["direction2"]["50"]["avg"])
185 y_tmp_vals[test["parent"]][5].append(
186 test["latency"]["direction2"]["50"]["max"])
187 elif test["type"] in ("NDRPDR", ):
188 if "-pdr" in plot_title.lower():
190 elif "-ndr" in plot_title.lower():
194 y_tmp_vals[test["parent"]][0].append(
195 test["latency"][ttype]["direction1"]["min"])
196 y_tmp_vals[test["parent"]][1].append(
197 test["latency"][ttype]["direction1"]["avg"])
198 y_tmp_vals[test["parent"]][2].append(
199 test["latency"][ttype]["direction1"]["max"])
200 y_tmp_vals[test["parent"]][3].append(
201 test["latency"][ttype]["direction2"]["min"])
202 y_tmp_vals[test["parent"]][4].append(
203 test["latency"][ttype]["direction2"]["avg"])
204 y_tmp_vals[test["parent"]][5].append(
205 test["latency"][ttype]["direction2"]["max"])
208 except (KeyError, TypeError):
212 for key, values in y_tmp_vals.items():
219 y_vals[key].append(average)
220 y_vals[key].append(average) # Twice for plot.ly
225 df = pd.DataFrame(y_vals)
227 except ValueError as err:
228 logging.error(" Finished with error: {}".
229 format(str(err).replace("\n", " ")))
232 for i, col in enumerate(df.columns):
233 name = "{0}. {1}".format(i + 1, col.lower().replace('-ndrpdrdisc', '').
234 replace('-ndrpdr', ''))
235 traces.append(plgo.Box(x=['TGint1-to-SUT1-to-SUT2-to-TGint2',
236 'TGint1-to-SUT1-to-SUT2-to-TGint2',
237 'TGint1-to-SUT1-to-SUT2-to-TGint2',
238 'TGint1-to-SUT1-to-SUT2-to-TGint2',
239 'TGint1-to-SUT1-to-SUT2-to-TGint2',
240 'TGint1-to-SUT1-to-SUT2-to-TGint2',
241 'TGint2-to-SUT2-to-SUT1-to-TGint1',
242 'TGint2-to-SUT2-to-SUT1-to-TGint1',
243 'TGint2-to-SUT2-to-SUT1-to-TGint1',
244 'TGint2-to-SUT2-to-SUT1-to-TGint1',
245 'TGint2-to-SUT2-to-SUT1-to-TGint1',
246 'TGint2-to-SUT2-to-SUT1-to-TGint1'],
253 logging.info(" Writing file '{0}{1}'.".
254 format(plot["output-file"], plot["output-file-type"]))
255 plpl = plgo.Figure(data=traces, layout=plot["layout"])
259 show_link=False, auto_open=False,
260 filename='{0}{1}'.format(plot["output-file"],
261 plot["output-file-type"]))
262 except PlotlyError as err:
263 logging.error(" Finished with error: {}".
264 format(str(err).replace("\n", " ")))
267 logging.info(" Done.")
270 def plot_throughput_speedup_analysis(plot, input_data):
271 """Generate the plot(s) with algorithm: plot_throughput_speedup_analysis
272 specified in the specification file.
274 :param plot: Plot to generate.
275 :param input_data: Data to process.
276 :type plot: pandas.Series
277 :type input_data: InputData
280 logging.info(" Generating the plot {0} ...".
281 format(plot.get("title", "")))
284 plot_title = plot.get("title", "")
285 logging.info(" Creating the data set for the {0} '{1}'.".
286 format(plot.get("type", ""), plot_title))
287 data = input_data.filter_data(plot)
289 logging.error("No data.")
296 if throughput.get(test["parent"], None) is None:
297 throughput[test["parent"]] = {"1": list(),
301 # TODO: Remove when definitely no NDRPDRDISC tests are used:
302 if test["type"] in ("NDR", "PDR"):
303 if "1T1C" in test["tags"]:
304 throughput[test["parent"]]["1"].\
305 append(test["throughput"]["value"])
306 elif "2T2C" in test["tags"]:
307 throughput[test["parent"]]["2"]. \
308 append(test["throughput"]["value"])
309 elif "4T4C" in test["tags"]:
310 throughput[test["parent"]]["4"]. \
311 append(test["throughput"]["value"])
312 elif test["type"] in ("NDRPDR", ):
313 if "-pdr" in plot_title.lower():
315 elif "-ndr" in plot_title.lower():
319 if "1T1C" in test["tags"]:
320 throughput[test["parent"]]["1"].\
321 append(test["throughput"][ttype]["LOWER"])
322 elif "2T2C" in test["tags"]:
323 throughput[test["parent"]]["2"]. \
324 append(test["throughput"][ttype]["LOWER"])
325 elif "4T4C" in test["tags"]:
326 throughput[test["parent"]]["4"]. \
327 append(test["throughput"][ttype]["LOWER"])
328 except (KeyError, TypeError):
332 logging.warning("No data for the plot '{}'".
333 format(plot.get("title", "")))
336 for test_name, test_vals in throughput.items():
337 for key, test_val in test_vals.items():
339 throughput[test_name][key] = sum(test_val) / len(test_val)
341 names = ['1 core', '2 cores', '4 cores']
347 for test_name, test_vals in throughput.items():
349 x_vals.append("-".join(test_name.split('-')[1:-1]))
353 round(float(test_vals["2"]) / float(test_vals["1"]), 2))
355 y_vals_2.append(None)
358 round(float(test_vals["4"]) / float(test_vals["1"]), 2))
360 y_vals_4.append(None)
362 y_vals = [y_vals_1, y_vals_2, y_vals_4]
364 y_vals_zipped = zip(names, y_vals)
366 for val in y_vals_zipped:
367 traces.append(plgo.Bar(x=x_vals,
373 logging.info(" Writing file '{0}{1}'.".
374 format(plot["output-file"], plot["output-file-type"]))
375 plpl = plgo.Figure(data=traces, layout=plot["layout"])
379 show_link=False, auto_open=False,
380 filename='{0}{1}'.format(plot["output-file"],
381 plot["output-file-type"]))
382 except PlotlyError as err:
383 logging.error(" Finished with error: {}".
384 format(str(err).replace("\n", " ")))
387 logging.info(" Done.")
390 def plot_http_server_performance_box(plot, input_data):
391 """Generate the plot(s) with algorithm: plot_http_server_performance_box
392 specified in the specification file.
394 :param plot: Plot to generate.
395 :param input_data: Data to process.
396 :type plot: pandas.Series
397 :type input_data: InputData
400 logging.info(" Generating the plot {0} ...".
401 format(plot.get("title", "")))
404 logging.info(" Creating the data set for the {0} '{1}'.".
405 format(plot.get("type", ""), plot.get("title", "")))
406 data = input_data.filter_data(plot)
408 logging.error("No data.")
411 # Prepare the data for the plot
416 if y_vals.get(test["name"], None) is None:
417 y_vals[test["name"]] = list()
419 y_vals[test["name"]].append(test["result"])
420 except (KeyError, TypeError):
421 y_vals[test["name"]].append(None)
423 # Add None to the lists with missing data
425 for val in y_vals.values():
426 if len(val) > max_len:
428 for key, val in y_vals.items():
429 if len(val) < max_len:
430 val.extend([None for _ in range(max_len - len(val))])
434 df = pd.DataFrame(y_vals)
436 for i, col in enumerate(df.columns):
437 name = "{0}. {1}".format(i + 1, col.lower().replace('-cps', '').
439 traces.append(plgo.Box(x=[str(i + 1) + '.'] * len(df[col]),
445 plpl = plgo.Figure(data=traces, layout=plot["layout"])
448 logging.info(" Writing file '{0}{1}'.".
449 format(plot["output-file"], plot["output-file-type"]))
451 show_link=False, auto_open=False,
452 filename='{0}{1}'.format(plot["output-file"],
453 plot["output-file-type"]))
454 except PlotlyError as err:
455 logging.error(" Finished with error: {}".
456 format(str(err).replace("\n", " ")))
459 logging.info(" Done.")