Skip to content

Commit 94ec710

Browse files
Enhance multi-asic support for queuestat (#3554)
- Added support for iterating over all namespaces (ns) when none specified - Added a test case to verify all ns behaviour - Introduced a wrapper class to handle the mutli-asic functionality - Replaced argparse with click for better argument checks
1 parent 688c1d1 commit 94ec710

File tree

3 files changed

+210
-56
lines changed

3 files changed

+210
-56
lines changed

scripts/queuestat

+61-56
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#####################################################################
88

99
import json
10-
import argparse
10+
import click
1111
import datetime
1212
import os.path
1313
import sys
@@ -102,23 +102,40 @@ def build_json(port, cnstat, voq=False):
102102
out.update(ports_stats(k))
103103
return out
104104

105+
class QueuestatWrapper(object):
106+
"""A wrapper to execute queuestat cmd over the correct namespaces"""
107+
def __init__(self, namespace, voq):
108+
self.namespace = namespace
109+
self.voq = voq
105110

106-
class Queuestat(object):
107-
def __init__(self, namespace, voq=False):
111+
# Initialize the multi-asic namespace
112+
self.multi_asic = multi_asic_util.MultiAsic(constants.DISPLAY_ALL, namespace_option=namespace)
108113
self.db = None
109-
self.multi_asic = multi_asic_util.MultiAsic(constants.DISPLAY_ALL, namespace)
110-
if namespace is not None:
111-
for ns in self.multi_asic.get_ns_list_based_on_options():
112-
self.db = multi_asic.connect_to_all_dbs_for_ns(ns)
114+
115+
@multi_asic_util.run_on_multi_asic
116+
def run(self, save_fresh_stats, port_to_show_stats, json_opt, non_zero):
117+
queuestat = Queuestat(self.multi_asic.current_namespace, self.db, self.voq)
118+
if save_fresh_stats:
119+
queuestat.save_fresh_stats()
120+
return
121+
122+
if port_to_show_stats != None:
123+
queuestat.get_print_port_stat(port_to_show_stats, json_opt, non_zero)
113124
else:
114-
self.db = SonicV2Connector(use_unix_socket_path=False)
115-
self.db.connect(self.db.COUNTERS_DB)
125+
queuestat.get_print_all_stat(json_opt, non_zero)
126+
127+
128+
class Queuestat(object):
129+
def __init__(self, namespace, db, voq=False):
130+
self.db = db
116131
self.voq = voq
132+
self.namespace = namespace
133+
self.namespace_str = f" for {namespace}" if namespace else ''
117134

118135
def get_queue_port(table_id):
119136
port_table_id = self.db.get(self.db.COUNTERS_DB, COUNTERS_QUEUE_PORT_MAP, table_id)
120137
if port_table_id is None:
121-
print("Port is not available!", table_id)
138+
print(f"Port is not available{self.namespace_str}!", table_id)
122139
sys.exit(1)
123140

124141
return port_table_id
@@ -130,7 +147,7 @@ class Queuestat(object):
130147
self.counter_port_name_map = self.db.get_all(self.db.COUNTERS_DB, COUNTERS_PORT_NAME_MAP)
131148

132149
if self.counter_port_name_map is None:
133-
print("COUNTERS_PORT_NAME_MAP is empty!")
150+
print(f"COUNTERS_PORT_NAME_MAP is empty{self.namespace_str}!")
134151
sys.exit(1)
135152

136153
self.port_queues_map = {}
@@ -148,7 +165,7 @@ class Queuestat(object):
148165
counter_queue_name_map = self.db.get_all(self.db.COUNTERS_DB, COUNTERS_QUEUE_NAME_MAP)
149166

150167
if counter_queue_name_map is None:
151-
print("COUNTERS_QUEUE_NAME_MAP is empty!")
168+
print(f"COUNTERS_QUEUE_NAME_MAP is empty{self.namespace_str}!")
152169
sys.exit(1)
153170

154171
for queue in counter_queue_name_map:
@@ -166,15 +183,15 @@ class Queuestat(object):
166183
def get_queue_index(table_id):
167184
queue_index = self.db.get(self.db.COUNTERS_DB, COUNTERS_QUEUE_INDEX_MAP, table_id)
168185
if queue_index is None:
169-
print("Queue index is not available!", table_id)
186+
print(f"Queue index is not available{self.namespace_str}!", table_id)
170187
sys.exit(1)
171188

172189
return queue_index
173190

174191
def get_queue_type(table_id):
175192
queue_type = self.db.get(self.db.COUNTERS_DB, COUNTERS_QUEUE_TYPE_MAP, table_id)
176193
if queue_type is None:
177-
print("Queue Type is not available!", table_id)
194+
print(f"Queue Type is not available{self.namespace_str}!", table_id)
178195
sys.exit(1)
179196
elif queue_type == SAI_QUEUE_TYPE_MULTICAST:
180197
return QUEUE_TYPE_MC
@@ -185,7 +202,7 @@ class Queuestat(object):
185202
elif queue_type == SAI_QUEUE_TYPE_ALL:
186203
return QUEUE_TYPE_ALL
187204
else:
188-
print("Queue Type is invalid:", table_id, queue_type)
205+
print(f"Queue Type is invalid{self.namespace_str}:", table_id, queue_type)
189206
sys.exit(1)
190207

191208
if self.voq:
@@ -255,6 +272,7 @@ class Queuestat(object):
255272
else:
256273
hdr = voq_header if self.voq else header
257274
if table:
275+
print(f"For namespace {self.namespace}:")
258276
print(tabulate(table, hdr, tablefmt='simple', stralign='right'))
259277
print()
260278

@@ -314,7 +332,7 @@ class Queuestat(object):
314332
else:
315333
hdr = voq_header if self.voq else header
316334
if table:
317-
print(port + " Last cached time was " + str(cnstat_old_dict.get('time')))
335+
print(port + f" Last cached time{self.namespace_str} was " + str(cnstat_old_dict.get('time')))
318336
print(tabulate(table, hdr, tablefmt='simple', stralign='right'))
319337
print()
320338

@@ -370,7 +388,7 @@ class Queuestat(object):
370388
json_output[port].update({"cached_time":cnstat_cached_dict.get('time')})
371389
json_output.update(self.cnstat_diff_print(port, cnstat_dict, cnstat_cached_dict, json_opt, non_zero))
372390
else:
373-
print("Last cached time was " + str(cnstat_cached_dict.get('time')))
391+
print(f"Last cached time{self.namespace_str} was " + str(cnstat_cached_dict.get('time')))
374392
self.cnstat_diff_print(port, cnstat_dict, cnstat_cached_dict, json_opt, non_zero)
375393
except IOError as e:
376394
print(e.errno, e)
@@ -395,38 +413,33 @@ class Queuestat(object):
395413
else:
396414
print("Clear and update saved counters for " + port)
397415

398-
def main():
416+
417+
@click.command()
418+
@click.option('-p', '--port', type=str, help='Show the queue conters for just one port', default=None)
419+
@click.option('-c', '--clear', is_flag=True, default=False, help='Clear previous stats and save new ones')
420+
@click.option('-d', '--delete', is_flag=True, default=False, help='Delete saved stats')
421+
@click.option('-j', '--json_opt', is_flag=True, default=False, help='Print in JSON format')
422+
@click.option('-V', '--voq', is_flag=True, default=False, help='display voq stats')
423+
@click.option('-nz','--non_zero', is_flag=True, default=False, help='Display non-zero queue counters')
424+
@click.option('-n', '--namespace', type=click.Choice(multi_asic.get_namespace_list()), help='Display queuecounters for a specific namespace name or skip for all', default=None)
425+
@click.version_option(version='1.0')
426+
def main(port, clear, delete, json_opt, voq, non_zero, namespace):
427+
"""
428+
Examples:
429+
queuestat
430+
queuestat -p Ethernet0
431+
queuestat -c
432+
queuestat -d
433+
queuestat -p Ethernet0 -n asic0
434+
"""
435+
399436
global cnstat_dir
400437
global cnstat_fqn_file
401438

402-
parser = argparse.ArgumentParser(description='Display the queue state and counters',
403-
formatter_class=argparse.RawTextHelpFormatter,
404-
epilog="""
405-
Examples:
406-
queuestat
407-
queuestat -p Ethernet0
408-
queuestat -c
409-
queuestat -d
410-
""")
411-
412-
parser.add_argument('-p', '--port', type=str, help='Show the queue conters for just one port', default=None)
413-
parser.add_argument('-c', '--clear', action='store_true', help='Clear previous stats and save new ones')
414-
parser.add_argument('-d', '--delete', action='store_true', help='Delete saved stats')
415-
parser.add_argument('-v', '--version', action='version', version='%(prog)s 1.0')
416-
parser.add_argument('-j', '--json_opt', action='store_true', help='Print in JSON format')
417-
parser.add_argument('-V', '--voq', action='store_true', help='display voq stats')
418-
parser.add_argument('-n','--namespace', default=None, help='Display queue counters for specific namespace')
419-
parser.add_argument('-nz','--non_zero', action='store_true', help='Display non-zero queue counters')
420-
args = parser.parse_args()
421-
422-
save_fresh_stats = args.clear
423-
delete_stats = args.delete
424-
voq = args.voq
425-
json_opt = args.json_opt
426-
namespace = args.namespace
427-
non_zero = args.non_zero
428-
429-
port_to_show_stats = args.port
439+
save_fresh_stats = clear
440+
delete_stats = delete
441+
442+
port_to_show_stats = port
430443

431444
cache = UserCache()
432445

@@ -436,16 +449,8 @@ Examples:
436449
if delete_stats:
437450
cache.remove()
438451

439-
queuestat = Queuestat( namespace, voq )
440-
441-
if save_fresh_stats:
442-
queuestat.save_fresh_stats()
443-
sys.exit(0)
444-
445-
if port_to_show_stats!=None:
446-
queuestat.get_print_port_stat(port_to_show_stats, json_opt, non_zero)
447-
else:
448-
queuestat.get_print_all_stat(json_opt, non_zero)
452+
queuestat_wrapper = QueuestatWrapper(namespace, voq)
453+
queuestat_wrapper.run(save_fresh_stats, port_to_show_stats, json_opt, non_zero)
449454

450455
sys.exit(0)
451456

tests/multi_asic_queue_counter_test.py

+133
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323

2424
show_queue_counters = """\
25+
For namespace asic0:
2526
Port TxQ Counter/pkts Counter/bytes Drop/pkts Drop/bytes
2627
--------- ----- -------------- --------------- ----------- ------------
2728
Ethernet0 UC0 68 30 56 74
@@ -41,6 +42,7 @@
4142
Ethernet0 MC14 82 44 42 60
4243
Ethernet0 MC15 83 45 41 59
4344
45+
For namespace asic0:
4446
Port TxQ Counter/pkts Counter/bytes Drop/pkts Drop/bytes
4547
--------- ----- -------------- --------------- ----------- ------------
4648
Ethernet4 UC0 84 46 40 58
@@ -60,6 +62,7 @@
6062
Ethernet4 MC14 98 60 26 44
6163
Ethernet4 MC15 99 61 25 43
6264
65+
For namespace asic0:
6366
Port TxQ Counter/pkts Counter/bytes Drop/pkts Drop/bytes
6467
------------ ----- -------------- --------------- ----------- ------------
6568
Ethernet-BP0 UC0 100 62 24 42
@@ -79,6 +82,7 @@
7982
Ethernet-BP0 MC14 114 76 10 28
8083
Ethernet-BP0 MC15 115 77 9 27
8184
85+
For namespace asic0:
8286
Port TxQ Counter/pkts Counter/bytes Drop/pkts Drop/bytes
8387
------------ ----- -------------- --------------- ----------- ------------
8488
Ethernet-BP4 UC0 116 78 8 26
@@ -100,8 +104,131 @@
100104
101105
"""
102106

107+
show_queue_counters_all_asics = """\
108+
For namespace asic0:
109+
Port TxQ Counter/pkts Counter/bytes Drop/pkts Drop/bytes
110+
--------- ----- -------------- --------------- ----------- ------------
111+
Ethernet0 UC0 68 30 56 74
112+
Ethernet0 UC1 69 31 55 73
113+
Ethernet0 UC2 70 32 54 72
114+
Ethernet0 UC3 71 33 53 71
115+
Ethernet0 UC4 72 34 52 70
116+
Ethernet0 UC5 73 35 51 69
117+
Ethernet0 UC6 74 36 50 68
118+
Ethernet0 UC7 75 37 49 67
119+
Ethernet0 MC8 76 38 48 66
120+
Ethernet0 MC9 77 39 47 65
121+
Ethernet0 MC10 78 40 46 64
122+
Ethernet0 MC11 79 41 45 63
123+
Ethernet0 MC12 80 42 44 62
124+
Ethernet0 MC13 81 43 43 61
125+
Ethernet0 MC14 82 44 42 60
126+
Ethernet0 MC15 83 45 41 59
127+
128+
For namespace asic0:
129+
Port TxQ Counter/pkts Counter/bytes Drop/pkts Drop/bytes
130+
--------- ----- -------------- --------------- ----------- ------------
131+
Ethernet4 UC0 84 46 40 58
132+
Ethernet4 UC1 85 47 39 57
133+
Ethernet4 UC2 86 48 38 56
134+
Ethernet4 UC3 87 49 37 55
135+
Ethernet4 UC4 88 50 36 54
136+
Ethernet4 UC5 89 51 35 53
137+
Ethernet4 UC6 90 52 34 52
138+
Ethernet4 UC7 91 53 33 51
139+
Ethernet4 MC8 92 54 32 50
140+
Ethernet4 MC9 93 55 31 49
141+
Ethernet4 MC10 94 56 30 48
142+
Ethernet4 MC11 95 57 29 47
143+
Ethernet4 MC12 96 58 28 46
144+
Ethernet4 MC13 97 59 27 45
145+
Ethernet4 MC14 98 60 26 44
146+
Ethernet4 MC15 99 61 25 43
147+
148+
For namespace asic0:
149+
Port TxQ Counter/pkts Counter/bytes Drop/pkts Drop/bytes
150+
------------ ----- -------------- --------------- ----------- ------------
151+
Ethernet-BP0 UC0 100 62 24 42
152+
Ethernet-BP0 UC1 101 63 23 41
153+
Ethernet-BP0 UC2 102 64 22 40
154+
Ethernet-BP0 UC3 103 65 21 39
155+
Ethernet-BP0 UC4 104 66 20 38
156+
Ethernet-BP0 UC5 105 67 19 37
157+
Ethernet-BP0 UC6 106 68 18 36
158+
Ethernet-BP0 UC7 107 69 17 35
159+
Ethernet-BP0 MC8 108 70 16 34
160+
Ethernet-BP0 MC9 109 71 15 33
161+
Ethernet-BP0 MC10 110 72 14 32
162+
Ethernet-BP0 MC11 111 73 13 31
163+
Ethernet-BP0 MC12 112 74 12 30
164+
Ethernet-BP0 MC13 113 75 11 29
165+
Ethernet-BP0 MC14 114 76 10 28
166+
Ethernet-BP0 MC15 115 77 9 27
167+
168+
For namespace asic0:
169+
Port TxQ Counter/pkts Counter/bytes Drop/pkts Drop/bytes
170+
------------ ----- -------------- --------------- ----------- ------------
171+
Ethernet-BP4 UC0 116 78 8 26
172+
Ethernet-BP4 UC1 117 79 7 25
173+
Ethernet-BP4 UC2 118 80 6 24
174+
Ethernet-BP4 UC3 119 81 5 23
175+
Ethernet-BP4 UC4 120 82 4 22
176+
Ethernet-BP4 UC5 121 83 3 21
177+
Ethernet-BP4 UC6 122 84 2 20
178+
Ethernet-BP4 UC7 123 85 1 19
179+
Ethernet-BP4 ALL8 124 86 0 18
180+
Ethernet-BP4 ALL9 125 87 1 17
181+
Ethernet-BP4 ALL10 126 88 2 16
182+
Ethernet-BP4 ALL11 127 89 3 15
183+
Ethernet-BP4 ALL12 128 90 4 14
184+
Ethernet-BP4 ALL13 129 91 5 13
185+
Ethernet-BP4 ALL14 130 92 6 12
186+
Ethernet-BP4 ALL15 131 93 7 11
187+
188+
For namespace asic1:
189+
Port TxQ Counter/pkts Counter/bytes Drop/pkts Drop/bytes
190+
-------------- ----- -------------- --------------- ----------- ------------
191+
Ethernet-BP256 UC0 N/A N/A N/A N/A
192+
Ethernet-BP256 UC1 N/A N/A N/A N/A
193+
Ethernet-BP256 UC2 N/A N/A N/A N/A
194+
Ethernet-BP256 UC3 N/A N/A N/A N/A
195+
Ethernet-BP256 UC4 N/A N/A N/A N/A
196+
Ethernet-BP256 UC5 N/A N/A N/A N/A
197+
Ethernet-BP256 UC6 N/A N/A N/A N/A
198+
Ethernet-BP256 UC7 N/A N/A N/A N/A
199+
Ethernet-BP256 MC8 N/A N/A N/A N/A
200+
Ethernet-BP256 MC9 N/A N/A N/A N/A
201+
Ethernet-BP256 MC10 N/A N/A N/A N/A
202+
Ethernet-BP256 MC11 N/A N/A N/A N/A
203+
Ethernet-BP256 MC12 N/A N/A N/A N/A
204+
Ethernet-BP256 MC13 N/A N/A N/A N/A
205+
Ethernet-BP256 MC14 N/A N/A N/A N/A
206+
Ethernet-BP256 MC15 N/A N/A N/A N/A
207+
208+
For namespace asic1:
209+
Port TxQ Counter/pkts Counter/bytes Drop/pkts Drop/bytes
210+
-------------- ----- -------------- --------------- ----------- ------------
211+
Ethernet-BP260 UC0 N/A N/A N/A N/A
212+
Ethernet-BP260 UC1 N/A N/A N/A N/A
213+
Ethernet-BP260 UC2 N/A N/A N/A N/A
214+
Ethernet-BP260 UC3 N/A N/A N/A N/A
215+
Ethernet-BP260 UC4 N/A N/A N/A N/A
216+
Ethernet-BP260 UC5 N/A N/A N/A N/A
217+
Ethernet-BP260 UC6 N/A N/A N/A N/A
218+
Ethernet-BP260 UC7 N/A N/A N/A N/A
219+
Ethernet-BP260 ALL8 N/A N/A N/A N/A
220+
Ethernet-BP260 ALL9 N/A N/A N/A N/A
221+
Ethernet-BP260 ALL10 N/A N/A N/A N/A
222+
Ethernet-BP260 ALL11 N/A N/A N/A N/A
223+
Ethernet-BP260 ALL12 N/A N/A N/A N/A
224+
Ethernet-BP260 ALL13 N/A N/A N/A N/A
225+
Ethernet-BP260 ALL14 N/A N/A N/A N/A
226+
Ethernet-BP260 ALL15 N/A N/A N/A N/A
227+
228+
"""
103229

104230
show_queue_counters_port = """\
231+
For namespace asic0:
105232
Port TxQ Counter/pkts Counter/bytes Drop/pkts Drop/bytes
106233
------------ ----- -------------- --------------- ----------- ------------
107234
Ethernet-BP4 UC0 116 78 8 26
@@ -143,6 +270,12 @@ def test_queue_counters_port(self):
143270
print(result)
144271
assert result == show_queue_counters_port
145272

273+
def test_queue_counters_all_masic(self):
274+
return_code, result = get_result_and_return_code(['queuestat'])
275+
assert return_code == 0
276+
print(result)
277+
assert result == show_queue_counters_all_asics
278+
146279
@classmethod
147280
def teardown_class(cls):
148281
os.environ["PATH"] = os.pathsep.join(os.environ["PATH"].split(os.pathsep)[:-1])

0 commit comments

Comments
 (0)