Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix multi-asic behaviour for queuestat #3554

Merged
merged 1 commit into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 61 additions & 56 deletions scripts/queuestat
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#####################################################################

import json
import argparse
import click
import datetime
import os.path
import sys
Expand Down Expand Up @@ -102,23 +102,40 @@ def build_json(port, cnstat, voq=False):
out.update(ports_stats(k))
return out

class QueuestatWrapper(object):
"""A wrapper to execute queuestat cmd over the correct namespaces"""
def __init__(self, namespace, voq):
self.namespace = namespace
self.voq = voq

class Queuestat(object):
def __init__(self, namespace, voq=False):
# Initialize the multi-asic namespace
self.multi_asic = multi_asic_util.MultiAsic(constants.DISPLAY_ALL, namespace_option=namespace)
self.db = None
self.multi_asic = multi_asic_util.MultiAsic(constants.DISPLAY_ALL, namespace)
if namespace is not None:
for ns in self.multi_asic.get_ns_list_based_on_options():
self.db = multi_asic.connect_to_all_dbs_for_ns(ns)

@multi_asic_util.run_on_multi_asic
def run(self, save_fresh_stats, port_to_show_stats, json_opt, non_zero):
queuestat = Queuestat(self.multi_asic.current_namespace, self.db, self.voq)
if save_fresh_stats:
queuestat.save_fresh_stats()
return

if port_to_show_stats != None:
queuestat.get_print_port_stat(port_to_show_stats, json_opt, non_zero)
else:
self.db = SonicV2Connector(use_unix_socket_path=False)
self.db.connect(self.db.COUNTERS_DB)
queuestat.get_print_all_stat(json_opt, non_zero)


class Queuestat(object):
def __init__(self, namespace, db, voq=False):
self.db = db
self.voq = voq
self.namespace = namespace
self.namespace_str = f" for {namespace}" if namespace else ''

def get_queue_port(table_id):
port_table_id = self.db.get(self.db.COUNTERS_DB, COUNTERS_QUEUE_PORT_MAP, table_id)
if port_table_id is None:
print("Port is not available!", table_id)
print(f"Port is not available{self.namespace_str}!", table_id)
sys.exit(1)

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

if self.counter_port_name_map is None:
print("COUNTERS_PORT_NAME_MAP is empty!")
print(f"COUNTERS_PORT_NAME_MAP is empty{self.namespace_str}!")
sys.exit(1)

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

if counter_queue_name_map is None:
print("COUNTERS_QUEUE_NAME_MAP is empty!")
print(f"COUNTERS_QUEUE_NAME_MAP is empty{self.namespace_str}!")
sys.exit(1)

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

return queue_index

def get_queue_type(table_id):
queue_type = self.db.get(self.db.COUNTERS_DB, COUNTERS_QUEUE_TYPE_MAP, table_id)
if queue_type is None:
print("Queue Type is not available!", table_id)
print(f"Queue Type is not available{self.namespace_str}!", table_id)
sys.exit(1)
elif queue_type == SAI_QUEUE_TYPE_MULTICAST:
return QUEUE_TYPE_MC
Expand All @@ -185,7 +202,7 @@ class Queuestat(object):
elif queue_type == SAI_QUEUE_TYPE_ALL:
return QUEUE_TYPE_ALL
else:
print("Queue Type is invalid:", table_id, queue_type)
print(f"Queue Type is invalid{self.namespace_str}:", table_id, queue_type)
sys.exit(1)

if self.voq:
Expand Down Expand Up @@ -255,6 +272,7 @@ class Queuestat(object):
else:
hdr = voq_header if self.voq else header
if table:
print(f"For namespace {self.namespace}:")
print(tabulate(table, hdr, tablefmt='simple', stralign='right'))
print()

Expand Down Expand Up @@ -314,7 +332,7 @@ class Queuestat(object):
else:
hdr = voq_header if self.voq else header
if table:
print(port + " Last cached time was " + str(cnstat_old_dict.get('time')))
print(port + f" Last cached time{self.namespace_str} was " + str(cnstat_old_dict.get('time')))
print(tabulate(table, hdr, tablefmt='simple', stralign='right'))
print()

