X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=resources%2Ftools%2Fpresentation%2Fgenerator_plots.py;h=ca1cd9bdf687bde2d10b7bdb83a0bf0618fd4773;hb=7f83ed570d3cd7ec18f2a7ea3c8c3badd0368099;hp=03cee06cb04776327b3a368deda482b02f86677f;hpb=1304e1ba4c723e255019a2990612906790f47bca;p=csit.git
diff --git a/resources/tools/presentation/generator_plots.py b/resources/tools/presentation/generator_plots.py
index 03cee06cb0..ca1cd9bdf6 100644
--- a/resources/tools/presentation/generator_plots.py
+++ b/resources/tools/presentation/generator_plots.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2018 Cisco and/or its affiliates.
+# Copyright (c) 2019 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
@@ -144,21 +144,22 @@ def plot_performance_box(plot, input_data):
df.head()
y_max = list()
for i, col in enumerate(df.columns):
- name = "{0}. {1}".format(i + 1, col.lower().replace('-ndrpdr', ''))
- if len(name) > 60:
+ name = "{nr}. ({samples:02d} run{plural}) {name}".\
+ format(nr=(i + 1),
+ samples=nr_of_samples[i],
+ plural='s' if nr_of_samples[i] > 1 else '',
+ name=col.lower().replace('-ndrpdr', ''))
+ if len(name) > 50:
name_lst = name.split('-')
name = ""
split_name = True
for segment in name_lst:
- if (len(name) + len(segment) + 1) > 60 and split_name:
+ if (len(name) + len(segment) + 1) > 50 and split_name:
name += "
"
split_name = False
name += segment + '-'
name = name[:-1]
- name = "{name} ({samples} run{plural})".\
- format(name=name,
- samples=nr_of_samples[i],
- plural='s' if nr_of_samples[i] > 1 else '')
+
logging.debug(name)
traces.append(plgo.Box(x=[str(i + 1) + '.'] * len(df[col]),
y=[y / 1000000 if y else None for y in df[col]],
@@ -194,6 +195,248 @@ def plot_performance_box(plot, input_data):
return
+def plot_soak_bars(plot, input_data):
+ """Generate the plot(s) with algorithm: plot_soak_bars
+ specified in the specification file.
+
+ :param plot: Plot to generate.
+ :param input_data: Data to process.
+ :type plot: pandas.Series
+ :type input_data: InputData
+ """
+
+ # Transform the data
+ plot_title = plot.get("title", "")
+ logging.info(" Creating the data set for the {0} '{1}'.".
+ format(plot.get("type", ""), plot_title))
+ data = input_data.filter_data(plot)
+ if data is None:
+ logging.error("No data.")
+ return
+
+ # Prepare the data for the plot
+ y_vals = dict()
+ y_tags = dict()
+ for job in data:
+ for build in job:
+ for test in build:
+ if y_vals.get(test["parent"], None) is None:
+ y_tags[test["parent"]] = test.get("tags", None)
+ try:
+ if test["type"] in ("SOAK", ):
+ y_vals[test["parent"]] = test["throughput"]
+ else:
+ continue
+ except (KeyError, TypeError):
+ y_vals[test["parent"]] = dict()
+
+ # Sort the tests
+ order = plot.get("sort", None)
+ if order and y_tags:
+ y_sorted = OrderedDict()
+ y_tags_l = {s: [t.lower() for t in ts] for s, ts in y_tags.items()}
+ for tag in order:
+ logging.debug(tag)
+ for suite, tags in y_tags_l.items():
+ if "not " in tag:
+ tag = tag.split(" ")[-1]
+ if tag.lower() in tags:
+ continue
+ else:
+ if tag.lower() not in tags:
+ continue
+ try:
+ y_sorted[suite] = y_vals.pop(suite)
+ y_tags_l.pop(suite)
+ logging.debug(suite)
+ except KeyError as err:
+ logging.error("Not found: {0}".format(repr(err)))
+ finally:
+ break
+ else:
+ y_sorted = y_vals
+
+ idx = 0
+ y_max = 0
+ traces = list()
+ for test_name, test_data in y_sorted.items():
+ idx += 1
+ name = "{nr}. {name}".\
+ format(nr=idx, name=test_name.lower().replace('-soak', ''))
+ if len(name) > 50:
+ name_lst = name.split('-')
+ name = ""
+ split_name = True
+ for segment in name_lst:
+ if (len(name) + len(segment) + 1) > 50 and split_name:
+ name += "
"
+ split_name = False
+ name += segment + '-'
+ name = name[:-1]
+
+ y_val = test_data.get("LOWER", None)
+ if y_val:
+ y_val /= 1000000
+ if y_val > y_max:
+ y_max = y_val
+
+ time = "No Information"
+ result = "No Information"
+ hovertext = ("{name}
"
+ "Packet Throughput: {val:.2f}Mpps
"
+ "Final Duration: {time}
"
+ "Result: {result}".format(name=name,
+ val=y_val,
+ time=time,
+ result=result))
+ traces.append(plgo.Bar(x=[str(idx) + '.', ],
+ y=[y_val, ],
+ name=name,
+ text=hovertext,
+ hoverinfo="text"))
+ try:
+ # Create plot
+ layout = deepcopy(plot["layout"])
+ if layout.get("title", None):
+ layout["title"] = "Packet Throughput: {0}". \
+ format(layout["title"])
+ if y_max:
+ layout["yaxis"]["range"] = [0, y_max + 1]
+ plpl = plgo.Figure(data=traces, layout=layout)
+ # Export Plot
+ logging.info(" Writing file '{0}{1}'.".
+ format(plot["output-file"], plot["output-file-type"]))
+ ploff.plot(plpl, show_link=False, auto_open=False,
+ filename='{0}{1}'.format(plot["output-file"],
+ plot["output-file-type"]))
+ except PlotlyError as err:
+ logging.error(" Finished with error: {}".
+ format(repr(err).replace("\n", " ")))
+ return
+
+
+def plot_soak_boxes(plot, input_data):
+ """Generate the plot(s) with algorithm: plot_soak_boxes
+ specified in the specification file.
+
+ :param plot: Plot to generate.
+ :param input_data: Data to process.
+ :type plot: pandas.Series
+ :type input_data: InputData
+ """
+
+ # Transform the data
+ plot_title = plot.get("title", "")
+ logging.info(" Creating the data set for the {0} '{1}'.".
+ format(plot.get("type", ""), plot_title))
+ data = input_data.filter_data(plot)
+ if data is None:
+ logging.error("No data.")
+ return
+
+ # Prepare the data for the plot
+ y_vals = dict()
+ y_tags = dict()
+ for job in data:
+ for build in job:
+ for test in build:
+ if y_vals.get(test["parent"], None) is None:
+ y_tags[test["parent"]] = test.get("tags", None)
+ try:
+ if test["type"] in ("SOAK", ):
+ y_vals[test["parent"]] = test["throughput"]
+ else:
+ continue
+ except (KeyError, TypeError):
+ y_vals[test["parent"]] = dict()
+
+ # Sort the tests
+ order = plot.get("sort", None)
+ if order and y_tags:
+ y_sorted = OrderedDict()
+ y_tags_l = {s: [t.lower() for t in ts] for s, ts in y_tags.items()}
+ for tag in order:
+ logging.debug(tag)
+ for suite, tags in y_tags_l.items():
+ if "not " in tag:
+ tag = tag.split(" ")[-1]
+ if tag.lower() in tags:
+ continue
+ else:
+ if tag.lower() not in tags:
+ continue
+ try:
+ y_sorted[suite] = y_vals.pop(suite)
+ y_tags_l.pop(suite)
+ logging.debug(suite)
+ except KeyError as err:
+ logging.error("Not found: {0}".format(repr(err)))
+ finally:
+ break
+ else:
+ y_sorted = y_vals
+
+ idx = 0
+ y_max = 0
+ traces = list()
+ for test_name, test_data in y_sorted.items():
+ idx += 1
+ name = "{nr}. {name}".\
+ format(nr=idx, name=test_name.lower().replace('-soak', ''))
+ if len(name) > 50:
+ name_lst = name.split('-')
+ name = ""
+ split_name = True
+ for segment in name_lst:
+ if (len(name) + len(segment) + 1) > 50 and split_name:
+ name += "
"
+ split_name = False
+ name += segment + '-'
+ name = name[:-1]
+
+ y_val = test_data.get("UPPER", None)
+ if y_val:
+ y_val /= 1000000
+ if y_val > y_max:
+ y_max = y_val
+
+ y_base = test_data.get("LOWER", None)
+ if y_base:
+ y_base /= 1000000
+
+ hovertext = ("{name}
"
+ "Upper bound: {upper:.2f}Mpps
"
+ "Lower bound: {lower:.2f}Mpps".format(name=name,
+ upper=y_val,
+ lower=y_base))
+ traces.append(plgo.Bar(x=[str(idx) + '.', ],
+ # +0.05 to see the value in case lower == upper
+ y=[y_val - y_base + 0.05, ],
+ base=y_base,
+ name=name,
+ text=hovertext,
+ hoverinfo="text"))
+ try:
+ # Create plot
+ layout = deepcopy(plot["layout"])
+ if layout.get("title", None):
+ layout["title"] = "Soak Tests: {0}". \
+ format(layout["title"])
+ if y_max:
+ layout["yaxis"]["range"] = [0, y_max + 1]
+ plpl = plgo.Figure(data=traces, layout=layout)
+ # Export Plot
+ logging.info(" Writing file '{0}{1}'.".
+ format(plot["output-file"], plot["output-file-type"]))
+ ploff.plot(plpl, show_link=False, auto_open=False,
+ filename='{0}{1}'.format(plot["output-file"],
+ plot["output-file-type"]))
+ except PlotlyError as err:
+ logging.error(" Finished with error: {}".
+ format(repr(err).replace("\n", " ")))
+ return
+
+
def plot_latency_error_bars(plot, input_data):
"""Generate the plot(s) with algorithm: plot_latency_error_bars
specified in the specification file.
@@ -298,13 +541,13 @@ def plot_latency_error_bars(plot, input_data):
nr_of_samples = list()
for key, val in y_sorted.items():
name = "-".join(key.split("-")[1:-1])
- if len(name) > 60:
+ if len(name) > 50:
name_lst = name.split('-')
name = ""
split_name = True
for segment in name_lst:
- if (len(name) + len(segment) + 1) > 60 and split_name:
- name += "
"
+ if (len(name) + len(segment) + 1) > 50 and split_name:
+ name += "
"
split_name = False
name += segment + '-'
name = name[:-1]
@@ -332,11 +575,11 @@ def plot_latency_error_bars(plot, input_data):
direction = "West-East"
else:
direction = "East-West"
- hovertext = ("Test: {test}
"
- "Direction: {dir}
"
- "No. of Runs: {nr}
".format(test=x_vals[idx],
- dir=direction,
- nr=nr_of_samples[idx]))
+ hovertext = ("No. of Runs: {nr}
"
+ "Test: {test}
"
+ "Direction: {dir}
".format(test=x_vals[idx],
+ dir=direction,
+ nr=nr_of_samples[idx]))
if isinstance(y_maxs[idx], float):
hovertext += "Max: {max:.2f}uSec
".format(max=y_maxs[idx])
if isinstance(y_vals[idx], float):
@@ -487,13 +730,13 @@ def plot_throughput_speedup_analysis(plot, input_data):
try:
if test_vals["1"][1]:
name = "-".join(test_name.split('-')[1:-1])
- if len(name) > 60:
+ if len(name) > 50:
name_lst = name.split('-')
name = ""
split_name = True
for segment in name_lst:
- if (len(name) + len(segment) + 1) > 60 and split_name:
- name += "
"
+ if (len(name) + len(segment) + 1) > 50 and split_name:
+ name += "
"
split_name = False
name += segment + '-'
name = name[:-1]
@@ -545,6 +788,8 @@ def plot_throughput_speedup_analysis(plot, input_data):
limit = plot["limits"]["nic"]["xxv710"]
elif "xl710" in test_name:
limit = plot["limits"]["nic"]["xl710"]
+ elif "x553" in test_name:
+ limit = plot["limits"]["nic"]["x553"]
else:
limit = 0
if limit > nic_limit:
@@ -694,9 +939,9 @@ def plot_throughput_speedup_analysis(plot, input_data):
for idx in range(len(val["val"])):
htext = ""
if isinstance(val["val"][idx], float):
- htext += "Mean: {0:.2f}Mpps
" \
- "No. of Runs: {1}
".format(val["val"][idx],
- val["count"][idx])
+ htext += "No. of Runs: {1}
" \
+ "Mean: {0:.2f}Mpps
".format(val["val"][idx],
+ val["count"][idx])
if isinstance(val["diff"][idx], float):
htext += "Diff: {0:.0f}%
".format(round(val["diff"][idx]))
if isinstance(val["rel"][idx], float):
@@ -804,21 +1049,21 @@ def plot_http_server_performance_box(plot, input_data):
df = pd.DataFrame(y_vals)
df.head()
for i, col in enumerate(df.columns):
- name = "{0}. {1}".format(i + 1, col.lower().replace('-ndrpdr', ''))
- if len(name) > 60:
+ name = "{nr}. ({samples:02d} run{plural}) {name}".\
+ format(nr=(i + 1),
+ samples=nr_of_samples[i],
+ plural='s' if nr_of_samples[i] > 1 else '',
+ name=col.lower().replace('-ndrpdr', ''))
+ if len(name) > 50:
name_lst = name.split('-')
name = ""
split_name = True
for segment in name_lst:
- if (len(name) + len(segment) + 1) > 60 and split_name:
+ if (len(name) + len(segment) + 1) > 50 and split_name:
name += "
"
split_name = False
name += segment + '-'
name = name[:-1]
- name = "{name} ({samples} run{plural})".\
- format(name=name,
- samples=nr_of_samples[i],
- plural='s' if nr_of_samples[i] > 1 else '')
traces.append(plgo.Box(x=[str(i + 1) + '.'] * len(df[col]),
y=df[col],
@@ -838,3 +1083,244 @@ def plot_http_server_performance_box(plot, input_data):
logging.error(" Finished with error: {}".
format(str(err).replace("\n", " ")))
return
+
+
+def plot_service_density_heatmap(plot, input_data):
+ """Generate the plot(s) with algorithm: plot_service_density_heatmap
+ specified in the specification file.
+
+ :param plot: Plot to generate.
+ :param input_data: Data to process.
+ :type plot: pandas.Series
+ :type input_data: InputData
+ """
+
+ # Example data in Mpps
+ txt_chains = ['1', '2', '4', '6', '8', '10']
+ txt_nodes = ['1', '2', '4', '6', '8', '10']
+ chains = [i + 1 for i in range(len(txt_chains))]
+ nodes = [i + 1 for i in range(len(txt_nodes))]
+ data = [
+ [6.3, 6.3, 6.3, 6.4, 6.5, 6.4],
+ [5.8, 5.6, 5.6, 5.6, 5.5, None],
+ [5.6, 5.5, 5.3, None, None, None],
+ [5.4, 5.3, None, None, None, None],
+ [5.4, 5.2, None, None, None, None],
+ [5.3, None, None, None, None, None]
+ ]
+
+ hovertext = list()
+ annotations = list()
+
+ text = "{name}"
+
+ for c in range(len(txt_chains)):
+ hover_line = list()
+ for n in range(len(txt_nodes)):
+ if data[c][n] is not None:
+ annotations.append(dict(
+ x=n+1,
+ y=c+1,
+ xref="x",
+ yref="y",
+ xanchor="center",
+ yanchor="middle",
+ text=str(data[c][n]),
+ font=dict(
+ size=14,
+ ),
+ align="center",
+ showarrow=False
+ ))
+ hover_line.append(text.format(name="Testcase Name"))
+ hovertext.append(hover_line)
+
+ traces = [
+ plgo.Heatmap(x=nodes,
+ y=chains,
+ z=data,
+ colorbar=dict(
+ title="Packet Throughput [Mpps]",
+ titleside="right",
+ titlefont=dict(
+ size=14
+ ),
+ ),
+ showscale=True,
+ colorscale="Reds",
+ text=hovertext,
+ hoverinfo="text")
+ ]
+
+ for idx, item in enumerate(txt_nodes):
+ annotations.append(dict(
+ x=idx+1,
+ y=0,
+ xref="x",
+ yref="y",
+ xanchor="center",
+ yanchor="top",
+ text=item,
+ font=dict(
+ size=16,
+ ),
+ align="center",
+ showarrow=False
+ ))
+ for idx, item in enumerate(txt_chains):
+ annotations.append(dict(
+ x=0.3,
+ y=idx+1,
+ xref="x",
+ yref="y",
+ xanchor="right",
+ yanchor="middle",
+ text=item,
+ font=dict(
+ size=16,
+ ),
+ align="center",
+ showarrow=False
+ ))
+ # X-axis:
+ annotations.append(dict(
+ x=0.55,
+ y=1.05,
+ xref="paper",
+ yref="paper",
+ xanchor="center",
+ yanchor="middle",
+ text="No. of Network Functions per Service Instance",
+ font=dict(
+ size=16,
+ ),
+ align="center",
+ showarrow=False
+ ))
+ # Y-axis:
+ annotations.append(dict(
+ x=-0.04,
+ y=0.5,
+ xref="paper",
+ yref="paper",
+ xanchor="center",
+ yanchor="middle",
+ text="No. of Service Instances",
+ font=dict(
+ size=16,
+ ),
+ align="center",
+ textangle=270,
+ showarrow=False
+ ))
+ updatemenus = list([
+ dict(
+ x=1.0,
+ y=0.0,
+ xanchor='right',
+ yanchor='bottom',
+ direction='up',
+ buttons=list([
+ dict(
+ args=[{"colorscale": "Reds", "reversescale": False}],
+ label="Red",
+ method="update"
+ ),
+ dict(
+ args=[{"colorscale": "Blues", "reversescale": True}],
+ label="Blue",
+ method="update"
+ ),
+ dict(
+ args=[{"colorscale": "Greys", "reversescale": True}],
+ label="Grey",
+ method="update"
+ ),
+ dict(
+ args=[{"colorscale": "Greens", "reversescale": True}],
+ label="Green",
+ method="update"
+ ),
+ dict(
+ args=[{"colorscale": "RdBu", "reversescale": False}],
+ label="RedBlue",
+ method="update"
+ ),
+ dict(
+ args=[{"colorscale": "Picnic", "reversescale": False}],
+ label="Picnic",
+ method="update"
+ ),
+ dict(
+ args=[{"colorscale": "Rainbow", "reversescale": False}],
+ label="Rainbow",
+ method="update"
+ ),
+ dict(
+ args=[{"colorscale": "Portland", "reversescale": False}],
+ label="Portland",
+ method="update"
+ ),
+ dict(
+ args=[{"colorscale": "Jet", "reversescale": False}],
+ label="Jet",
+ method="update"
+ ),
+ dict(
+ args=[{"colorscale": "Hot", "reversescale": True}],
+ label="Hot",
+ method="update"
+ ),
+ dict(
+ args=[{"colorscale": "Blackbody", "reversescale": True}],
+ label="Blackbody",
+ method="update"
+ ),
+ dict(
+ args=[{"colorscale": "Earth", "reversescale": True}],
+ label="Earth",
+ method="update"
+ ),
+ dict(
+ args=[{"colorscale": "Electric", "reversescale": True}],
+ label="Electric",
+ method="update"
+ ),
+ dict(
+ args=[{"colorscale": "Viridis", "reversescale": True}],
+ label="Viridis",
+ method="update"
+ ),
+ dict(
+ args=[{"colorscale": "Cividis", "reversescale": True}],
+ label="Cividis",
+ method="update"
+ ),
+ ])
+ )
+ ])
+
+ try:
+ layout = deepcopy(plot["layout"])
+ except KeyError as err:
+ logging.error("Finished with error: No layout defined")
+ logging.error(repr(err))
+ return
+
+ layout["annotations"] = annotations
+ layout['updatemenus'] = updatemenus
+
+ try:
+ # Create plot
+ plpl = plgo.Figure(data=traces, layout=layout)
+
+ # Export Plot
+ logging.info(" Writing file '{0}{1}'.".
+ format(plot["output-file"], plot["output-file-type"]))
+ ploff.plot(plpl, show_link=False, auto_open=False,
+ filename='{0}{1}'.format(plot["output-file"],
+ plot["output-file-type"]))
+ except PlotlyError as err:
+ logging.error(" Finished with error: {}".
+ format(str(err).replace("\n", " ")))
+ return