UTI: Display Latency graph 57/35857/6
authorTibor Frank <tifrank@cisco.com>
Fri, 1 Apr 2022 06:19:59 +0000 (08:19 +0200)
committerTibor Frank <tifrank@cisco.com>
Mon, 4 Apr 2022 13:58:08 +0000 (13:58 +0000)
- Display Latency graph below the ndrpdr throughput graph for the same test set

Change-Id: I5c6475ccc1a849dbe299f78939b40ef6f6076634
Signed-off-by: Tibor Frank <tifrank@cisco.com>
resources/tools/dash/app/pal/data/data.yaml
resources/tools/dash/app/pal/trending/graphs.py
resources/tools/dash/app/pal/trending/layout.py
resources/tools/dash/app/pal/trending/layout.yaml

index 45e7f6b..f639873 100644 (file)
@@ -48,46 +48,46 @@ trending-ndrpdr:
     - result_ndr_lower_rate_value
     - result_ndr_lower_bandwidth_unit
     - result_ndr_lower_bandwidth_value
-    - result_latency_reverse_pdr_90_avg
+    - result_latency_reverse_pdr_90_avg
     - result_latency_reverse_pdr_90_hdrh
-    - result_latency_reverse_pdr_90_max
-    - result_latency_reverse_pdr_90_min
-    - result_latency_reverse_pdr_90_unit
-    - result_latency_reverse_pdr_50_avg
+    - result_latency_reverse_pdr_90_max
+    - result_latency_reverse_pdr_90_min
+    - result_latency_reverse_pdr_90_unit
+    - result_latency_reverse_pdr_50_avg
     - result_latency_reverse_pdr_50_hdrh
-    - result_latency_reverse_pdr_50_max
-    - result_latency_reverse_pdr_50_min
-    - result_latency_reverse_pdr_50_unit
-    - result_latency_reverse_pdr_10_avg
+    - result_latency_reverse_pdr_50_max
+    - result_latency_reverse_pdr_50_min
+    - result_latency_reverse_pdr_50_unit
+    - result_latency_reverse_pdr_10_avg
     - result_latency_reverse_pdr_10_hdrh
-    - result_latency_reverse_pdr_10_max
-    - result_latency_reverse_pdr_10_min
-    - result_latency_reverse_pdr_10_unit
-    - result_latency_reverse_pdr_0_avg
+    - result_latency_reverse_pdr_10_max
+    - result_latency_reverse_pdr_10_min
+    - result_latency_reverse_pdr_10_unit
+    - result_latency_reverse_pdr_0_avg
     - result_latency_reverse_pdr_0_hdrh
-    - result_latency_reverse_pdr_0_max
-    - result_latency_reverse_pdr_0_min
-    - result_latency_reverse_pdr_0_unit
-    - result_latency_forward_pdr_90_avg
+    - result_latency_reverse_pdr_0_max
+    - result_latency_reverse_pdr_0_min
+    - result_latency_reverse_pdr_0_unit
+    - result_latency_forward_pdr_90_avg
     - result_latency_forward_pdr_90_hdrh
-    - result_latency_forward_pdr_90_max
-    - result_latency_forward_pdr_90_min
-    - result_latency_forward_pdr_90_unit
+    - result_latency_forward_pdr_90_max
+    - result_latency_forward_pdr_90_min
+    - result_latency_forward_pdr_90_unit
     - result_latency_forward_pdr_50_avg
     - result_latency_forward_pdr_50_hdrh
-    - result_latency_forward_pdr_50_max
-    - result_latency_forward_pdr_50_min
+    - result_latency_forward_pdr_50_max
+    - result_latency_forward_pdr_50_min
     - result_latency_forward_pdr_50_unit
-    - result_latency_forward_pdr_10_avg
+    - result_latency_forward_pdr_10_avg
     - result_latency_forward_pdr_10_hdrh