Expand Down Expand Up @@ -370,7 +388,7 @@ class Queuestat(object):
json_output[port].update({"cached_time":cnstat_cached_dict.get('time')})
json_output.update(self.cnstat_diff_print(port, cnstat_dict, cnstat_cached_dict, json_opt, non_zero))
else:
print("Last cached time was " + str(cnstat_cached_dict.get('time')))
print(f"Last cached time{self.namespace_str} was " + str(cnstat_cached_dict.get('time')))
self.cnstat_diff_print(port, cnstat_dict, cnstat_cached_dict, json_opt, non_zero)
except IOError as e:
print(e.errno, e)
Expand All @@ -395,38 +413,33 @@ class Queuestat(object):
else:
print("Clear and update saved counters for " + port)

def main():

@click.command()
@click.option('-p', '--port', type=str, help='Show the queue conters for just one port', default=None)
@click.option('-c', '--clear', is_flag=True, default=False, help='Clear previous stats and save new ones')
@click.option('-d', '--delete', is_flag=True, default=False, help='Delete saved stats')
@click.option('-j', '--json_opt', is_flag=True, default=False, help='Print in JSON format')
@click.option('-V', '--voq', is_flag=True, default=False, help='display voq stats')
@click.option('-nz','--non_zero', is_flag=True, default=False, help='Display non-zero queue counters')
@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)
@click.version_option(version='1.0')
def main(port, clear, delete, json_opt, voq, non_zero, namespace):
"""
Examples:
queuestat
queuestat -p Ethernet0
queuestat -c
queuestat -d
queuestat -p Ethernet0 -n asic0
"""

global cnstat_dir
global cnstat_fqn_file

parser = argparse.ArgumentParser(description='Display the queue state and counters',
formatter_class=argparse.RawTextHelpFormatter,
epilog="""
Examples:
queuestat
queuestat -p Ethernet0
queuestat -c
queuestat -d
""")

parser.add_argument('-p', '--port', type=str, help='Show the queue conters for just one port', default=None)
parser.add_argument('-c', '--clear', action='store_true', help='Clear previous stats and save new ones')
parser.add_argument('-d', '--delete', action='store_true', help='Delete saved stats')
parser.add_argument('-v', '--version', action='version', version='%(prog)s 1.0')
parser.add_argument('-j', '--json_opt', action='store_true', help='Print in JSON format')
parser.add_argument('-V', '--voq', action='store_true', help='display voq stats')
parser.add_argument('-n','--namespace', default=None, help='Display queue counters for specific namespace')
parser.add_argument('-nz','--non_zero', action='store_true', help='Display non-zero queue counters')
args = parser.parse_args()

save_fresh_stats = args.clear
delete_stats = args.delete
voq = args.voq
json_opt = args.json_opt
namespace = args.namespace
non_zero = args.non_zero

port_to_show_stats = args.port
save_fresh_stats = clear
delete_stats = delete

port_to_show_stats = port

cache = UserCache()

Expand All @@ -436,16 +449,8 @@ Examples:
if delete_stats:
cache.remove()

queuestat = Queuestat( namespace, voq )

if save_fresh_stats:
queuestat.save_fresh_stats()
sys.exit(0)

if port_to_show_stats!=None:
queuestat.get_print_port_stat(port_to_show_stats, json_opt, non_zero)
else:
queuestat.get_print_all_stat(json_opt, non_zero)
queuestat_wrapper = QueuestatWrapper(namespace, voq)
queuestat_wrapper.run(save_fresh_stats, port_to_show_stats, json_opt, non_zero)

sys.exit(0)

Expand Down
133 changes: 133 additions & 0 deletions tests/multi_asic_queue_counter_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@


