from ..utils.control_panel import ControlPanel
from ..utils.trigger import Trigger
from ..utils.utils import show_tooltip, label, sync_checklists, gen_new_url, \
- generate_options, get_list_group_items
+ generate_options, get_list_group_items, graph_hdrh_latency
from ..utils.url_processing import url_decode
-from ..data.data import Data
from .graphs import graph_iterative, select_iterative_data
"""The layout of the dash app and the callbacks.
"""
- def __init__(self, app: Flask, releases: list, html_layout_file: str,
- graph_layout_file: str, data_spec_file: str, tooltip_file: str) -> None:
+ def __init__(
+ self,
+ app: Flask,
+ data_iterative: pd.DataFrame,
+ html_layout_file: str,
+ graph_layout_file: str,
+ tooltip_file: str
+ ) -> None:
"""Initialization:
- save the input parameters,
- read and pre-process the data,
- read tooltips from the tooltip file.
:param app: Flask application running the dash application.
- :param releases: Lis of releases to be displayed.
:param html_layout_file: Path and name of the file specifying the HTML
layout of the dash application.
:param graph_layout_file: Path and name of the file with layout of
plot.ly graphs.
- :param data_spec_file: Path and name of the file specifying the data to
- be read from parquets for this application.
:param tooltip_file: Path and name of the yaml file specifying the
tooltips.
:type app: Flask
- :type releases: list
:type html_layout_file: str
:type graph_layout_file: str
- :type data_spec_file: str
:type tooltip_file: str
"""
# Inputs
self._app = app
- self.releases = releases
self._html_layout_file = html_layout_file
self._graph_layout_file = graph_layout_file
- self._data_spec_file = data_spec_file
self._tooltip_file = tooltip_file
-
- # Read the data:
- self._data = pd.DataFrame()
- for rls in releases:
- data_mrr = Data(self._data_spec_file, True).\
- read_iterative_mrr(release=rls)
- data_mrr["release"] = rls
- data_ndrpdr = Data(self._data_spec_file, True).\
- read_iterative_ndrpdr(release=rls)
- data_ndrpdr["release"] = rls
- self._data = pd.concat(
- [self._data, data_mrr, data_ndrpdr],
- ignore_index=True,
- copy=False
- )
+ self._data = data_iterative
# Get structure of tests:
tbs = dict()
- cols = ["job", "test_id", "test_type", "dut_version", "release"]
+ cols = [
+ "job", "test_id", "test_type", "dut_version", "tg_type", "release"
+ ]
for _, row in self._data[cols].drop_duplicates().iterrows():
rls = row["release"]
- ttype = row["test_type"]
lst_job = row["job"].split("-")
dut = lst_job[1]
d_ver = row["dut_version"]
if dut == "dpdk":
area = "dpdk"
else:
- area = "-".join(lst_test_id[3:-2])
+ area = ".".join(lst_test_id[3:-2])
suite = lst_test_id[-2].replace("2n1l-", "").replace("1n1l-", "").\
replace("2n-", "")
test = lst_test_id[-1]
tbs[rls][dut][d_ver][infra][area][test]["frame-size"].append(
framesize.upper()
)
- if ttype == "mrr":
+ if row["test_type"] == "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":
+ elif row["test_type"] == "ndrpdr":
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", )
)
+ elif row["test_type"] == "hoststack" and \
+ row["tg_type"] in ("iperf", "vpp"):
+ if "BPS" not in \
+ tbs[rls][dut][d_ver][infra][area][test]["test-type"]:
+ tbs[rls][dut][d_ver][infra][area][test]["test-type"].append(
+ "BPS"
+ )
+ elif row["test_type"] == "hoststack" and row["tg_type"] == "ab":
+ if "CPS" not in \
+ tbs[rls][dut][d_ver][infra][area][test]["test-type"]:
+ tbs[rls][dut][d_ver][infra][area][test]["test-type"].extend(
+ ("CPS", "RPS")
+ )
self._spec_tbs = tbs
# Read from files:
self._add_ctrl_col(),
self._add_plotting_col()
]
+ ),
+ dbc.Spinner(
+ dbc.Offcanvas(
+ class_name="w-50",
+ id="offcanvas-metadata",
+ title="Throughput And Latency",
+ placement="end",
+ is_open=False,
+ children=[
+ dbc.Row(id="metadata-tput-lat"),
+ dbc.Row(id="metadata-hdrh-graph")
+ ]
+ ),
+ delay_show=C.SPINNER_DELAY
+ ),
+ dbc.Offcanvas(
+ class_name="w-75",
+ id="offcanvas-documentation",
+ title="Documentation",
+ placement="end",
+ is_open=False,
+ children=html.Iframe(
+ src=C.URL_DOC_REL_NOTES,
+ width="100%",
+ height="100%"
+ )
)
]
)
return dbc.NavbarSimple(
id="navbarsimple-main",
children=[
- dbc.NavItem(
- dbc.NavLink(
- C.REPORT_TITLE,
- disabled=True,
- external_link=True,
- href="#"
- )
- )
+ dbc.NavItem(dbc.NavLink(
+ C.REPORT_TITLE,
+ active=True,
+ external_link=True,
+ href="/report"
+ )),
+ dbc.NavItem(dbc.NavLink(
+ "Comparisons",
+ external_link=True,
+ href="/comparisons"
+ )),
+ dbc.NavItem(dbc.NavLink(
+ "Coverage Data",
+ external_link=True,
+ href="/coverage"
+ )),
+ dbc.NavItem(dbc.NavLink(
+ "Documentation",
+ id="btn-documentation",
+ ))
],
brand=C.BRAND,
brand_href="/",
class_name="overflow-auto p-0",
id="lg-selected",
children=[],
- style={"max-height": "14em"},
+ style={"max-height": "20em"},
flush=True
)
]
try:
store_sel = literal_eval(url_params["store_sel"][0])
normalize = literal_eval(url_params["norm"][0])
- except (KeyError, IndexError):
+ except (KeyError, IndexError, AttributeError):
pass
if store_sel:
row_card_sel_tests = C.STYLE_ENABLED
if on_draw:
if store_sel:
- lg_selected = get_list_group_items(store_sel, "sel-cl")
+ lg_selected = get_list_group_items(
+ store_sel, "sel-cl", add_index=True
+ )
plotting_area = self._get_plotting_area(
store_sel,
bool(normalize),
Input("plot-btn-download", "n_clicks"),
prevent_initial_call=True
)
- def _download_trending_data(store_sel, _):
+ def _download_iterative_data(store_sel, _):
"""Download the data
:param store_sel: List of tests selected by user stored in the
df = pd.concat([df, sel_data], ignore_index=True)
return dcc.send_data_frame(df.to_csv, C.REPORT_DOWNLOAD_FILE_NAME)
+
+ @app.callback(
+ Output("metadata-tput-lat", "children"),
+ Output("metadata-hdrh-graph", "children"),
+ Output("offcanvas-metadata", "is_open"),
+ Input({"type": "graph", "index": ALL}, "clickData"),
+ prevent_initial_call=True
+ )
+ def _show_metadata_from_graphs(graph_data: dict) -> tuple:
+ """Generates the data for the offcanvas displayed when a particular
+ point in a graph is clicked on.
+
+ :param graph_data: The data from the clicked point in the graph.
+ :type graph_data: dict
+ :returns: The data to be displayed on the offcanvas and the
+ information to show the offcanvas.
+ :rtype: tuple(list, list, bool)
+ """
+
+ trigger = Trigger(callback_context.triggered)
+
+ try:
+ idx = 0 if trigger.idx == "tput" else 1
+ graph_data = graph_data[idx]["points"]
+ except (IndexError, KeyError, ValueError, TypeError):
+ raise PreventUpdate
+
+ def _process_stats(data: list, param: str) -> list:
+ """Process statistical data provided by plot.ly box graph.
+
+ :param data: Statistical data provided by plot.ly box graph.
+ :param param: Parameter saying if the data come from "tput" or
+ "lat" graph.
+ :type data: list
+ :type param: str
+ :returns: Listo of tuples where the first value is the
+ statistic's name and the secont one it's value.
+ :rtype: list
+ """
+ if len(data) == 7:
+ stats = ("max", "upper fence", "q3", "median", "q1",
+ "lower fence", "min")
+ elif len(data) == 9:
+ stats = ("outlier", "max", "upper fence", "q3", "median",
+ "q1", "lower fence", "min", "outlier")
+ elif len(data) == 1:
+ if param == "lat":
+ stats = ("Average Latency at 50% PDR", )
+ else:
+ stats = ("Throughput", )
+ else:
+ return list()
+ unit = " [us]" if param == "lat" else str()
+ return [(f"{stat}{unit}", f"{value['y']:,.0f}")
+ for stat, value in zip(stats, data)]
+
+ graph = list()
+ if trigger.idx == "tput":
+ title = "Throughput"
+ elif trigger.idx == "lat":
+ title = "Latency"
+ if len(graph_data) == 1:
+ hdrh_data = graph_data[0].get("customdata", None)
+ if hdrh_data:
+ graph = [dbc.Card(
+ class_name="gy-2 p-0",
+ children=[
+ dbc.CardHeader(hdrh_data.pop("name")),
+ dbc.CardBody(children=[
+ dcc.Graph(
+ id="hdrh-latency-graph",
+ figure=graph_hdrh_latency(
+ hdrh_data, self._graph_layout
+ )
+ )
+ ])
+ ])
+ ]
+ else:
+ raise PreventUpdate
+ metadata = [
+ dbc.Card(
+ class_name="gy-2 p-0",
+ children=[
+ dbc.CardHeader(children=[
+ dcc.Clipboard(
+ target_id="tput-lat-metadata",
+ title="Copy",
+ style={"display": "inline-block"}
+ ),
+ title
+ ]),
+ dbc.CardBody(
+ id="tput-lat-metadata",
+ class_name="p-0",
+ children=[dbc.ListGroup(
+ [
+ dbc.ListGroupItem([dbc.Badge(k), v])
+ for k, v in _process_stats(
+ graph_data, trigger.idx)
+ ],
+ flush=True)
+ ]
+ )
+ ]
+ )
+ ]
+
+ return metadata, graph, True
+
+ @app.callback(
+ Output("offcanvas-documentation", "is_open"),
+ Input("btn-documentation", "n_clicks"),
+ State("offcanvas-documentation", "is_open")
+ )
+ def toggle_offcanvas_documentation(n_clicks, is_open):
+ if n_clicks:
+ return not is_open
+ return is_open