-    - result_latency_forward_pdr_10_max
-    - result_latency_forward_pdr_10_min
-    - result_latency_forward_pdr_10_unit
-    - result_latency_forward_pdr_0_avg
+    - result_latency_forward_pdr_10_max
+    - result_latency_forward_pdr_10_min
+    - result_latency_forward_pdr_10_unit
+    - result_latency_forward_pdr_0_avg
     - result_latency_forward_pdr_0_hdrh
-    - result_latency_forward_pdr_0_max
-    - result_latency_forward_pdr_0_min
-    - result_latency_forward_pdr_0_unit
+    - result_latency_forward_pdr_0_max
+    - result_latency_forward_pdr_0_min
+    - result_latency_forward_pdr_0_unit
 iterative-mrr:
   path: s3://fdio-docs-s3-cloudfront-index/csit/parquet/iterative_rls2202
   columns:
index 8cb96ea..b71c327 100644 (file)
 """
 
 
-import logging
 import plotly.graph_objects as go
 import pandas as pd
 import re
 
 from datetime import datetime
 from numpy import isnan
-from dash import no_update
 
 from ..jumpavg import classify
 
@@ -57,7 +55,7 @@ _ANOMALY_COLOR = {
     u"normal": 0.5,
     u"progression": 1.0
 }
-_COLORSCALE = [
+_COLORSCALE_TPUT = [
     [0.00, u"red"],
     [0.33, u"red"],
     [0.33, u"white"],
@@ -65,15 +63,27 @@ _COLORSCALE = [
     [0.66, u"green"],
     [1.00, u"green"]
 ]
+_TICK_TEXT_TPUT = [u"Regression", u"Normal", u"Progression"]
+_COLORSCALE_LAT = [
+    [0.00, u"green"],
+    [0.33, u"green"],
+    [0.33, u"white"],
+    [0.66, u"white"],
+    [0.66, u"red"],
+    [1.00, u"red"]
+]
+_TICK_TEXT_LAT = [u"Progression", u"Normal", u"Regression"]
 _VALUE = {
     "mrr": "result_receive_rate_rate_avg",
     "ndr": "result_ndr_lower_rate_value",
-    "pdr": "result_pdr_lower_rate_value"
+    "pdr": "result_pdr_lower_rate_value",
+    "pdr-lat": "result_latency_forward_pdr_50_avg"
 }
 _UNIT = {
     "mrr": "result_receive_rate_rate_unit",
     "ndr": "result_ndr_lower_rate_unit",
-    "pdr": "result_pdr_lower_rate_unit"
+    "pdr": "result_pdr_lower_rate_unit",
+    "pdr-lat": "result_latency_forward_pdr_50_unit"
 }
 
 
@@ -133,7 +143,7 @@ def trending_tput(data: pd.DataFrame, sel:dict, layout: dict, start: datetime,
     """
 
     if not sel:
-        return no_update, no_update
+        return None, None
 
     def _generate_traces(ttype: str, name: str, df: pd.DataFrame,
         start: datetime, end: datetime, color: str):