show_queue_counters = """\
For namespace asic0:
Port TxQ Counter/pkts Counter/bytes Drop/pkts Drop/bytes
--------- ----- -------------- --------------- ----------- ------------
Ethernet0 UC0 68 30 56 74
Expand All @@ -41,6 +42,7 @@
Ethernet0 MC14 82 44 42 60
Ethernet0 MC15 83 45 41 59

For namespace asic0:
Port TxQ Counter/pkts Counter/bytes Drop/pkts Drop/bytes
--------- ----- -------------- --------------- ----------- ------------
Ethernet4 UC0 84 46 40 58
Expand All @@ -60,6 +62,7 @@
Ethernet4 MC14 98 60 26 44
Ethernet4 MC15 99 61 25 43

For namespace asic0:
Port TxQ Counter/pkts Counter/bytes Drop/pkts Drop/bytes
------------ ----- -------------- --------------- ----------- ------------
Ethernet-BP0 UC0 100 62 24 42
Expand All @@ -79,6 +82,7 @@
Ethernet-BP0 MC14 114 76 10 28
Ethernet-BP0 MC15 115 77 9 27

For namespace asic0:
Port TxQ Counter/pkts Counter/bytes Drop/pkts Drop/bytes
------------ ----- -------------- --------------- ----------- ------------
Ethernet-BP4 UC0 116 78 8 26
Expand All @@ -100,8 +104,131 @@

"""

