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:
6 # http://www.apache.org/licenses/LICENSE-2.0
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.
14 """The coverage data tables.
21 import dash_bootstrap_components as dbc
23 from dash import dash_table
24 from dash.dash_table.Format import Format, Scheme
26 from ..utils.constants import Constants as C
29 def select_coverage_data(
33 show_latency: bool=True
35 """Select coverage data for the tables and generate tables as pandas data
38 :param data: Coverage data.
39 :param selected: Dictionary with user selection.
40 :param csv: If True, pandas data frame with selected coverage data is
41 returned for "Download Data" feature.
42 :param show_latency: If True, latency is displayed in the tables.
43 :type data: pandas.DataFrame
46 :type show_latency: bool
47 :returns: List of tuples with suite name (str) and data (pandas dataframe)
48 or pandas dataframe if csv is True.
49 :rtype: list[tuple[str, pandas.DataFrame], ] or pandas.DataFrame
54 # Filter data selected by the user.
55 phy = selected["phy"].split("-")
57 topo, arch, nic, drv = phy
58 drv_str = "" if drv == "dpdk" else drv.replace("_", "-")
62 df = pd.DataFrame(data.loc[(
63 (data["passed"] == True) &
64 (data["dut_type"] == selected["dut"]) &
65 (data["dut_version"] == selected["dutver"]) &
66 (data["release"] == selected["rls"])
69 (df.job.str.endswith(f"{topo}-{arch}")) &
70 (df.test_id.str.contains(
71 f"^.*\.{selected['area']}\..*{nic}.*{drv_str}.*$",
76 for driver in C.DRIVERS:
78 df[df.test_id.str.contains(f"-{driver}-")].index,
82 ttype = df["test_type"].to_list()[0]
86 # Prepare the coverage data
87 def _latency(hdrh_string: str, percentile: float) -> int:
88 """Get latency from HDRH string for given percentile.
90 :param hdrh_string: Encoded HDRH string.
91 :param percentile: Given percentile.
92 :type hdrh_string: str
93 :type percentile: float
94 :returns: The latency value for the given percentile from the encoded
99 hdr_lat = hdrh.histogram.HdrHistogram.decode(hdrh_string)
100 return hdr_lat.get_value_at_percentile(percentile)
101 except (hdrh.codec.HdrLengthException, TypeError):
104 def _get_suite(test_id: str) -> str:
105 """Get the suite name from the test ID.
107 return test_id.split(".")[-2].replace("2n1l-", "").\
108 replace("1n1l-", "").replace("2n-", "").replace("-ndrpdr", "")
110 def _get_test(test_id: str) -> str:
111 """Get the test name from the test ID.
113 return test_id.split(".")[-1].replace("-ndrpdr", "")
116 cov["Suite"] = df.apply(lambda row: _get_suite(row["test_id"]), axis=1)
117 cov["Test Name"] = df.apply(lambda row: _get_test(row["test_id"]), axis=1)
119 if ttype == "device":
120 cov = cov.assign(Result="PASS")
122 cov["Throughput_Unit"] = df["result_receive_rate_rate_unit"]
123 cov["Throughput_AVG"] = df.apply(
124 lambda row: row["result_receive_rate_rate_avg"] / 1e9, axis=1
126 cov["Throughput_STDEV"] = df.apply(
127 lambda row: row["result_receive_rate_rate_stdev"] / 1e9, axis=1
130 cov["Throughput_Unit"] = df["result_pdr_lower_rate_unit"]
131 cov["Throughput_NDR"] = df.apply(
132 lambda row: row["result_ndr_lower_rate_value"] / 1e6, axis=1
134 cov["Throughput_NDR_Gbps"] = df.apply(
135 lambda row: row["result_ndr_lower_bandwidth_value"] / 1e9, axis=1
137 cov["Throughput_PDR"] = df.apply(
138 lambda row: row["result_pdr_lower_rate_value"] / 1e6, axis=1
140 cov["Throughput_PDR_Gbps"] = df.apply(
141 lambda row: row["result_pdr_lower_bandwidth_value"] / 1e9, axis=1
144 for way in ("Forward", "Reverse"):
145 for pdr in (10, 50, 90):
146 for perc in (50, 90, 99):
147 latency = f"result_latency_{way.lower()}_pdr_{pdr}_hdrh"
148 cov[f"Latency {way} [us]_{pdr}% PDR_P{perc}"] = \
150 lambda row: _latency(row[latency], perc),
157 # Split data into tables depending on the test suite.
158 for suite in cov["Suite"].unique().tolist():
159 df_suite = pd.DataFrame(cov.loc[(cov["Suite"] == suite)])
162 unit = df_suite["Throughput_Unit"].tolist()[0]
165 "Throughput_NDR": f"Throughput_NDR_M{unit}",
166 "Throughput_PDR": f"Throughput_PDR_M{unit}",
167 "Throughput_AVG": f"Throughput_G{unit}_AVG",
168 "Throughput_STDEV": f"Throughput_G{unit}_STDEV"
172 df_suite.drop(["Suite", "Throughput_Unit"], axis=1, inplace=True)
174 l_data.append((suite, df_suite, ))
182 show_latency: bool=True,
183 start_collapsed: bool=True
185 """Generate an accordion with coverage tables.
187 :param data: Coverage data.
188 :param selected: Dictionary with user selection.
189 :param show_latency: If True, latency is displayed in the tables.
190 :param start_collapsed: If True, the accordion with tables is collapsed when
192 :type data: pandas.DataFrame
194 :type show_latency: bool
195 :type start_collapsed: bool
196 :returns: Accordion with suite names (titles) and tables.
197 :rtype: dash_bootstrap_components.Accordion
200 accordion_items = list()
202 select_coverage_data(data, selected, show_latency=show_latency)
203 for suite, cov_data in sel_data:
204 if ttype == "device": # VPP Device
212 } for col in cov_data.columns
214 style_cell={"textAlign": "left"}
215 style_cell_conditional=[
217 "if": {"column_id": "Result"},
221 elif ttype == "mrr": # MRR
223 for idx, col in enumerate(cov_data.columns):
226 "name": ["", "", col],
234 "name": col.split("_"),
239 "format": Format(precision=2, scheme=Scheme.fixed)
241 style_cell={"textAlign": "right"}
242 style_cell_conditional=[
244 "if": {"column_id": "Test Name"},
248 else: # Performance NDRPDR
250 for idx, col in enumerate(cov_data.columns):
253 "name": ["", "", col],
261 "name": col.split("_"),
266 "format": Format(precision=2, scheme=Scheme.fixed)
270 "name": col.split("_"),
275 "format": Format(precision=0, scheme=Scheme.fixed)
277 style_cell={"textAlign": "right"}
278 style_cell_conditional=[
280 "if": {"column_id": "Test Name"},
285 accordion_items.append(
288 children=dash_table.DataTable(
290 data=cov_data.to_dict("records"),
291 merge_duplicate_headers=True,
293 filter_action="none",
294 sort_action="native",
299 style_cell=style_cell,
300 style_cell_conditional=style_cell_conditional
304 if not accordion_items:
305 accordion_items.append(dbc.AccordionItem(
309 start_collapsed = True
310 return dbc.Accordion(
311 children=accordion_items,
312 class_name="gy-1 p-0",
313 start_collapsed=start_collapsed,