@@ -151,10 +161,9 @@ def trending_tput(data: pd.DataFrame, sel:dict, layout: dict, start: datetime,
         hover = list()
         for _, row in df.iterrows():
             hover_itm = (
-                f"date: "
-                f"{row['start_time'].strftime('%d-%m-%Y %H:%M:%S')}<br>"
-                f"average [{row[_UNIT[ttype]]}]: "
-                f"{row[_VALUE[ttype]]}<br>"
+                f"date: {row['start_time'].strftime('%d-%m-%Y %H:%M:%S')}<br>"
+                f"<prop> [{row[_UNIT[ttype]]}]: {row[_VALUE[ttype]]}<br>"
+                f"<stdev>"
                 f"{row['dut_type']}-ref: {row['dut_version']}<br>"
                 f"csit-ref: {row['job']}/{row['build']}"
             )
@@ -165,15 +174,23 @@ def trending_tput(data: pd.DataFrame, sel:dict, layout: dict, start: datetime,
                 )
             else:
                 stdev = ""
-            hover_itm = hover_itm.replace("<stdev>", stdev)
+            hover_itm = hover_itm.replace(
+                "<prop>", "latency" if ttype == "pdr-lat" else "average"
+            ).replace("<stdev>", stdev)
             hover.append(hover_itm)
 
         hover_trend = list()
         for avg, stdev in zip(trend_avg, trend_stdev):
-            hover_trend.append(
-                f"trend [pps]: {avg}<br>"
-                f"stdev [pps]: {stdev}"
-            )
+            if ttype == "pdr-lat":
+                hover_trend.append(
+                    f"trend [us]: {avg}<br>"
+                    f"stdev [us]: {stdev}"
+                )
+            else:
+                hover_trend.append(
+                    f"trend [pps]: {avg}<br>"
+                    f"stdev [pps]: {stdev}"
+                )
 
         traces = [
             go.Scatter(  # Samples
@@ -212,13 +229,12 @@ def trending_tput(data: pd.DataFrame, sel:dict, layout: dict, start: datetime,
             anomaly_x = list()
             anomaly_y = list()
             anomaly_color = list()
-            ticktext = [u"Regression", u"Normal", u"Progression"]
             for idx, anomaly in enumerate(anomalies):
                 if anomaly in (u"regression", u"progression"):
                     anomaly_x.append(x_axis[idx])
                     anomaly_y.append(trend_avg[idx])
                     anomaly_color.append(_ANOMALY_COLOR[anomaly])
-            anomaly_color.append([0.0, 0.5, 1.0])
+            anomaly_color.extend([0.0, 0.5, 1.0])
             traces.append(
                 go.Scatter(
                     x=anomaly_x,
@@ -232,7 +248,8 @@ def trending_tput(data: pd.DataFrame, sel:dict, layout: dict, start: datetime,
                         u"size": 15,
                         u"symbol": u"circle-open",
                         u"color": anomaly_color,
-                        u"colorscale": _COLORSCALE,
+                        u"colorscale": _COLORSCALE_LAT \
+                            if ttype == "pdr-lat" else _COLORSCALE_TPUT,
                         u"showscale": True,
                         u"line": {
                             u"width": 2
@@ -247,7 +264,8 @@ def trending_tput(data: pd.DataFrame, sel:dict, layout: dict, start: datetime,
                             },
                             u"tickmode": u"array",
                             u"tickvals": [0.167, 0.500, 0.833],
-                            u"ticktext": ticktext,
+                            u"ticktext": _TICK_TEXT_LAT \
+                                if ttype == "pdr-lat" else _TICK_TEXT_TPUT,
                             u"ticks": u"",
                             u"ticklen": 0,
                             u"tickangle": -90,
@@ -260,7 +278,8 @@ def trending_tput(data: pd.DataFrame, sel:dict, layout: dict, start: datetime,
         return traces
 
     # Generate graph:
-    fig = go.Figure()
+    fig_tput = None
+    fig_lat = None
     for idx, itm in enumerate(sel):
         phy = itm["phy"].split("-")
         if len(phy) == 4:
@@ -293,18 +312,29 @@ def trending_tput(data: pd.DataFrame, sel:dict, layout: dict, start: datetime,
             f"{itm['phy']}-{itm['framesize']}-{itm['core']}-"
             f"{itm['test']}-{itm['testtype']}"
         )
-        for trace in _generate_traces(itm['testtype'], name, df, start, end,
-                _COLORS[idx % len(_COLORS)]):
-            fig.add_trace(trace)
 
-    style={
-        "vertical-align": "top",
-        "display": "inline-block",
-        "width": "80%",
-        "padding": "5px"
-    }
+        traces = _generate_traces(
+            itm["testtype"], name, df, start, end, _COLORS[idx % len(_COLORS)]
+        )
+        if traces:
+            if not fig_tput:
+                fig_tput = go.Figure()
+            for trace in traces:
+                fig_tput.add_trace(trace)
+
+        if itm["testtype"] == "pdr":
+            traces = _generate_traces(
+                "pdr-lat", name, df, start, end, _COLORS[idx % len(_COLORS)]
+            )
+            if traces:
+                if not fig_lat:
+                    fig_lat = go.Figure()
+                for trace in traces:
+                    fig_lat.add_trace(trace)
 
-    layout = layout.get("plot-trending", dict())
-    fig.update_layout(layout)
+    if fig_tput:
+        fig_tput.update_layout(layout.get("plot-trending-tput", dict()))
+    if fig_lat:
+        fig_lat.update_layout(layout.get("plot-trending-lat", dict()))
 
-    return fig, style
+    return fig_tput, fig_lat
index 6be71ac..3776214 100644 (file)
@@ -34,6 +34,11 @@ class Layout:
     """
     """
 
+    STYLE_HIDEN = {"display": "none"}
+    STYLE_BLOCK = {"display": "block"}
+    STYLE_INLINE ={"display": "inline-block", "width": "50%"}
+    NO_GRAPH = {"data": [], "layout": {}, "frames": []}
+
     def __init__(self, app, html_layout_file, spec_file, graph_layout_file,
         data_spec_file):
         """
@@ -170,27 +175,52 @@ class Layout:
                     id="loading-graph",
                     children=[
                         dcc.Graph(
-                            id="graph"
+                            id="graph-tput",
+                            style=self.STYLE_HIDEN
+                        ),
+                        dcc.Graph(
+                            id="graph-latency",
+                            style=self.STYLE_HIDEN
                         )
                     ],
                     type="circle"
                 ),
                 html.Div(
                     children=[
-                        dcc.Markdown("""
-                        **Metadata**
-
-                        Click on data points in the graph.
-                        """),
-                        html.Pre(
-                            id="hover-metadata"
+                        html.Div(
+                            id="div-tput-metadata",
+                            children=[
+                                dcc.Markdown("""
+                                **Metadata**
+
+                                Click on data points in the graph.
+                                """),
+                                html.Pre(
+                                    id="tput-metadata"
+                                )
+                            ],
+                            style=self.STYLE_HIDEN
+                        ),
+                        html.Div(
+                            id="div-latency-metadata",
+                            children=[
+                                dcc.Markdown("""
+                                **Metadata**
+
+                                Click on data points in the graph.
+                                """),
+                                html.Pre(
+                                    id="latency-metadata"
+                                )
+                            ],
+                            style=self.STYLE_HIDEN
                         )
                     ]
                 )
             ],
             style={
                 "vertical-align": "top",
-                "display": "none",
+                "display": "inline-block",
                 "width": "80%",
                 "padding": "5px"
             }
@@ -471,13 +501,17 @@ class Layout:
             return _sync_checklists(opt, sel, all, "cl-ctrl-testtype")
 
         @app.callback(
-            Output("graph", "figure"),
+            Output("graph-tput", "figure"),
+            Output("graph-tput", "style"),
+            Output("div-tput-metadata", "style"),
+            Output("graph-latency", "figure"),
+            Output("graph-latency", "style"),
+            Output("div-latency-metadata", "style"),
             Output("selected-tests", "data"),  # Store
             Output("cl-selected", "options"),  # User selection
             Output("dd-ctrl-phy", "value"),
             Output("dd-ctrl-area", "value"),
             Output("dd-ctrl-test", "value"),
-            Output("div-plotting-area", "style"),
             State("selected-tests", "data"),  # Store
             State("cl-selected", "value"),
             State("dd-ctrl-phy", "value"),
@@ -511,24 +545,46 @@ class Layout:
                 else:
                     return list()
 
+            class RetunValue:
+                def __init__(self) -> None:
+                    self._output = {
+                        "graph-tput-figure": no_update,
+                        "graph-tput-style": no_update,
+                        "div-tput-metadata-style": no_update,
+                        "graph-lat-figure": no_update,
+                        "graph-lat-style": no_update,
+                        "div-lat-metadata-style": no_update,
+                        "selected-tests-data": no_update,
+                        "cl-selected-options": no_update,
+                        "dd-ctrl-phy-value": no_update,
+                        "dd-ctrl-area-value": no_update,
+                        "dd-ctrl-test-value": no_update,
+                    }
+
+                def value(self):
+                    return tuple(self._output.values())
+
+                def set_values(self, kwargs: dict) -> None:
+                    for key, val in kwargs.items():
+                        if key in self._output:
+                            self._output[key] = val
+                        else:
+                            raise KeyError(f"The key {key} is not defined.")
+
+
             trigger_id = callback_context.triggered[0]["prop_id"].split(".")[0]
 
-            d_start = datetime(
-                 int(d_start[0:4]), int(d_start[5:7]), int(d_start[8:10])
-            )
-            d_end = datetime(
-                 int(d_end[0:4]), int(d_end[5:7]), int(d_end[8:10])
-            )
+            d_start = datetime(int(d_start[0:4]), int(d_start[5:7]),
+                int(d_start[8:10]))
+            d_end = datetime(int(d_end[0:4]), int(d_end[5:7]), int(d_end[8:10]))
+
+            output = RetunValue()
 
             if trigger_id == "btn-ctrl-add":
                 # Add selected test to the list of tests in store:
                 if phy and area and test and cores and framesizes and testtypes:
-
-                    # TODO: Add validation
-
                     if store_sel is None:
                         store_sel = list()
-
                     for core in cores:
                         for framesize in framesizes:
                             for ttype in testtypes:
@@ -550,15 +606,32 @@ class Layout:
                                         "core": core.lower(),
                                         "testtype": ttype.lower()
                                     })
-                return (no_update, store_sel, _list_tests(), None,
-                    None, None, no_update)
+                output.set_values({
+                    "selected-tests-data": store_sel,
+                    "cl-selected-options": _list_tests(),
+                    "dd-ctrl-phy-value": None,
+                    "dd-ctrl-area-value": None,
+                    "dd-ctrl-test-value": None,
+                })
 
             elif trigger_id in ("btn-sel-display", "dpr-period"):
-                fig, style = trending_tput(
+                fig_tput, fig_lat = trending_tput(
                     self.data, store_sel, self.layout, d_start, d_end
                 )
-                return (fig, no_update, no_update,
-                    no_update, no_update, no_update, style)
+                output.set_values({
+                    "graph-tput-figure": \
+                        fig_tput if fig_tput else self.NO_GRAPH,
+                    "graph-tput-style": \
+                        self.STYLE_BLOCK if fig_tput else self.STYLE_HIDEN,
+                    "div-tput-metadata-style": \
+                        self.STYLE_INLINE if fig_tput else self.STYLE_HIDEN,
+                    "graph-lat-figure": \
+                        fig_lat if fig_lat else self.NO_GRAPH,
+                    "graph-lat-style": \
+                        self.STYLE_BLOCK if fig_lat else self.STYLE_HIDEN,
+                    "div-lat-metadata-style": \
+                        self.STYLE_INLINE if fig_lat else self.STYLE_HIDEN
+                })
 
             elif trigger_id == "btn-sel-remove":
                 if list_sel:
@@ -568,26 +641,53 @@ class Layout:
                             new_store_sel.append(item)
                     store_sel = new_store_sel
                 if store_sel:
-                    fig, style = trending_tput(
+                    fig_tput, fig_lat = trending_tput(
                         self.data, store_sel, self.layout, d_start, d_end
                     )
-                    return (fig, store_sel, _list_tests(),
-                    no_update, no_update, no_update, style)
+                    output.set_values({
+                        "graph-tput-figure": \
+                            fig_tput if fig_tput else self.NO_GRAPH,
+                        "graph-tput-style": \
+                            self.STYLE_BLOCK if fig_tput else self.STYLE_HIDEN,
+                        "div-tput-metadata-style": \
+                            self.STYLE_INLINE if fig_tput else self.STYLE_HIDEN,
+                        "graph-lat-figure": \
+                            fig_lat if fig_lat else self.NO_GRAPH,
+                        "graph-lat-style": \
+                            self.STYLE_BLOCK if fig_lat else self.STYLE_HIDEN,
+                        "div-lat-metadata-style": \
+                            self.STYLE_INLINE if fig_lat else self.STYLE_HIDEN,
+                        "selected-tests-data": store_sel,
+                        "cl-selected-options": _list_tests()
+                    })
                 else:
-                    style={
-                        "vertical-align": "top",
-                        "display": "none",
-                        "width": "80%",
-                        "padding": "5px"
-                    }
-                    return (no_update, store_sel, _list_tests(),
-                        no_update, no_update, no_update, style)
+                    output.set_values({
+                        "graph-tput-figure": self.NO_GRAPH,
+                        "graph-tput-style": self.STYLE_HIDEN,
+                        "div-tput-metadata-style": self.STYLE_HIDEN,
+                        "graph-lat-figure": self.NO_GRAPH,
+                        "graph-lat-style": self.STYLE_HIDEN,
+                        "div-lat-metadata-style": self.STYLE_HIDEN,
+                        "selected-tests-data": store_sel,
+                        "cl-selected-options": _list_tests()
+                    })
+
+            return output.value()
+
+        @app.callback(
+            Output("tput-metadata", "children"),
+            Input("graph-tput", "clickData")
+        )
+        def _show_tput_metadata(hover_data):
+            if not hover_data:
+                raise PreventUpdate
+            return json.dumps(hover_data, indent=2)
 
         @app.callback(
-            Output("hover-metadata", "children"),
-            Input("graph", "clickData")
+            Output("latency-metadata", "children"),
+            Input("graph-latency", "clickData")
         )
-        def _show_metadata(hover_data):
+        def _show_latency_metadata(hover_data):
             if not hover_data:
                 raise PreventUpdate
             return json.dumps(hover_data, indent=2)
index 143ade1..86a9f19 100644 (file)
@@ -1,4 +1,4 @@
-plot-trending:
+plot-trending-tput:
   title: ""
   titlefont:
     size: 16
@@ -75,3 +75,81 @@ plot-trending:
   plot_bgcolor: "#fff"
   hoverlabel:
     namelength: -1
+
+plot-trending-lat:
+  title: ""
+  titlefont:
+    size: 16
+  autosize: True
+  showlegend: True
+  # width: 1100
+  height: 600
+  yaxis:
+    showticklabels: True
+    tickformat: ".3s"
+    title: "Latency [us]"
+    hoverformat: ".5s"
+    gridcolor: "rgb(238, 238, 238)"
+    linecolor: "rgb(238, 238, 238)"
+    showline: True
+    zeroline: False
+    tickcolor: "rgb(238, 238, 238)"
+    linewidth: 1
+    showgrid: True
+  xaxis:
+    title: 'Date [MMDD]'
+    type: "date"
+    autorange: True
+    fixedrange: False
+    showgrid: True
+    gridcolor: "rgb(238, 238, 238)"
+    showline: True
+    linecolor: "rgb(238, 238, 238)"
+    zeroline: False
+    linewidth: 1
+    showticklabels: True
+    tickcolor: "rgb(238, 238, 238)"
+    tickmode: "auto"
+    tickformat: "%m%d"
+    rangeselector:
+      buttons:
+      - count: 14
+        label: "2w"
+        step: "day"
+        stepmode: "backward"
+      - count: 1
+        label: "1m"
+        step: "month"
+        stepmode: "backward"
+      - count: 2
+        label: "2m"
+        step: "month"
+        stepmode: "backward"
+      - count: 3
+        label: "3m"
+        step: "month"
+        stepmode: "backward"
+      - count: 4
+        label: "4m"
+        step: "month"
+        stepmode: "backward"
+      - count: 5
+        label: "5m"
+        step: "month"
+        stepmode: "backward"
+      - step: "all"
+  margin:
+    r: 20
+    b: 0
+    t: 5
+    l: 70
+  legend:
+    orientation: "h"
+    y: -0.18
+    xanchor: "auto"
+    traceorder: "normal"
+    bordercolor: "rgb(238, 238, 238)"
+  paper_bgcolor: "#fff"
+  plot_bgcolor: "#fff"
+  hoverlabel:
+    namelength: -1