Skip to content

Commit 5fbf221

Browse files
JibinBaomssonicbld
authored andcommitted
[Mellanox] Update QoS test cases for SN5600 (sonic-net#9583)
For Nvidia SN5600 the formula to calculate the shared buffer size for pg and queue differs from other Spectrum. So, update the corresponding code for it.
1 parent 1525536 commit 5fbf221

File tree

3 files changed

+169
-12
lines changed

3 files changed

+169
-12
lines changed

tests/qos/files/mellanox/qos_param_generator.py

Lines changed: 64 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
import math
2+
import yaml
3+
import os
4+
5+
MELLANOX_QOS_CONFIG_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "special_qos_config.yml")
26

37

48
class QosParamMellanox(object):
@@ -65,6 +69,7 @@ def run(self):
6569
"""
6670
self.collect_qos_configurations()
6771
self.calculate_parameters()
72+
self.update_special_qos_config()
6873
return self.qos_params_mlnx
6974

7075
def collect_qos_configurations(self):
@@ -81,6 +86,10 @@ def collect_qos_configurations(self):
8186
headroom = xon + xoff
8287
ingress_lossless_size = int(
8388
math.ceil(float(self.ingressLosslessProfile['static_th']) / self.cell_size)) - xon
89+
if self.asic_type == "spc4":
90+
pg_q_alpha = self.ingressLosslessProfile['pg_q_alpha']
91+
port_alpha = self.ingressLosslessProfile['port_alpha']
92+
pool_size = int(math.ceil(float(self.ingressLosslessProfile['pool_size']) / self.cell_size))
8493
else:
8594
headroom = size
8695
ingress_lossless_size = int(
@@ -89,6 +98,8 @@ def collect_qos_configurations(self):
8998

9099
egress_lossy_size = int(math.ceil(float(self.egressLossyProfile['static_th']) / self.cell_size))
91100

101+
ingess_lossy_size = int(math.ceil(float(self.ingressLossyProfile['static_th']) / self.cell_size))
102+
92103
pkts_num_trig_pfc = ingress_lossless_size + xon + hysteresis
93104
pkts_num_trig_ingr_drp = ingress_lossless_size + headroom
94105
if self.sharedHeadroomPoolSize:
@@ -98,7 +109,8 @@ def collect_qos_configurations(self):
98109
else:
99110
pkts_num_trig_ingr_drp -= self.headroom_overhead
100111
pkts_num_dismiss_pfc = ingress_lossless_size + 1
101-
pkts_num_trig_egr_drp = egress_lossy_size + 1
112+
pkts_num_trig_egr_drp = egress_lossy_size + 1 if egress_lossy_size <= ingess_lossy_size \
113+
else ingess_lossy_size + 1
102114

103115
if self.sharedHeadroomPoolSize:
104116
src_testPortIds = self.dutConfig['testPortIds'][self.src_dut_index][self.src_asic_index]
@@ -109,11 +121,25 @@ def collect_qos_configurations(self):
109121
occupancy_per_port = ingress_lossless_size
110122
self.qos_parameters['dst_port_id'] = dst_testPortIds[0]
111123
pgs_per_port = 2 if not self.dualTor else 4
112-
for i in range(1, ingress_ports_num_shp):
113-
for j in range(pgs_per_port):
114-
pkts_num_trig_pfc_shp.append(occupancy_per_port + xon + hysteresis)
115-
occupancy_per_port /= 2
116-
ingress_ports_list_shp.append(src_testPortIds[i])
124+
occupied_buffer = 0
125+
if self.asic_type == "spc4":
126+
for i in range(1, ingress_ports_num_shp):
127+
for j in range(pgs_per_port):
128+
pg_occupancy = int(math.ceil(
129+
(pg_q_alpha*port_alpha*(pool_size - occupied_buffer) - pg_q_alpha*occupied_buffer)/(
130+
1 + pg_q_alpha*port_alpha + pg_q_alpha)))
131+
pkts_num_trig_pfc_shp.append(pg_occupancy + xon + hysteresis)
132+
occupied_buffer += pg_occupancy
133+
# For a new port it should be treated as a smaller pool with the occupancy being 0
134+
pool_size -= occupied_buffer
135+
occupied_buffer = 0
136+
ingress_ports_list_shp.append(src_testPortIds[i])
137+
else:
138+
for i in range(1, ingress_ports_num_shp):
139+
for j in range(pgs_per_port):
140+
pkts_num_trig_pfc_shp.append(occupancy_per_port + xon + hysteresis)
141+
occupancy_per_port //= 2
142+
ingress_ports_list_shp.append(src_testPortIds[i])
117143
self.qos_parameters['pkts_num_trig_pfc_shp'] = pkts_num_trig_pfc_shp
118144
self.qos_parameters['src_port_ids'] = ingress_ports_list_shp
119145
self.qos_parameters['pkts_num_hdrm_full'] = xoff - 2
@@ -176,6 +202,7 @@ def calculate_parameters(self):
176202
xon['pkts_num_hysteresis'] = pkts_num_hysteresis + 16
177203
xon['pkts_num_margin'] = 3
178204
xon['cell_size'] = self.cell_size
205+
179206
self.qos_params_mlnx['xon_1'].update(xon)
180207
self.qos_params_mlnx['xon_2'].update(xon)
181208
self.qos_params_mlnx['xon_3'].update(xon)
@@ -201,15 +228,11 @@ def calculate_parameters(self):
201228
lossy_queue = self.qos_params_mlnx['lossy_queue_1']
202229
lossy_queue['pkts_num_trig_egr_drp'] = pkts_num_trig_egr_drp - 1
203230
lossy_queue['cell_size'] = self.cell_size
204-
if self.asic_type == "spc4":
205-
lossy_queue['packet_size'] = 600
206231

207232
wm_shared_lossy = {}
208233
wm_shared_lossy['pkts_num_trig_egr_drp'] = pkts_num_trig_egr_drp
209234
wm_shared_lossy['cell_size'] = self.cell_size
210-
wm_shared_lossy["pkts_num_margin"] = 3
211-
if self.asic_type == "spc4":
212-
wm_shared_lossy["packet_size"] = 600
235+
wm_shared_lossy["pkts_num_margin"] = 4
213236
self.qos_params_mlnx['wm_pg_shared_lossy'].update(wm_shared_lossy)
214237
wm_shared_lossy["pkts_num_margin"] = 8
215238
self.qos_params_mlnx['wm_q_shared_lossy'].update(wm_shared_lossy)
@@ -228,3 +251,33 @@ def calculate_parameters(self):
228251

229252
self.qos_params_mlnx['shared-headroom-pool'] = self.sharedHeadroomPoolSize
230253
self.qos_params_mlnx['pkts_num_private_headrooom'] = self.asic_param_dic[self.asic_type]['private_headroom']
254+
255+
def update_special_qos_config(self):
256+
"""
257+
Update qos parameters based on the file of special_qos_config.yml
258+
The format of qos_special_config.yml is same to qos.yml,
259+
and it just list the parameter with different value for the specified asic_type
260+
"""
261+
with open(MELLANOX_QOS_CONFIG_FILE) as file:
262+
special_qos_config_data = yaml.load(file, Loader=yaml.FullLoader)
263+
264+
def update_dict_value(speical_qos_config_dict, qos_params_dict):
265+
if speical_qos_config_dict:
266+
for key, value in speical_qos_config_dict.items():
267+
if isinstance(value, dict):
268+
update_dict_value(value, qos_params_dict[key])
269+
else:
270+
qos_params_dict[key] = value
271+
272+
special_qos_config = special_qos_config_data.get("qos_params").get(self.asic_type, {})
273+
if special_qos_config:
274+
for qos_config_key, qos_config_value in special_qos_config.items():
275+
qos_params_dict = self.qos_params_mlnx[self.speed_cable_len] if qos_config_key == 'profile' \
276+
else self.qos_params_mlnx[qos_config_key]
277+
278+
for sub_qos_config_key, sub_qos_config_value in qos_config_value.items():
279+
if isinstance(sub_qos_config_value, dict):
280+
if sub_qos_config_key in qos_params_dict:
281+
update_dict_value(sub_qos_config_value, qos_params_dict[sub_qos_config_key])
282+
else:
283+
qos_params_dict[sub_qos_config_key] = sub_qos_config_value
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Special qos config
2+
#
3+
qos_params:
4+
spc4:
5+
profile:
6+
pkts_num_leak_out: 1
7+
xoff_1:
8+
packet_size: 600
9+
xoff_2:
10+
packet_size: 600
11+
xoff_3:
12+
packet_size: 600
13+
xoff_4:
14+
packet_size: 600
15+
wm_pg_headroom:
16+
packet_size: 600
17+
wm_q_shared_lossless:
18+
packet_size: 600
19+
hdrm_pool_size:
20+
packet_size: 600
21+
xon_1:
22+
packet_size: 600
23+
xon_2:
24+
packet_size: 600
25+
xon_3:
26+
packet_size: 600
27+
xon_4:
28+
packet_size: 600
29+
lossy_queue_1:
30+
packet_size: 600
31+
wm_pg_shared_lossless:
32+
packet_size: 600
33+
pkts_num_margin: 7
34+
wm_pg_shared_lossy:
35+
packet_size: 600
36+
wm_q_shared_lossy:
37+
packet_size: 600

tests/qos/qos_sai_base.py

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,70 @@ def __computeBufferThreshold(self, dut_asic, bufferProfile):
178178
bufferProfile["size"]) + int(bufferScale * bufferSize)}
179179
)
180180

181+
def __compute_buffer_threshold_for_nvidia_device(self, dut_asic, table, port, pg_q_buffer_profile):
182+
"""
183+
Computes buffer threshold for dynamic threshold profiles for nvidia device
184+
185+
Args:
186+
dut_asic (SonicAsic): Device ASIC Under Test (DUT)
187+
table (str): Redis table name
188+
port (str): DUT port alias
189+
pg_q_buffer_profile (dict, inout): Map of pg or q buffer profile attributes
190+
191+
Returns:
192+
Updates bufferProfile with computed buffer threshold
193+
"""
194+
195+
port_table_name = "BUFFER_PORT_EGRESS_PROFILE_LIST_TABLE" if \
196+
table == "BUFFER_QUEUE_TABLE" else "BUFFER_PORT_INGRESS_PROFILE_LIST_TABLE"
197+
db = "0"
198+
port_profile_res = dut_asic.run_redis_cmd(
199+
argv=["redis-cli", "-n", db, "HGET", f"{port_table_name}:{port}", "profile_list"]
200+
)[0]
201+
port_profile_list = port_profile_res.split(",")
202+
203+
port_dynamic_th = ''
204+
for port_profile in port_profile_list:
205+
buffer_pool_name = dut_asic.run_redis_cmd(
206+
argv=["redis-cli", "-n", db, "HGET", f'BUFFER_PROFILE_TABLE:{port_profile}', "pool"]
207+
)[0]
208+
if buffer_pool_name == pg_q_buffer_profile["pool"]:
209+
port_dynamic_th = dut_asic.run_redis_cmd(
210+
argv=["redis-cli", "-n", db, "HGET", f'BUFFER_PROFILE_TABLE:{port_profile}', "dynamic_th"]
211+
)[0]
212+
break
213+
if port_dynamic_th:
214+
215+
def calculate_alpha(dynamic_th):
216+
if dynamic_th == "7":
217+
alpha = 64
218+
else:
219+
alpha = 2 ** float(dynamic_th)
220+
return alpha
221+
222+
pg_q_alpha = calculate_alpha(pg_q_buffer_profile['dynamic_th'])
223+
port_alpha = calculate_alpha(port_dynamic_th)
224+
pool = f'BUFFER_POOL_TABLE:{pg_q_buffer_profile["pool"]}'
225+
buffer_size = int(
226+
dut_asic.run_redis_cmd(
227+
argv=["redis-cli", "-n", db, "HGET", pool, "size"]
228+
)[0]
229+
)
230+
231+
buffer_scale = port_alpha * pg_q_alpha / (port_alpha * pg_q_alpha + pg_q_alpha + 1)
232+
233+
pg_q_max_occupancy = int(buffer_size * buffer_scale)
234+
235+
pg_q_buffer_profile.update(
236+
{"static_th": int(
237+
pg_q_buffer_profile["size"]) + int(pg_q_max_occupancy)}
238+
)
239+
pg_q_buffer_profile["pg_q_alpha"] = pg_q_alpha
240+
pg_q_buffer_profile["port_alpha"] = port_alpha
241+
pg_q_buffer_profile["pool_size"] = buffer_size
242+
else:
243+
raise Exception("Not found port dynamic th")
244+
181245
def __updateVoidRoidParams(self, dut_asic, bufferProfile):
182246
"""
183247
Updates buffer profile with VOID/ROID params
@@ -271,7 +335,10 @@ def __getBufferProfile(self, request, dut_asic, os_version, table, port, priorit
271335

272336
# Update profile static threshold value if profile threshold is dynamic
273337
if "dynamic_th" in list(bufferProfile.keys()):
274-
self.__computeBufferThreshold(dut_asic, bufferProfile)
338+
if dut_asic.sonichost.facts['platform'] == "x86_64-nvidia_sn5600-r0":
339+
self.__compute_buffer_threshold_for_nvidia_device(dut_asic, table, port, bufferProfile)
340+
else:
341+
self.__computeBufferThreshold(dut_asic, bufferProfile)
275342

276343
if "pg_lossless" in bufferProfileName:
277344
pytest_assert(

0 commit comments

Comments
 (0)