show_queue_counters_all_asics = """\
For namespace asic0:
Port TxQ Counter/pkts Counter/bytes Drop/pkts Drop/bytes
--------- ----- -------------- --------------- ----------- ------------
Ethernet0 UC0 68 30 56 74
Ethernet0 UC1 69 31 55 73
Ethernet0 UC2 70 32 54 72
Ethernet0 UC3 71 33 53 71
Ethernet0 UC4 72 34 52 70
Ethernet0 UC5 73 35 51 69
Ethernet0 UC6 74 36 50 68
Ethernet0 UC7 75 37 49 67
Ethernet0 MC8 76 38 48 66
Ethernet0 MC9 77 39 47 65
Ethernet0 MC10 78 40 46 64
Ethernet0 MC11 79 41 45 63
Ethernet0 MC12 80 42 44 62
Ethernet0 MC13 81 43 43 61
Ethernet0 MC14 82 44 42 60
Ethernet0 MC15 83 45 41 59

For namespace asic0:
Port TxQ Counter/pkts Counter/bytes Drop/pkts Drop/bytes
--------- ----- -------------- --------------- ----------- ------------
Ethernet4 UC0 84 46 40 58
Ethernet4 UC1 85 47 39 57
Ethernet4 UC2 86 48 38 56
Ethernet4 UC3 87 49 37 55
Ethernet4 UC4 88 50 36 54
Ethernet4 UC5 89 51 35 53
Ethernet4 UC6 90 52 34 52
Ethernet4 UC7 91 53 33 51
Ethernet4 MC8 92 54 32 50
Ethernet4 MC9 93 55 31 49
Ethernet4 MC10 94 56 30 48
Ethernet4 MC11 95 57 29 47
Ethernet4 MC12 96 58 28 46
Ethernet4 MC13 97 59 27 45
Ethernet4 MC14 98 60 26 44
Ethernet4 MC15 99 61 25 43

For namespace asic0:
Port TxQ Counter/pkts Counter/bytes Drop/pkts Drop/bytes
------------ ----- -------------- --------------- ----------- ------------
Ethernet-BP0 UC0 100 62 24 42
Ethernet-BP0 UC1 101 63 23 41
Ethernet-BP0 UC2 102 64 22 40
Ethernet-BP0 UC3 103 65 21 39
Ethernet-BP0 UC4 104 66 20 38
Ethernet-BP0 UC5 105 67 19 37
Ethernet-BP0 UC6 106 68 18 36
Ethernet-BP0 UC7 107 69 17 35
Ethernet-BP0 MC8 108 70 16 34
Ethernet-BP0 MC9 109 71 15 33
Ethernet-BP0 MC10 110 72 14 32
Ethernet-BP0 MC11 111 73 13 31
Ethernet-BP0 MC12 112 74 12 30
Ethernet-BP0 MC13 113 75 11 29
Ethernet-BP0 MC14 114 76 10 28
Ethernet-BP0 MC15 115 77 9 27

For namespace asic0:
Port TxQ Counter/pkts Counter/bytes Drop/pkts Drop/bytes
------------ ----- -------------- --------------- ----------- ------------
Ethernet-BP4 UC0 116 78 8 26
Ethernet-BP4 UC1 117 79 7 25
Ethernet-BP4 UC2 118 80 6 24
Ethernet-BP4 UC3 119 81 5 23
Ethernet-BP4 UC4 120 82 4 22
Ethernet-BP4 UC5 121 83 3 21
Ethernet-BP4 UC6 122 84 2 20
Ethernet-BP4 UC7 123 85 1 19
Ethernet-BP4 ALL8 124 86 0 18
Ethernet-BP4 ALL9 125 87 1 17
Ethernet-BP4 ALL10 126 88 2 16
Ethernet-BP4 ALL11 127 89 3 15
Ethernet-BP4 ALL12 128 90 4 14
Ethernet-BP4 ALL13 129 91 5 13
Ethernet-BP4 ALL14 130 92 6 12
Ethernet-BP4 ALL15 131 93 7 11

For namespace asic1:
Port TxQ Counter/pkts Counter/bytes Drop/pkts Drop/bytes
-------------- ----- -------------- --------------- ----------- ------------
Ethernet-BP256 UC0 N/A N/A N/A N/A
Ethernet-BP256 UC1 N/A N/A N/A N/A
Ethernet-BP256 UC2 N/A N/A N/A N/A
Ethernet-BP256 UC3 N/A N/A N/A N/A
Ethernet-BP256 UC4 N/A N/A N/A N/A
Ethernet-BP256 UC5 N/A N/A N/A N/A
Ethernet-BP256 UC6 N/A N/A N/A N/A
Ethernet-BP256 UC7 N/A N/A N/A N/A
Ethernet-BP256 MC8 N/A N/A N/A N/A
Ethernet-BP256 MC9 N/A N/A N/A N/A
Ethernet-BP256 MC10 N/A N/A N/A N/A
Ethernet-BP256 MC11 N/A N/A N/A N/A
Ethernet-BP256 MC12 N/A N/A N/A N/A
Ethernet-BP256 MC13 N/A N/A N/A N/A
Ethernet-BP256 MC14 N/A N/A N/A N/A
Ethernet-BP256 MC15 N/A N/A N/A N/A

For namespace asic1:
Port TxQ Counter/pkts Counter/bytes Drop/pkts Drop/bytes
-------------- ----- -------------- --------------- ----------- ------------
Ethernet-BP260 UC0 N/A N/A N/A N/A
Ethernet-BP260 UC1 N/A N/A N/A N/A
Ethernet-BP260 UC2 N/A N/A N/A N/A
Ethernet-BP260 UC3 N/A N/A N/A N/A
Ethernet-BP260 UC4 N/A N/A N/A N/A
Ethernet-BP260 UC5 N/A N/A N/A N/A
Ethernet-BP260 UC6 N/A N/A N/A N/A
Ethernet-BP260 UC7 N/A N/A N/A N/A
Ethernet-BP260 ALL8 N/A N/A N/A N/A
Ethernet-BP260 ALL9 N/A N/A N/A N/A
Ethernet-BP260 ALL10 N/A N/A N/A N/A
Ethernet-BP260 ALL11 N/A N/A N/A N/A
Ethernet-BP260 ALL12 N/A N/A N/A N/A
Ethernet-BP260 ALL13 N/A N/A N/A N/A
Ethernet-BP260 ALL14 N/A N/A N/A N/A
Ethernet-BP260 ALL15 N/A N/A N/A N/A

"""

show_queue_counters_port = """\
For namespace asic0:
Port TxQ Counter/pkts Counter/bytes Drop/pkts Drop/bytes
------------ ----- -------------- --------------- ----------- ------------
Ethernet-BP4 UC0 116 78 8 26
Expand Down Expand Up @@ -143,6 +270,12 @@ def test_queue_counters_port(self):
print(result)
assert result == show_queue_counters_port

def test_queue_counters_all_masic(self):
return_code, result = get_result_and_return_code(['queuestat'])
assert return_code == 0
print(result)
assert result == show_queue_counters_all_asics

@classmethod
def teardown_class(cls):
os.environ["PATH"] = os.pathsep.join(os.environ["PATH"].split(os.pathsep)[:-1])
Expand Down
Loading
Loading