diff options
author | Tibor Frank <tifrank@cisco.com> | 2022-05-19 14:24:15 +0200 |
---|---|---|
committer | Tibor Frank <tifrank@cisco.com> | 2022-06-09 11:00:10 +0000 |
commit | a6c94c7c5898fb8570f6f9ca6fdc1909d43c5dc0 (patch) | |
tree | 934f6cda980c0b7ac105092f0db00e88a992e780 /resources/tools/dash/app/pal/report | |
parent | 400205b1f838b88e72236559308d9c4b3ee61aa4 (diff) |
feat(uti): Add statistical graphs
Change-Id: Ia2831cfbcb9e2333c5b49af5c6b0577867d99902
Signed-off-by: Tibor Frank <tifrank@cisco.com>
Diffstat (limited to 'resources/tools/dash/app/pal/report')
-rw-r--r-- | resources/tools/dash/app/pal/report/graphs.py | 228 | ||||
-rw-r--r-- | resources/tools/dash/app/pal/report/layout.py | 74 | ||||
-rw-r--r-- | resources/tools/dash/app/pal/report/layout.yaml | 118 |
3 files changed, 314 insertions, 106 deletions
diff --git a/resources/tools/dash/app/pal/report/graphs.py b/resources/tools/dash/app/pal/report/graphs.py index 751eb34006..42ae07938e 100644 --- a/resources/tools/dash/app/pal/report/graphs.py +++ b/resources/tools/dash/app/pal/report/graphs.py @@ -14,21 +14,18 @@ """ """ +import re import plotly.graph_objects as go import pandas as pd +from copy import deepcopy + import hdrh.histogram import hdrh.codec -_COLORS = ( - u"#1A1110", u"#DA2647", u"#214FC6", u"#01786F", u"#BD8260", u"#FFD12A", - u"#A6E7FF", u"#738276", u"#C95A49", u"#FC5A8D", u"#CEC8EF", u"#391285", - u"#6F2DA8", u"#FF878D", u"#45A27D", u"#FFD0B9", u"#FD5240", u"#DB91EF", - u"#44D7A8", u"#4F86F7", u"#84DE02", u"#FFCFF1", u"#614051" -) _VALUE = { - "mrr": "result_receive_rate_rate_avg", + "mrr": "result_receive_rate_rate_values", "ndr": "result_ndr_lower_rate_value", "pdr": "result_pdr_lower_rate_value", "pdr-lat": "result_latency_forward_pdr_50_avg" @@ -63,6 +60,37 @@ _GRAPH_LAT_HDRH_DESC = { u"result_latency_forward_pdr_90_hdrh": u"High-load, 90% PDR.", u"result_latency_reverse_pdr_90_hdrh": u"High-load, 90% PDR." } +REG_EX_VPP_VERSION = re.compile(r"^(\d{2}).(\d{2})-(rc0|rc1|rc2|release$)") + + +def _get_color(idx: int) -> str: + """ + """ + _COLORS = ( + "#1A1110", "#DA2647", "#214FC6", "#01786F", "#BD8260", "#FFD12A", + "#A6E7FF", "#738276", "#C95A49", "#FC5A8D", "#CEC8EF", "#391285", + "#6F2DA8", "#FF878D", "#45A27D", "#FFD0B9", "#FD5240", "#DB91EF", + "#44D7A8", "#4F86F7", "#84DE02", "#FFCFF1", "#614051" + ) + return _COLORS[idx % len(_COLORS)] + + +def get_short_version(version: str, dut_type: str="vpp") -> str: + """ + """ + + if dut_type in ("trex", "dpdk"): + return version + + s_version = str() + groups = re.search(pattern=REG_EX_VPP_VERSION, string=version) + if groups: + try: + s_version = f"{groups.group(1)}.{groups.group(2)}_{groups.group(3)}" + except IndexError: + pass + + return s_version def select_iterative_data(data: pd.DataFrame, itm:dict) -> pd.DataFrame: @@ -82,18 +110,31 @@ def select_iterative_data(data: pd.DataFrame, itm:dict) -> pd.DataFrame: core = str() if itm["dut"] == "trex" else f"{itm['core']}" ttype = "ndrpdr" if itm["testtype"] in ("ndr", "pdr") else itm["testtype"] - dut = "none" if itm["dut"] == "trex" else itm["dut"].upper() + dut_v100 = "none" if itm["dut"] == "trex" else itm["dut"] + dut_v101 = itm["dut"] df = data.loc[( - (data["dut_type"] == dut) & + (data["release"] == itm["rls"]) & + ( + ( + (data["version"] == "1.0.0") & + (data["dut_type"].str.lower() == dut_v100) + ) | + ( + (data["version"] == "1.0.1") & + (data["dut_type"].str.lower() == dut_v101) + ) + ) & (data["test_type"] == ttype) & (data["passed"] == True) )] - df = df[df.job.str.endswith(f"{topo}-{arch}")] - df = df[df.test_id.str.contains( - f"^.*[.|-]{nic}.*{itm['framesize']}-{core}-{drv}{itm['test']}-{ttype}$", - regex=True - )].sort_values(by="start_time", ignore_index=True) + regex_test = \ + f"^.*[.|-]{nic}.*{itm['framesize']}-{core}-{drv}{itm['test']}-{ttype}$" + df = df[ + (df.job.str.endswith(f"{topo}-{arch}")) & + (df.dut_version.str.contains(itm["dutver"].replace("_", "-"))) & + (df.test_id.str.contains(regex_test, regex=True)) + ] return df @@ -102,56 +143,129 @@ def graph_iterative(data: pd.DataFrame, sel:dict, layout: dict) -> tuple: """ """ - fig_tput = go.Figure() - fig_tsa = go.Figure() + fig_tput = None + fig_lat = None + + tput_traces = list() + y_tput_max = 0 + lat_traces = list() + y_lat_max = 0 + x_lat = list() + for idx, itm in enumerate(sel): + itm_data = select_iterative_data(data, itm) + if itm["testtype"] == "mrr": + y_data = itm_data[_VALUE[itm["testtype"]]].to_list()[0] + if y_data.size > 0: + y_tput_max = \ + max(y_data) if max(y_data) > y_tput_max else y_tput_max + else: + y_data = itm_data[_VALUE[itm["testtype"]]].to_list() + if y_data: + y_tput_max = \ + max(y_data) if max(y_data) > y_tput_max else y_tput_max + nr_of_samples = len(y_data) + tput_kwargs = dict( + y=y_data, + name=( + f"{idx + 1}. " + f"({nr_of_samples:02d} " + f"run{u's' if nr_of_samples > 1 else u''}) " + f"{itm['id']}" + ), + hoverinfo=u"y+name", + boxpoints="all", + jitter=0.3, + marker=dict(color=_get_color(idx)) + ) + tput_traces.append(go.Box(**tput_kwargs)) + + show_latency = False + if itm["testtype"] == "pdr": + y_lat = itm_data[_VALUE["pdr-lat"]].to_list() + if y_lat: + y_lat_max = max(y_lat) if max(y_lat) > y_lat_max else y_lat_max + nr_of_samples = len(y_lat) + lat_kwargs = dict( + y=y_lat, + name=( + f"{idx + 1}. " + f"({nr_of_samples:02d} " + f"run{u's' if nr_of_samples > 1 else u''}) " + f"{itm['id']}" + ), + hoverinfo=u"y+name", + boxpoints="all", + jitter=0.3, + marker=dict(color=_get_color(idx)) + ) + x_lat.append(idx + 1) + lat_traces.append(go.Box(**lat_kwargs)) + show_latency = True + else: + lat_traces.append(go.Box()) - return fig_tput, fig_tsa + pl_tput = deepcopy(layout["plot-throughput"]) + pl_tput[u"xaxis"][u"tickvals"] = [i for i in range(len(sel))] + pl_tput[u"xaxis"][u"ticktext"] = [str(i + 1) for i in range(len(sel))] + if y_tput_max: + pl_tput[u"yaxis"][u"range"] = [0, (int(y_tput_max / 1e6) + 1) * 1e6] + fig_tput = go.Figure(data=tput_traces, layout=pl_tput) + + if show_latency: + pl_lat = deepcopy(layout["plot-latency"]) + pl_lat[u"xaxis"][u"tickvals"] = [i for i in range(len(x_lat))] + pl_lat[u"xaxis"][u"ticktext"] = x_lat + if y_lat_max: + pl_lat[u"yaxis"][u"range"] = [0, (int(y_lat_max / 10) + 1) * 10] + fig_lat = go.Figure(data=lat_traces, layout=pl_lat) + + return fig_tput, fig_lat def table_comparison(data: pd.DataFrame, sel:dict) -> pd.DataFrame: """ """ table = pd.DataFrame( - { - "Test Case": [ - "64b-2t1c-avf-eth-l2xcbase-eth-2memif-1dcr", - "64b-2t1c-avf-eth-l2xcbase-eth-2vhostvr1024-1vm-vppl2xc", - "64b-2t1c-avf-ethip4udp-ip4base-iacl50sl-10kflows", - "78b-2t1c-avf-ethip6-ip6scale2m-rnd "], - "2106.0-8": [ - "14.45 +- 0.08", - "9.63 +- 0.05", - "9.7 +- 0.02", - "8.95 +- 0.06"], - "2110.0-8": [ - "14.45 +- 0.08", - "9.63 +- 0.05", - "9.7 +- 0.02", - "8.95 +- 0.06"], - "2110.0-9": [ - "14.45 +- 0.08", - "9.63 +- 0.05", - "9.7 +- 0.02", - "8.95 +- 0.06"], - "2202.0-9": [ - "14.45 +- 0.08", - "9.63 +- 0.05", - "9.7 +- 0.02", - "8.95 +- 0.06"], - "2110.0-9 vs 2110.0-8": [ - "-0.23 +- 0.62", - "-1.37 +- 1.3", - "+0.08 +- 0.2", - "-2.16 +- 0.83"], - "2202.0-9 vs 2110.0-9": [ - "+6.95 +- 0.72", - "+5.35 +- 1.26", - "+4.48 +- 1.48", - "+4.09 +- 0.95"] - } -) + { + "Test Case": [ + "64b-2t1c-avf-eth-l2xcbase-eth-2memif-1dcr", + "64b-2t1c-avf-eth-l2xcbase-eth-2vhostvr1024-1vm-vppl2xc", + "64b-2t1c-avf-ethip4udp-ip4base-iacl50sl-10kflows", + "78b-2t1c-avf-ethip6-ip6scale2m-rnd "], + "2106.0-8": [ + "14.45 +- 0.08", + "9.63 +- 0.05", + "9.7 +- 0.02", + "8.95 +- 0.06"], + "2110.0-8": [ + "14.45 +- 0.08", + "9.63 +- 0.05", + "9.7 +- 0.02", + "8.95 +- 0.06"], + "2110.0-9": [ + "14.45 +- 0.08", + "9.63 +- 0.05", + "9.7 +- 0.02", + "8.95 +- 0.06"], + "2202.0-9": [ + "14.45 +- 0.08", + "9.63 +- 0.05", + "9.7 +- 0.02", + "8.95 +- 0.06"], + "2110.0-9 vs 2110.0-8": [ + "-0.23 +- 0.62", + "-1.37 +- 1.3", + "+0.08 +- 0.2", + "-2.16 +- 0.83"], + "2202.0-9 vs 2110.0-9": [ + "+6.95 +- 0.72", + "+5.35 +- 1.26", + "+4.48 +- 1.48", + "+4.09 +- 0.95"] + } + ) - return table + return pd.DataFrame() #table def graph_hdrh_latency(data: dict, layout: dict) -> go.Figure: @@ -206,7 +320,7 @@ def graph_hdrh_latency(data: dict, layout: dict) -> go.Figure: legendgroup=_GRAPH_LAT_HDRH_DESC[lat_name], showlegend=bool(idx % 2), line=dict( - color=_COLORS[int(idx/2)], + color=_get_color(int(idx/2)), dash=u"solid", width=1 if idx % 2 else 2 ), diff --git a/resources/tools/dash/app/pal/report/layout.py b/resources/tools/dash/app/pal/report/layout.py index 26b9a9f4b5..ef98b7b376 100644 --- a/resources/tools/dash/app/pal/report/layout.py +++ b/resources/tools/dash/app/pal/report/layout.py @@ -33,7 +33,7 @@ from pprint import pformat from ..data.data import Data from ..data.url_processing import url_decode, url_encode -from .graphs import graph_iterative, table_comparison +from .graphs import graph_iterative, table_comparison, get_short_version class Layout: @@ -116,9 +116,9 @@ class Layout: for _, row in self._data[cols].drop_duplicates().iterrows(): rls = row["release"] ttype = row["test_type"] - d_ver = row["dut_version"] lst_job = row["job"].split("-") dut = lst_job[1] + d_ver = get_short_version(row["dut_version"], dut) tbed = "-".join(lst_job[-2:]) lst_test_id = row["test_id"].split(".") if dut == "dpdk": @@ -131,10 +131,7 @@ class Layout: nic = suite.split("-")[0] for drv in self.DRIVERS: if drv in test: - if drv == "af-xdp": - driver = "af_xdp" - else: - driver = drv + driver = drv.replace("-", "_") test = test.replace(f"{drv}-", "") break else: @@ -157,20 +154,27 @@ class Layout: tbs[rls][dut][d_ver][infra][area] = dict() if tbs[rls][dut][d_ver][infra][area].get(test, None) is None: tbs[rls][dut][d_ver][infra][area][test] = dict() - tbs_test = tbs[rls][dut][d_ver][infra][area][test] - tbs_test["core"] = list() - tbs_test["frame-size"] = list() - tbs_test["test-type"] = list() - if core.upper() not in tbs_test["core"]: - tbs_test["core"].append(core.upper()) - if framesize.upper() not in tbs_test["frame-size"]: - tbs_test["frame-size"].append(framesize.upper()) + tbs[rls][dut][d_ver][infra][area][test]["core"] = list() + tbs[rls][dut][d_ver][infra][area][test]["frame-size"] = list() + tbs[rls][dut][d_ver][infra][area][test]["test-type"] = list() + if core.upper() not in \ + tbs[rls][dut][d_ver][infra][area][test]["core"]: + tbs[rls][dut][d_ver][infra][area][test]["core"].append( + core.upper()) + if framesize.upper() not in \ + tbs[rls][dut][d_ver][infra][area][test]["frame-size"]: + tbs[rls][dut][d_ver][infra][area][test]["frame-size"].append( + framesize.upper()) if ttype == "mrr": - if "MRR" not in tbs_test["test-type"]: - tbs_test["test-type"].append("MRR") + if "MRR" not in \ + tbs[rls][dut][d_ver][infra][area][test]["test-type"]: + tbs[rls][dut][d_ver][infra][area][test]["test-type"].append( + "MRR") elif ttype == "ndrpdr": - if "NDR" not in tbs_test["test-type"]: - tbs_test["test-type"].extend(("NDR", "PDR", )) + if "NDR" not in \ + tbs[rls][dut][d_ver][infra][area][test]["test-type"]: + tbs[rls][dut][d_ver][infra][area][test]["test-type"].extend( + ("NDR", "PDR", )) self._spec_tbs = tbs # Read from files: @@ -366,8 +370,8 @@ class Layout: width=6 ), dbc.Col( - dbc.Row( # TSA - id="row-graph-tsa", + dbc.Row( # Latency + id="row-graph-lat", class_name="g-0 p-2", children=[ self.PLACEHOLDER @@ -787,10 +791,10 @@ class Layout: """ """ - (fig_tput, fig_tsa) = figs + (fig_tput, fig_lat) = figs row_fig_tput = self.PLACEHOLDER - row_fig_tsa = self.PLACEHOLDER + row_fig_lat = self.PLACEHOLDER row_table = self.PLACEHOLDER row_btn_dwnld = self.PLACEHOLDER @@ -840,11 +844,11 @@ class Layout: ] ) ] - if fig_tsa: - row_fig_tsa = [ + if fig_lat: + row_fig_lat = [ dcc.Graph( id={"type": "graph", "index": "lat"}, - figure=fig_tsa + figure=fig_lat ) ] if not table.empty: @@ -858,13 +862,13 @@ class Layout: ) ] - return row_fig_tput, row_fig_tsa, row_table, row_btn_dwnld + return row_fig_tput, row_fig_lat, row_table, row_btn_dwnld @app.callback( Output("control-panel", "data"), # Store Output("selected-tests", "data"), # Store Output("row-graph-tput", "children"), - Output("row-graph-tsa", "children"), + Output("row-graph-lat", "children"), Output("row-table", "children"), Output("row-btn-download", "children"), Output("row-card-sel-tests", "style"), @@ -950,7 +954,7 @@ class Layout: parsed_url = url_decode(href) row_fig_tput = no_update - row_fig_tsa = no_update + row_fig_lat = no_update row_table = no_update row_btn_dwnld = no_update row_card_sel_tests = no_update @@ -1282,7 +1286,7 @@ class Layout: ctrl_panel.set({ "cl-selected-options": self._list_tests(store_sel) }) - row_fig_tput, row_fig_tsa, row_table, row_btn_dwnld = \ + row_fig_tput, row_fig_lat, row_table, row_btn_dwnld = \ _generate_plotting_area( graph_iterative(self.data, store_sel, self.layout), table_comparison(self.data, store_sel), @@ -1291,7 +1295,7 @@ class Layout: elif trigger_id == "btn-sel-remove-all": _ = btn_remove_all row_fig_tput = self.PLACEHOLDER - row_fig_tsa = self.PLACEHOLDER + row_fig_lat = self.PLACEHOLDER row_table = self.PLACEHOLDER row_btn_dwnld = self.PLACEHOLDER row_card_sel_tests = self.STYLE_DISABLED @@ -1307,7 +1311,7 @@ class Layout: new_store_sel.append(item) store_sel = new_store_sel if store_sel: - row_fig_tput, row_fig_tsa, row_table, row_btn_dwnld = \ + row_fig_tput, row_fig_lat, row_table, row_btn_dwnld = \ _generate_plotting_area( graph_iterative(self.data, store_sel, self.layout), table_comparison(self.data, store_sel), @@ -1318,7 +1322,7 @@ class Layout: }) else: row_fig_tput = self.PLACEHOLDER - row_fig_tsa = self.PLACEHOLDER + row_fig_lat = self.PLACEHOLDER row_table = self.PLACEHOLDER row_btn_dwnld = self.PLACEHOLDER row_card_sel_tests = self.STYLE_DISABLED @@ -1332,7 +1336,7 @@ class Layout: store_sel = literal_eval( url_params.get("store_sel", list())[0]) if store_sel: - row_fig_tput, row_fig_tsa, row_table, row_btn_dwnld = \ + row_fig_tput, row_fig_lat, row_table, row_btn_dwnld = \ _generate_plotting_area( graph_iterative(self.data, store_sel, self.layout), @@ -1346,7 +1350,7 @@ class Layout: }) else: row_fig_tput = self.PLACEHOLDER - row_fig_tsa = self.PLACEHOLDER + row_fig_lat = self.PLACEHOLDER row_table = self.PLACEHOLDER row_btn_dwnld = self.PLACEHOLDER row_card_sel_tests = self.STYLE_DISABLED @@ -1364,7 +1368,7 @@ class Layout: ret_val = [ ctrl_panel.panel, store_sel, - row_fig_tput, row_fig_tsa, row_table, row_btn_dwnld, + row_fig_tput, row_fig_lat, row_table, row_btn_dwnld, row_card_sel_tests, row_btns_sel_tests ] ret_val.extend(ctrl_panel.values()) diff --git a/resources/tools/dash/app/pal/report/layout.yaml b/resources/tools/dash/app/pal/report/layout.yaml index 6fa91f31f1..e6ee788a0f 100644 --- a/resources/tools/dash/app/pal/report/layout.yaml +++ b/resources/tools/dash/app/pal/report/layout.yaml @@ -1,10 +1,6 @@ plot-throughput: - titlefont: - size: 16 xaxis: title: "<b>Test Cases [Index]</b>" - titlefont: - size: 14 autorange: True fixedrange: False gridcolor: "rgb(230, 230, 230)" @@ -15,24 +11,18 @@ plot-throughput: showticklabels: True tickcolor: "rgb(220, 220, 220)" tickmode: "array" - tickfont: - size: 14 zeroline: False yaxis: - title: "<b>Packet Throughput [Mpps]</b>" - titlefont: - size: 14 + title: "<b>Packet Throughput [pps]</b>" gridcolor: "rgb(230, 230, 230)" - hoverformat: ".4r" - tickformat: ".3r" + hoverformat: ".3s" + tickformat: ".3s" linecolor: "rgb(220, 220, 220)" linewidth: 1 showgrid: True showline: True showticklabels: True tickcolor: "rgb(220, 220, 220)" - tickfont: - size: 14 zeroline: False range: [0, 50] autosize: False @@ -45,7 +35,52 @@ plot-throughput: legend: orientation: "h" font: - size: 14 + size: 10 + width: 700 + height: 900 + paper_bgcolor: "#fff" + plot_bgcolor: "#fff" + hoverlabel: + namelength: -1 + +plot-latency: + xaxis: + title: "<b>Test Cases [Index]</b>" + autorange: True + fixedrange: False + gridcolor: "rgb(230, 230, 230)" + linecolor: "rgb(220, 220, 220)" + linewidth: 1 + showgrid: True + showline: True + showticklabels: True + tickcolor: "rgb(220, 220, 220)" + tickmode: "array" + zeroline: False + yaxis: + title: "<b>Packet Latency [us]</b>" + gridcolor: "rgb(230, 230, 230)" + hoverformat: ".3s" + tickformat: ".3s" + linecolor: "rgb(220, 220, 220)" + linewidth: 1 + showgrid: True + showline: True + showticklabels: True + tickcolor: "rgb(220, 220, 220)" + zeroline: False + range: [0, 50] + autosize: False + margin: + t: 50 + b: 0 + l: 80 + r: 20 + showlegend: True + legend: + orientation: "h" + font: + size: 10 width: 700 height: 900 paper_bgcolor: "#fff" @@ -53,6 +88,61 @@ plot-throughput: hoverlabel: namelength: -1 +plot-hdrh-latency: + # title: + # text: "Latency by Percentile Distribution" + # xanchor: "center" + # x: 0.5 + # font: + # size: 10 + showlegend: True + legend: + traceorder: "normal" + orientation: "h" + # font: + # size: 16 + xanchor: "left" + yanchor: "top" + x: 0 + y: -0.25 + bgcolor: "rgba(255, 255, 255, 0)" + bordercolor: "rgba(255, 255, 255, 0)" + xaxis: + type: "log" + title: "Percentile [%]" + # titlefont: + # size: 14 + autorange: False + fixedrange: True + gridcolor: "rgb(230, 230, 230)" + linecolor: "rgb(220, 220, 220)" + linewidth: 1 + showgrid: True + showline: True + showticklabels: True + tickcolor: "rgb(220, 220, 220)" + tickvals: [1, 2, 1e1, 20, 1e2, 1e3, 1e4, 1e5, 1e6] + ticktext: [0, 50, 90, 95, 99, 99.9, 99.99, 99.999, 99.9999] + # tickfont: + # size: 14 + yaxis: + title: "One-Way Latency per Direction [us]" + # titlefont: + # size: 14 + gridcolor: "rgb(230, 230, 230)" + linecolor: "rgb(220, 220, 220)" + linewidth: 1 + showgrid: True + showline: True + showticklabels: True + tickcolor: "rgb(220, 220, 220)" + # tickfont: + # size: 14 + autosize: True + #height: 400 + paper_bgcolor: "white" + plot_bgcolor: "white" + plot-throughput-speedup-analysis: titlefont: size: 16 |