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 if test["type"] in ("NDRPDR", ):
79 if "-pdr" in plot_title.lower():
80 y_vals[test["parent"]].\
81 append(test["throughput"]["PDR"]["LOWER"])
82 elif "-ndr" in plot_title.lower():
83 y_vals[test["parent"]]. \
84 append(test["throughput"]["NDR"]["LOWER"])
89 except (KeyError, TypeError):
90 y_vals[test["parent"]].append(None)
92 # Add None to the lists with missing data
94 for val in y_vals.values():
95 if len(val) > max_len:
97 for key, val in y_vals.items():
98 if len(val) < max_len:
99 val.extend([None for _ in range(max_len - len(val))])
103 df = pd.DataFrame(y_vals)
105 for i, col in enumerate(df.columns):
106 name = "{0}. {1}".format(i + 1, col.lower().replace('-ndrpdrdisc', '').
107 replace('-ndrpdr', ''))
108 traces.append(plgo.Box(x=[str(i + 1) + '.'] * len(df[col]),
115 plpl = plgo.Figure(data=traces, layout=plot["layout"])
118 logging.info(" Writing file '{0}{1}'.".
119 format(plot["output-file"], plot["output-file-type"]))
121 show_link=False, auto_open=False,
122 filename='{0}{1}'.format(plot["output-file"],
123 plot["output-file-type"]))
124 except PlotlyError as err:
125 logging.error(" Finished with error: {}".
126 format(str(err).replace("\n", " ")))
129 logging.info(" Done.")
132 def plot_latency_box(plot, input_data):
133 """Generate the plot(s) with algorithm: plot_latency_box
134 specified in the specification file.
136 :param plot: Plot to generate.
137 :param input_data: Data to process.
138 :type plot: pandas.Series
139 :type input_data: InputData
142 logging.info(" Generating the plot {0} ...".
143 format(plot.get("title", "")))
146 plot_title = plot.get("title", "")
147 logging.info(" Creating the data set for the {0} '{1}'.".
148 format(plot.get("type", ""), plot_title))
149 data = input_data.filter_data(plot)
151 logging.error("No data.")
154 # Prepare the data for the plot
159 if y_tmp_vals.get(test["parent"], None) is None:
160 y_tmp_vals[test["parent"]] = [
161 list(), # direction1, min
162 list(), # direction1, avg
163 list(), # direction1, max
164 list(), # direction2, min
165 list(), # direction2, avg
166 list() # direction2, max
169 if test["type"] in ("NDRPDR", ):
170 if "-pdr" in plot_title.lower():
172 elif "-ndr" in plot_title.lower():
176 y_tmp_vals[test["parent"]][0].append(
177 test["latency"][ttype]["direction1"]["min"])
178 y_tmp_vals[test["parent"]][1].append(
179 test["latency"][ttype]["direction1"]["avg"])
180 y_tmp_vals[test["parent"]][2].append(
181 test["latency"][ttype]["direction1"]["max"])
182 y_tmp_vals[test["parent"]][3].append(
183 test["latency"][ttype]["direction2"]["min"])
184 y_tmp_vals[test["parent"]][4].append(
185 test["latency"][ttype]["direction2"]["avg"])
186 y_tmp_vals[test["parent"]][5].append(
187 test["latency"][ttype]["direction2"]["max"])
190 except (KeyError, TypeError):
194 for key, values in y_tmp_vals.items():
201 y_vals[key].append(average)
202 y_vals[key].append(average) # Twice for plot.ly
207 df = pd.DataFrame(y_vals)
209 except ValueError as err:
210 logging.error(" Finished with error: {}".
211 format(str(err).replace("\n", " ")))
214 for i, col in enumerate(df.columns):
215 name = "{0}. {1}".format(i + 1, col.lower().replace('-ndrpdrdisc', '').
216 replace('-ndrpdr', ''))
217 traces.append(plgo.Box(x=['TGint1-to-SUT1-to-SUT2-to-TGint2',
218 'TGint1-to-SUT1-to-SUT2-to-TGint2',
219 'TGint1-to-SUT1-to-SUT2-to-TGint2',
220 'TGint1-to-SUT1-to-SUT2-to-TGint2',
221 'TGint1-to-SUT1-to-SUT2-to-TGint2',
222 'TGint1-to-SUT1-to-SUT2-to-TGint2',
223 'TGint2-to-SUT2-to-SUT1-to-TGint1',
224 'TGint2-to-SUT2-to-SUT1-to-TGint1',
225 'TGint2-to-SUT2-to-SUT1-to-TGint1',
226 'TGint2-to-SUT2-to-SUT1-to-TGint1',
227 'TGint2-to-SUT2-to-SUT1-to-TGint1',
228 'TGint2-to-SUT2-to-SUT1-to-TGint1'],
235 logging.info(" Writing file '{0}{1}'.".
236 format(plot["output-file"], plot["output-file-type"]))
237 plpl = plgo.Figure(data=traces, layout=plot["layout"])
241 show_link=False, auto_open=False,
242 filename='{0}{1}'.format(plot["output-file"],
243 plot["output-file-type"]))
244 except PlotlyError as err:
245 logging.error(" Finished with error: {}".
246 format(str(err).replace("\n", " ")))
249 logging.info(" Done.")
252 def plot_throughput_speedup_analysis(plot, input_data):
253 """Generate the plot(s) with algorithm: plot_throughput_speedup_analysis
254 specified in the specification file.
256 :param plot: Plot to generate.
257 :param input_data: Data to process.
258 :type plot: pandas.Series
259 :type input_data: InputData
262 logging.info(" Generating the plot {0} ...".
263 format(plot.get("title", "")))
266 plot_title = plot.get("title", "")
267 logging.info(" Creating the data set for the {0} '{1}'.".
268 format(plot.get("type", ""), plot_title))
269 data = input_data.filter_data(plot)
271 logging.error("No data.")
278 if throughput.get(test["parent"], None) is None:
279 throughput[test["parent"]] = {"1": list(),
283 if test["type"] in ("NDRPDR", ):
284 if "-pdr" in plot_title.lower():
286 elif "-ndr" in plot_title.lower():
290 if "1C" in test["tags"]:
291 throughput[test["parent"]]["1"].\
292 append(test["throughput"][ttype]["LOWER"])
293 elif "2C" in test["tags"]:
294 throughput[test["parent"]]["2"]. \
295 append(test["throughput"][ttype]["LOWER"])
296 elif "4C" in test["tags"]:
297 throughput[test["parent"]]["4"]. \
298 append(test["throughput"][ttype]["LOWER"])
299 except (KeyError, TypeError):
303 logging.warning("No data for the plot '{}'".
304 format(plot.get("title", "")))
307 for test_name, test_vals in throughput.items():
308 for key, test_val in test_vals.items():
310 throughput[test_name][key] = sum(test_val) / len(test_val)
312 names = ['1 core', '2 cores', '4 cores']
318 for test_name, test_vals in throughput.items():
320 x_vals.append("-".join(test_name.split('-')[1:-1]))
324 round(float(test_vals["2"]) / float(test_vals["1"]), 2))
326 y_vals_2.append(None)
329 round(float(test_vals["4"]) / float(test_vals["1"]), 2))
331 y_vals_4.append(None)
333 y_vals = [y_vals_1, y_vals_2, y_vals_4]
335 y_vals_zipped = zip(names, y_vals)
337 for val in y_vals_zipped:
338 traces.append(plgo.Bar(x=x_vals,
344 logging.info(" Writing file '{0}{1}'.".
345 format(plot["output-file"], plot["output-file-type"]))
346 plpl = plgo.Figure(data=traces, layout=plot["layout"])
350 show_link=False, auto_open=False,
351 filename='{0}{1}'.format(plot["output-file"],
352 plot["output-file-type"]))
353 except PlotlyError as err:
354 logging.error(" Finished with error: {}".
355 format(str(err).replace("\n", " ")))
358 logging.info(" Done.")
361 def plot_http_server_performance_box(plot, input_data):
362 """Generate the plot(s) with algorithm: plot_http_server_performance_box
363 specified in the specification file.
365 :param plot: Plot to generate.
366 :param input_data: Data to process.
367 :type plot: pandas.Series
368 :type input_data: InputData
371 logging.info(" Generating the plot {0} ...".
372 format(plot.get("title", "")))
375 logging.info(" Creating the data set for the {0} '{1}'.".
376 format(plot.get("type", ""), plot.get("title", "")))
377 data = input_data.filter_data(plot)
379 logging.error("No data.")
382 # Prepare the data for the plot
387 if y_vals.get(test["name"], None) is None:
388 y_vals[test["name"]] = list()
390 y_vals[test["name"]].append(test["result"])
391 except (KeyError, TypeError):
392 y_vals[test["name"]].append(None)
394 # Add None to the lists with missing data
396 for val in y_vals.values():
397 if len(val) > max_len:
399 for key, val in y_vals.items():
400 if len(val) < max_len:
401 val.extend([None for _ in range(max_len - len(val))])
405 df = pd.DataFrame(y_vals)
407 for i, col in enumerate(df.columns):
408 name = "{0}. {1}".format(i + 1, col.lower().replace('-cps', '').
410 traces.append(plgo.Box(x=[str(i + 1) + '.'] * len(df[col]),
416 plpl = plgo.Figure(data=traces, layout=plot["layout"])
419 logging.info(" Writing file '{0}{1}'.".
420 format(plot["output-file"], plot["output-file-type"]))
422 show_link=False, auto_open=False,
423 filename='{0}{1}'.format(plot["output-file"],
424 plot["output-file-type"]))
425 except PlotlyError as err:
426 logging.error(" Finished with error: {}".
427 format(str(err).replace("\n", " ")))
430 logging.info(" Done.")