Add 2048B file size cps rps tests in job specs for http-ldpreload-nginx-1_21_5.
[csit.git] / csit.infra.dash / app / cdash / report / graphs.py
1 # Copyright (c) 2024 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 from numpy import percentile
22
23 from ..utils.constants import Constants as C
24 from ..utils.utils import get_color, get_hdrh_latencies
25
26
27 def select_iterative_data(data: pd.DataFrame, itm:dict) -> pd.DataFrame:
28     """Select the data for graphs and tables from the provided data frame.
29
30     :param data: Data frame with data for graphs and tables.
31     :param itm: Item (in this case job name) which data will be selected from
32         the input data frame.
33     :type data: pandas.DataFrame
34     :type itm: str
35     :returns: A data frame with selected data.
36     :rtype: pandas.DataFrame
37     """
38
39     phy = itm["phy"].split("-")
40     if len(phy) == 4:
41         topo, arch, nic, drv = phy
42         if drv == "dpdk":
43             drv = ""
44         else:
45             drv += "-"
46             drv = drv.replace("_", "-")
47     else:
48         return None
49
50     if itm["testtype"] in ("ndr", "pdr"):
51         test_type = "ndrpdr"
52     elif itm["testtype"] == "mrr":
53         test_type = "mrr"
54     elif itm["testtype"] == "soak":
55         test_type = "soak"
56     elif itm["area"] == "hoststack":
57         test_type = "hoststack"
58     df = data.loc[(
59         (data["release"] == itm["rls"]) &
60         (data["test_type"] == test_type) &
61         (data["passed"] == True)
62     )]
63
64     core = str() if itm["dut"] == "trex" else f"{itm['core']}"
65     ttype = "ndrpdr" if itm["testtype"] in ("ndr", "pdr") else itm["testtype"]
66     regex_test = \
67         f"^.*[.|-]{nic}.*{itm['framesize']}-{core}-{drv}{itm['test']}-{ttype}$"
68     df = df[
69         (df.job.str.endswith(f"{topo}-{arch}")) &
70         (df.dut_version.str.contains(itm["dutver"].replace(".r", "-r").\
71             replace("rls", "release"))) &
72         (df.test_id.str.contains(regex_test, regex=True))
73     ]
74
75     return df
76
77
78 def graph_iterative(data: pd.DataFrame, sel: list, layout: dict,
79         normalize: bool=False, remove_outliers: bool=False) -> tuple:
80     """Generate the statistical box graph with iterative data (MRR, NDR and PDR,
81     for PDR also Latencies).
82
83     :param data: Data frame with iterative data.
84     :param sel: Selected tests.
85     :param layout: Layout of plot.ly graph.
86     :param normalize: If True, the data is normalized to CPU frequency
87         Constants.NORM_FREQUENCY.
88     :param remove_outliers: If True the outliers are removed before
89         generating the table.
90     :type data: pandas.DataFrame
91     :type sel: list
92     :type layout: dict
93     :type normalize: bool
94     :type remove_outliers: bool
95     :returns: Tuple of graphs - throughput and latency.
96     :rtype: tuple(plotly.graph_objects.Figure, plotly.graph_objects.Figure)
97     """
98
99     def get_y_values(data, y_data_max, param, norm_factor, release=str(),
100                      remove_outliers=False):
101         if param == "result_receive_rate_rate_values":
102             if release == "rls2402":
103                 y_vals_raw = data["result_receive_rate_rate_avg"].to_list()
104             else:
105                 y_vals_raw = data[param].to_list()[0]
106         else:
107             y_vals_raw = data[param].to_list()
108         y_data = [(y * norm_factor) for y in y_vals_raw]
109
110         if remove_outliers:
111             try:
112                 q1 = percentile(y_data, 25, method=C.COMP_PERCENTILE_METHOD)
113                 q3 = percentile(y_data, 75, method=C.COMP_PERCENTILE_METHOD)
114                 irq = q3 - q1
115                 lif = q1 - C.COMP_OUTLIER_TYPE * irq
116                 uif = q3 + C.COMP_OUTLIER_TYPE * irq
117                 y_data = [i for i in y_data if i >= lif and i <= uif]
118             except TypeError:
119                 pass
120         try:
121             y_data_max = max(max(y_data), y_data_max)
122         except TypeError:
123             y_data_max = 0
124         return y_data, y_data_max
125
126     fig_tput = None
127     fig_band = None
128     fig_lat = None
129
130     tput_traces = list()
131     y_tput_max = 0
132     y_units = set()
133
134     lat_traces = list()
135     y_lat_max = 0
136     x_lat = list()
137
138     band_traces = list()
139     y_band_max = 0
140     y_band_units = set()
141     x_band = list()
142
143     for idx, itm in enumerate(sel):
144
145         itm_data = select_iterative_data(data, itm)
146         if itm_data.empty:
147             continue
148
149         phy = itm["phy"].split("-")
150         topo_arch = f"{phy[0]}-{phy[1]}" if len(phy) == 4 else str()
151         norm_factor = (C.NORM_FREQUENCY / C.FREQUENCY[topo_arch]) \
152             if normalize else 1.0
153
154         if itm["area"] == "hoststack":
155             ttype = f"hoststack-{itm['testtype']}"
156         else:
157             ttype = itm["testtype"]
158
159         y_units.update(itm_data[C.UNIT[ttype]].unique().tolist())
160
161         y_data, y_tput_max = get_y_values(
162             itm_data,
163             y_tput_max,
164             C.VALUE_ITER[ttype],
165             norm_factor,
166             itm["rls"],
167             remove_outliers
168         )
169
170         nr_of_samples = len(y_data)
171
172         customdata = list()
173         metadata = {
174             "csit release": itm["rls"],
175             "dut": itm["dut"],
176             "dut version": itm["dutver"],
177             "infra": itm["phy"],
178             "test": (
179                 f"{itm['area']}-{itm['framesize']}-{itm['core']}-"
180                 f"{itm['test']}-{itm['testtype']}"
181             )
182         }
183
184         if itm["testtype"] == "mrr" and itm["rls"] in ("rls2306", "rls2310"):
185             trial_run = "trial"
186             metadata["csit-ref"] = (
187                 f"{itm_data['job'].to_list()[0]}/",
188                 f"{itm_data['build'].to_list()[0]}"
189             )
190             customdata = [{"metadata": metadata}, ] * nr_of_samples
191         else:
192             trial_run = "run"
193             for _, row in itm_data.iterrows():
194                 metadata["csit-ref"] = f"{row['job']}/{row['build']}"
195                 try:
196                     metadata["hosts"] = ", ".join(row["hosts"])
197                 except (KeyError, TypeError):
198                     pass
199                 customdata.append({"metadata": deepcopy(metadata)})
200         tput_kwargs = dict(
201             y=y_data,
202             name=(
203                 f"{idx + 1}. "
204                 f"({nr_of_samples:02d} "
205                 f"{trial_run}{'s' if nr_of_samples > 1 else ''}) "
206                 f"{itm['id']}"
207             ),
208             hoverinfo=u"y+name",
209             boxpoints="all",
210             jitter=0.3,
211             marker=dict(color=get_color(idx)),
212             customdata=customdata
213         )
214         tput_traces.append(go.Box(**tput_kwargs))
215
216         if ttype in C.TESTS_WITH_BANDWIDTH:
217             y_band, y_band_max = get_y_values(
218                 itm_data,
219                 y_band_max,
220                 C.VALUE_ITER[f"{ttype}-bandwidth"],
221                 norm_factor,
222                 remove_outliers=remove_outliers
223             )
224             if not all(pd.isna(y_band)):
225                 y_band_units.update(
226                     itm_data[C.UNIT[f"{ttype}-bandwidth"]].unique().\
227                         dropna().tolist()
228                 )
229                 band_kwargs = dict(
230                     y=y_band,
231                     name=(
232                         f"{idx + 1}. "
233                         f"({nr_of_samples:02d} "
234                         f"run{'s' if nr_of_samples > 1 else ''}) "
235                         f"{itm['id']}"
236                     ),
237                     hoverinfo=u"y+name",
238                     boxpoints="all",
239                     jitter=0.3,
240                     marker=dict(color=get_color(idx)),
241                     customdata=customdata
242                 )
243                 x_band.append(idx + 1)
244                 band_traces.append(go.Box(**band_kwargs))
245
246         if ttype in C.TESTS_WITH_LATENCY:
247             y_lat, y_lat_max = get_y_values(
248                 itm_data,
249                 y_lat_max,
250                 C.VALUE_ITER["latency"],
251                 1 / norm_factor,
252                 remove_outliers=remove_outliers
253             )
254             if not all(pd.isna(y_lat)):
255                 customdata = list()
256                 for _, row in itm_data.iterrows():
257                     hdrh = get_hdrh_latencies(
258                         row,
259                         f"{metadata['infra']}-{metadata['test']}"
260                     )
261                     metadata["csit-ref"] = f"{row['job']}/{row['build']}"
262                     customdata.append({
263                         "metadata": deepcopy(metadata),
264                         "hdrh": hdrh
265                     })
266                 nr_of_samples = len(y_lat)
267                 lat_kwargs = dict(
268                     y=y_lat,
269                     name=(
270                         f"{idx + 1}. "
271                         f"({nr_of_samples:02d} "
272                         f"run{u's' if nr_of_samples > 1 else u''}) "
273                         f"{itm['id']}"
274                     ),
275                     hoverinfo="all",
276                     boxpoints="all",
277                     jitter=0.3,
278                     marker=dict(color=get_color(idx)),
279                     customdata=customdata
280                 )
281                 x_lat.append(idx + 1)
282                 lat_traces.append(go.Box(**lat_kwargs))
283
284     if tput_traces:
285         pl_tput = deepcopy(layout["plot-throughput"])
286         pl_tput["xaxis"]["tickvals"] = [i for i in range(len(sel))]
287         pl_tput["xaxis"]["ticktext"] = [str(i + 1) for i in range(len(sel))]
288         pl_tput["yaxis"]["title"] = f"Throughput [{'|'.join(sorted(y_units))}]"
289         if y_tput_max:
290             pl_tput["yaxis"]["range"] = [0, int(y_tput_max) * 1.1]
291         fig_tput = go.Figure(data=tput_traces, layout=pl_tput)
292
293     if band_traces:
294         pl_band = deepcopy(layout["plot-bandwidth"])
295         pl_band["xaxis"]["tickvals"] = [i for i in range(len(x_band))]
296         pl_band["xaxis"]["ticktext"] = x_band
297         pl_band["yaxis"]["title"] = \
298             f"Bandwidth [{'|'.join(sorted(y_band_units))}]"
299         if y_band_max:
300             pl_band["yaxis"]["range"] = [0, int(y_band_max) * 1.1]
301         fig_band = go.Figure(data=band_traces, layout=pl_band)
302
303     if lat_traces:
304         pl_lat = deepcopy(layout["plot-latency"])
305         pl_lat["xaxis"]["tickvals"] = [i for i in range(len(x_lat))]
306         pl_lat["xaxis"]["ticktext"] = x_lat
307         if y_lat_max:
308             pl_lat["yaxis"]["range"] = [0, int(y_lat_max) + 5]
309         fig_lat = go.Figure(data=lat_traces, layout=pl_lat)
310
311     return fig_tput, fig_band, fig_lat