C-Dash: Add hoststack
[csit.git] / csit.infra.dash / app / cdash / report / graphs.py
1 # Copyright (c) 2023 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13
14 """Implementation of graphs for iterative data.
15 """
16
17 import plotly.graph_objects as go
18 import pandas as pd
19
20 from copy import deepcopy
21
22 from ..utils.constants import Constants as C
23 from ..utils.utils import get_color
24
25
26 def select_iterative_data(data: pd.DataFrame, itm:dict) -> pd.DataFrame:
27     """Select the data for graphs and tables from the provided data frame.
28
29     :param data: Data frame with data for graphs and tables.
30     :param itm: Item (in this case job name) which data will be selected from
31         the input data frame.
32     :type data: pandas.DataFrame
33     :type itm: str
34     :returns: A data frame with selected data.
35     :rtype: pandas.DataFrame
36     """
37
38     phy = itm["phy"].split("-")
39     if len(phy) == 4:
40         topo, arch, nic, drv = phy
41         if drv == "dpdk":
42             drv = ""
43         else:
44             drv += "-"
45             drv = drv.replace("_", "-")
46     else:
47         return None
48
49     if itm["testtype"] in ("ndr", "pdr"):
50         test_type = "ndrpdr"
51     elif itm["testtype"] == "mrr":
52         test_type = "mrr"
53     elif itm["area"] == "hoststack":
54         test_type = "hoststack"
55     df = data.loc[(
56         (data["release"] == itm["rls"]) &
57         (data["test_type"] == test_type) &
58         (data["passed"] == True)
59     )]
60
61     core = str() if itm["dut"] == "trex" else f"{itm['core']}"
62     ttype = "ndrpdr" if itm["testtype"] in ("ndr", "pdr") else itm["testtype"]
63     regex_test = \
64         f"^.*[.|-]{nic}.*{itm['framesize']}-{core}-{drv}{itm['test']}-{ttype}$"
65     df = df[
66         (df.job.str.endswith(f"{topo}-{arch}")) &
67         (df.dut_version.str.contains(itm["dutver"].replace(".r", "-r").\
68             replace("rls", "release"))) &
69         (df.test_id.str.contains(regex_test, regex=True))
70     ]
71
72     return df
73
74
75 def graph_iterative(data: pd.DataFrame, sel:dict, layout: dict,
76         normalize: bool) -> tuple:
77     """Generate the statistical box graph with iterative data (MRR, NDR and PDR,
78     for PDR also Latencies).
79
80     :param data: Data frame with iterative data.
81     :param sel: Selected tests.
82     :param layout: Layout of plot.ly graph.
83     :param normalize: If True, the data is normalized to CPU frquency
84         Constants.NORM_FREQUENCY.
85     :param data: pandas.DataFrame
86     :param sel: dict
87     :param layout: dict
88     :param normalize: bool
89     :returns: Tuple of graphs - throughput and latency.
90     :rtype: tuple(plotly.graph_objects.Figure, plotly.graph_objects.Figure)
91     """
92
93     fig_tput = None
94     fig_lat = None
95
96     tput_traces = list()
97     y_tput_max = 0
98     lat_traces = list()
99     y_lat_max = 0
100     x_lat = list()
101     show_latency = False
102     show_tput = False
103     for idx, itm in enumerate(sel):
104         itm_data = select_iterative_data(data, itm)
105         if itm_data.empty:
106             continue
107         phy = itm["phy"].split("-")
108         topo_arch = f"{phy[0]}-{phy[1]}" if len(phy) == 4 else str()
109         norm_factor = (C.NORM_FREQUENCY / C.FREQUENCY[topo_arch]) \
110             if normalize else 1.0
111         if itm["testtype"] == "mrr":
112             y_data_raw = itm_data[C.VALUE_ITER[itm["testtype"]]].to_list()[0]
113             y_data = [(y * norm_factor) for y in y_data_raw]
114             if len(y_data) > 0:
115                 y_tput_max = \
116                     max(y_data) if max(y_data) > y_tput_max else y_tput_max
117         else:
118             y_data_raw = itm_data[C.VALUE_ITER[itm["testtype"]]].to_list()
119             y_data = [(y * norm_factor) for y in y_data_raw]
120             if y_data:
121                 y_tput_max = \
122                     max(y_data) if max(y_data) > y_tput_max else y_tput_max
123         nr_of_samples = len(y_data)
124         tput_kwargs = dict(
125             y=y_data,
126             name=(
127                 f"{idx + 1}. "
128                 f"({nr_of_samples:02d} "
129                 f"run{'s' if nr_of_samples > 1 else ''}) "
130                 f"{itm['id']}"
131             ),
132             hoverinfo=u"y+name",
133             boxpoints="all",
134             jitter=0.3,
135             marker=dict(color=get_color(idx))
136         )
137         tput_traces.append(go.Box(**tput_kwargs))
138         show_tput = True
139
140         if itm["testtype"] == "pdr":
141             y_lat_row = itm_data[C.VALUE_ITER["pdr-lat"]].to_list()
142             y_lat = [(y / norm_factor) for y in y_lat_row]
143             if y_lat:
144                 y_lat_max = max(y_lat) if max(y_lat) > y_lat_max else y_lat_max
145             nr_of_samples = len(y_lat)
146             lat_kwargs = dict(
147                 y=y_lat,
148                 name=(
149                     f"{idx + 1}. "
150                     f"({nr_of_samples:02d} "
151                     f"run{u's' if nr_of_samples > 1 else u''}) "
152                     f"{itm['id']}"
153                 ),
154                 hoverinfo="all",
155                 boxpoints="all",
156                 jitter=0.3,
157                 marker=dict(color=get_color(idx))
158             )
159             x_lat.append(idx + 1)
160             lat_traces.append(go.Box(**lat_kwargs))
161             show_latency = True
162         else:
163             lat_traces.append(go.Box())
164
165     if show_tput:
166         pl_tput = deepcopy(layout["plot-throughput"])
167         pl_tput["xaxis"]["tickvals"] = [i for i in range(len(sel))]
168         pl_tput["xaxis"]["ticktext"] = [str(i + 1) for i in range(len(sel))]
169         if y_tput_max:
170             pl_tput["yaxis"]["range"] = [0, (int(y_tput_max / 1e6) + 1) * 1e6]
171         fig_tput = go.Figure(data=tput_traces, layout=pl_tput)
172
173     if show_latency:
174         pl_lat = deepcopy(layout["plot-latency"])
175         pl_lat["xaxis"]["tickvals"] = [i for i in range(len(x_lat))]
176         pl_lat["xaxis"]["ticktext"] = x_lat
177         if y_lat_max:
178             pl_lat["yaxis"]["range"] = [0, (int(y_lat_max / 10) + 1) * 10]
179         fig_lat = go.Figure(data=lat_traces, layout=pl_lat)
180
181     return fig_tput, fig_lat