+ if u"-gbps" in plot_title:
+ value = u"gbps"
+ h_unit = u"Gbps"
+ multiplier = 1e6
+ else:
+ value = u"throughput"
+ h_unit = u"Mpps"
+ multiplier = 1.0
+
+ for ttype in plot.get(u"test-type", (u"ndr", u"pdr")):
+ y_vals = OrderedDict()
+ for item in plot.get(u"include", tuple()):
+ reg_ex = re.compile(str(item).lower())
+ for job in data:
+ for build in job:
+ for test_id, test in build.iteritems():
+ if re.match(reg_ex, str(test_id).lower()):
+ if y_vals.get(test[u"parent"], None) is None:
+ y_vals[test[u"parent"]] = {
+ u"1": list(),
+ u"2": list(),
+ u"4": list()
+ }
+ try:
+ if test[u"type"] not in (u"NDRPDR", u"CPS"):
+ continue
+
+ if u"1C" in test[u"tags"]:
+ y_vals[test[u"parent"]][u"1"].append(
+ test[value][ttype.upper()][u"LOWER"] *
+ multiplier
+ )
+ elif u"2C" in test[u"tags"]:
+ y_vals[test[u"parent"]][u"2"].append(
+ test[value][ttype.upper()][u"LOWER"] *
+ multiplier
+ )
+ elif u"4C" in test[u"tags"]:
+ y_vals[test[u"parent"]][u"4"].append(
+ test[value][ttype.upper()][u"LOWER"] *
+ multiplier
+ )
+ except (KeyError, TypeError):
+ pass
+
+ if not y_vals:
+ logging.warning(f"No data for the plot {plot.get(u'title', u'')}")
+ return
+
+ y_1c_max = dict()
+ for test_name, test_vals in y_vals.items():
+ for key, test_val in test_vals.items():
+ if test_val:
+ avg_val = sum(test_val) / len(test_val)
+ y_vals[test_name][key] = [avg_val, len(test_val)]
+ ideal = avg_val / (int(key) * 1e6)
+ if test_name not in y_1c_max or ideal > y_1c_max[test_name]:
+ y_1c_max[test_name] = ideal
+
+ vals = OrderedDict()
+ y_max = list()
+ nic_limit = 0
+ lnk_limit = 0
+ pci_limit = 0
+ for test_name, test_vals in y_vals.items():
+ try:
+ if test_vals[u"1"][1]:
+ name = re.sub(
+ REGEX_NIC,
+ u"",
+ test_name.replace(u'-ndrpdr', u'').
+ replace(u'2n1l-', u'')
+ )
+ vals[name] = OrderedDict()
+ y_val_1 = test_vals[u"1"][0] / 1e6
+ y_val_2 = test_vals[u"2"][0] / 1e6 if test_vals[u"2"][0] \
+ else None
+ y_val_4 = test_vals[u"4"][0] / 1e6 if test_vals[u"4"][0] \
+ else None
+
+ vals[name][u"val"] = [y_val_1, y_val_2, y_val_4]
+ vals[name][u"rel"] = [1.0, None, None]
+ vals[name][u"ideal"] = [
+ y_1c_max[test_name],
+ y_1c_max[test_name] * 2,
+ y_1c_max[test_name] * 4
+ ]
+ vals[name][u"diff"] = [
+ (y_val_1 - y_1c_max[test_name]) * 100 / y_val_1,
+ None,
+ None
+ ]
+ vals[name][u"count"] = [
+ test_vals[u"1"][1],
+ test_vals[u"2"][1],
+ test_vals[u"4"][1]
+ ]
+
+ try:
+ val_max = max(vals[name][u"val"])
+ except ValueError as err:
+ logging.error(repr(err))
+ continue
+ if val_max:
+ y_max.append(val_max)
+
+ if y_val_2:
+ vals[name][u"rel"][1] = round(y_val_2 / y_val_1, 2)
+ vals[name][u"diff"][1] = \
+ (y_val_2 - vals[name][u"ideal"][1]) * 100 / y_val_2
+ if y_val_4:
+ vals[name][u"rel"][2] = round(y_val_4 / y_val_1, 2)
+ vals[name][u"diff"][2] = \
+ (y_val_4 - vals[name][u"ideal"][2]) * 100 / y_val_4
+ except IndexError as err:
+ logging.warning(f"No data for {test_name}")
+ logging.warning(repr(err))
+
+ # Limits:
+ if u"x520" in test_name:
+ limit = plot[u"limits"][u"nic"][u"x520"]
+ elif u"x710" in test_name:
+ limit = plot[u"limits"][u"nic"][u"x710"]
+ elif u"xxv710" in test_name:
+ limit = plot[u"limits"][u"nic"][u"xxv710"]
+ elif u"xl710" in test_name:
+ limit = plot[u"limits"][u"nic"][u"xl710"]
+ elif u"x553" in test_name:
+ limit = plot[u"limits"][u"nic"][u"x553"]
+ elif u"cx556a" in test_name:
+ limit = plot[u"limits"][u"nic"][u"cx556a"]
+ elif u"e810cq" in test_name:
+ limit = plot[u"limits"][u"nic"][u"e810cq"]
+ elif u"e810xxv" in test_name:
+ limit = plot[u"limits"][u"nic"][u"e810xxv"]
+ else:
+ limit = 0
+ if limit > nic_limit:
+ nic_limit = limit
+
+ mul = 2 if u"ge2p" in test_name else 1
+ if u"10ge" in test_name:
+ limit = plot[u"limits"][u"link"][u"10ge"] * mul
+ elif u"25ge" in test_name:
+ limit = plot[u"limits"][u"link"][u"25ge"] * mul
+ elif u"40ge" in test_name:
+ limit = plot[u"limits"][u"link"][u"40ge"] * mul
+ elif u"100ge" in test_name:
+ limit = plot[u"limits"][u"link"][u"100ge"] * mul
+ else:
+ limit = 0
+ if limit > lnk_limit:
+ lnk_limit = limit
+
+ if u"cx556a" in test_name:
+ limit = plot[u"limits"][u"pci"][u"pci-g3-x8"]
+ else:
+ limit = plot[u"limits"][u"pci"][u"pci-g3-x16"]
+ if limit > pci_limit:
+ pci_limit = limit
+
+ traces = list()
+ annotations = list()
+ x_vals = [1, 2, 4]
+
+ # Limits:
+ if u"-gbps" not in plot_title and u"-cps-" not in plot_title:
+ nic_limit /= 1e6
+ lnk_limit /= 1e6
+ pci_limit /= 1e6
+ min_limit = min((nic_limit, lnk_limit, pci_limit))
+ if nic_limit == min_limit:
+ traces.append(plgo.Scatter(
+ x=x_vals,
+ y=[nic_limit, ] * len(x_vals),
+ name=f"NIC: {nic_limit:.2f}Mpps",
+ showlegend=False,
+ mode=u"lines",
+ line=dict(
+ dash=u"dot",
+ color=COLORS[-1],
+ width=1),
+ hoverinfo=u"none"
+ ))
+ annotations.append(dict(
+ x=1,
+ y=nic_limit,
+ xref=u"x",
+ yref=u"y",
+ xanchor=u"left",
+ yanchor=u"bottom",
+ text=f"NIC: {nic_limit:.2f}Mpps",
+ font=dict(
+ size=14,
+ color=COLORS[-1],
+ ),
+ align=u"left",
+ showarrow=False
+ ))
+ y_max.append(nic_limit)
+ elif lnk_limit == min_limit:
+ traces.append(plgo.Scatter(
+ x=x_vals,
+ y=[lnk_limit, ] * len(x_vals),
+ name=f"Link: {lnk_limit:.2f}Mpps",
+ showlegend=False,
+ mode=u"lines",
+ line=dict(
+ dash=u"dot",
+ color=COLORS[-1],
+ width=1),
+ hoverinfo=u"none"
+ ))
+ annotations.append(dict(
+ x=1,
+ y=lnk_limit,
+ xref=u"x",
+ yref=u"y",
+ xanchor=u"left",
+ yanchor=u"bottom",
+ text=f"Link: {lnk_limit:.2f}Mpps",
+ font=dict(
+ size=14,
+ color=COLORS[-1],
+ ),
+ align=u"left",
+ showarrow=False
+ ))
+ y_max.append(lnk_limit)
+ elif pci_limit == min_limit:
+ traces.append(plgo.Scatter(
+ x=x_vals,
+ y=[pci_limit, ] * len(x_vals),
+ name=f"PCIe: {pci_limit:.2f}Mpps",
+ showlegend=False,
+ mode=u"lines",
+ line=dict(
+ dash=u"dot",
+ color=COLORS[-1],
+ width=1),
+ hoverinfo=u"none"
+ ))
+ annotations.append(dict(
+ x=1,
+ y=pci_limit,
+ xref=u"x",
+ yref=u"y",
+ xanchor=u"left",
+ yanchor=u"bottom",
+ text=f"PCIe: {pci_limit:.2f}Mpps",
+ font=dict(
+ size=14,
+ color=COLORS[-1],
+ ),
+ align=u"left",
+ showarrow=False
+ ))
+ y_max.append(pci_limit)
+
+ # Perfect and measured:
+ cidx = 0
+ for name, val in vals.items():
+ hovertext = list()
+ try:
+ for idx in range(len(val[u"val"])):
+ htext = ""
+ if isinstance(val[u"val"][idx], float):
+ htext += (
+ f"No. of Runs: {val[u'count'][idx]}<br>"
+ f"Mean: {val[u'val'][idx]:.2f}{h_unit}<br>"
+ )
+ if isinstance(val[u"diff"][idx], float):
+ htext += f"Diff: {round(val[u'diff'][idx]):.0f}%<br>"
+ if isinstance(val[u"rel"][idx], float):
+ htext += f"Speedup: {val[u'rel'][idx]:.2f}"
+ hovertext.append(htext)
+ traces.append(
+ plgo.Scatter(
+ x=x_vals,
+ y=val[u"val"],
+ name=name,
+ legendgroup=name,
+ mode=u"lines+markers",
+ line=dict(
+ color=COLORS[cidx],
+ width=2),
+ marker=dict(
+ symbol=u"circle",
+ size=10
+ ),
+ text=hovertext,
+ hoverinfo=u"text+name"
+ )
+ )
+ traces.append(
+ plgo.Scatter(
+ x=x_vals,
+ y=val[u"ideal"],
+ name=f"{name} perfect",
+ legendgroup=name,
+ showlegend=False,
+ mode=u"lines",
+ line=dict(
+ color=COLORS[cidx],
+ width=2,
+ dash=u"dash"),
+ text=[f"Perfect: {y:.2f}Mpps" for y in val[u"ideal"]],
+ hoverinfo=u"text"
+ )
+ )
+ cidx += 1
+ except (IndexError, ValueError, KeyError) as err:
+ logging.warning(f"No data for {name}\n{repr(err)}")
+
+ try:
+ # Create plot
+ file_name = f"{plot[u'output-file'].format(test_type=ttype)}.html"
+ logging.info(f" Writing file {file_name}")
+ layout = deepcopy(plot[u"layout"])
+ if layout.get(u"title", None):
+ layout[u"title"] = (
+ f"<b>Speedup Multi-core:</b> "
+ f"{layout[u'title'].format(test_type=ttype)}"
+ )
+ layout[u"yaxis"][u"range"] = [0, int(max(y_max) * 1.1)]
+ layout[u"annotations"].extend(annotations)
+ plpl = plgo.Figure(data=traces, layout=layout)
+
+ # Export Plot
+ ploff.plot(
+ plpl,
+ show_link=False,
+ auto_open=False,
+ filename=file_name
+ )
+ except PlotlyError as err:
+ logging.error(
+ f" Finished with error: {repr(err)}".replace(u"\n", u" ")
+ )
+
+
+def plot_http_server_perf_box(plot, input_data):
+ """Generate the plot(s) with algorithm: plot_http_server_perf_box