xref: /aosp_15_r20/external/bcc/tools/netqtop.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1#!/usr/bin/env python
2
3from __future__ import print_function
4from bcc import BPF
5from ctypes import *
6import argparse
7import os
8from time import sleep,time,localtime,asctime
9
10# pre defines -------------------------------
11ROOT_PATH = "/sys/class/net"
12IFNAMSIZ = 16
13COL_WIDTH = 10
14MAX_QUEUE_NUM = 1024
15EBPF_FILE = "netqtop.c"
16
17# structure for network interface name array
18class Devname(Structure):
19    _fields_=[
20        ('name', c_char*IFNAMSIZ)
21    ]
22
23################## printer for results ###################
24def to_str(num):
25    s = ""
26    if num > 1000000:
27        return str(round(num/(1024*1024.0), 2)) + 'M'
28    elif num > 1000:
29        return str(round(num/1024.0, 2)) + 'K'
30    else:
31        if isinstance(num, float):
32            return str(round(num, 2))
33        else:
34            return str(num)
35
36def print_table(table, qnum):
37    global print_interval
38
39    # ---- print headers ----------------
40    headers = [
41		"QueueID",
42		"avg_size",
43		"[0, 64)",
44		"[64, 512)",
45		"[512, 2K)",
46		"[2K, 16K)",
47		"[16K, 64K)"
48	]
49    if args.throughput:
50        headers.append("BPS")
51        headers.append("PPS")
52
53    print(" ", end="")
54    for hd in headers:
55        print( "%-11s" % hd, end="")
56    print()
57
58    # ------- calculates --------------
59    qids=[]
60    tBPS = 0
61    tPPS = 0
62    tAVG = 0
63    tGroup = [0,0,0,0,0]
64    tpkt = 0
65    tlen = 0
66    for k, v in table.items():
67        qids += [k.value]
68        tlen += v.total_pkt_len
69        tpkt += v.num_pkt
70        tGroup[0] += v.size_64B
71        tGroup[1] += v.size_512B
72        tGroup[2] += v.size_2K
73        tGroup[3] += v.size_16K
74        tGroup[4] += v.size_64K
75    tBPS = tlen / print_interval
76    tPPS = tpkt / print_interval
77    if tpkt != 0:
78        tAVG = tlen / tpkt
79
80    # -------- print table --------------
81    for k in range(qnum):
82        if k in qids:
83            item = table[c_ushort(k)]
84            data = [
85                k,
86                item.total_pkt_len,
87                item.num_pkt,
88                item.size_64B,
89                item.size_512B,
90                item.size_2K,
91                item.size_16K,
92                item.size_64K
93            ]
94        else:
95            data = [k,0,0,0,0,0,0,0]
96
97        # print a line per queue
98        avg = 0
99        if data[2] != 0:
100            avg = data[1] / data[2]
101        print(" %-11d%-11s%-11s%-11s%-11s%-11s%-11s" % (
102            data[0],
103            to_str(avg),
104            to_str(data[3]),
105            to_str(data[4]),
106            to_str(data[5]),
107            to_str(data[6]),
108            to_str(data[7])
109        ), end="")
110        if args.throughput:
111            BPS = data[1] / print_interval
112            PPS = data[2] / print_interval
113            print("%-11s%-11s" % (
114                to_str(BPS),
115                to_str(PPS)
116            ))
117        else:
118            print()
119
120    # ------- print total --------------
121    print(" Total      %-11s%-11s%-11s%-11s%-11s%-11s" % (
122        to_str(tAVG),
123        to_str(tGroup[0]),
124        to_str(tGroup[1]),
125        to_str(tGroup[2]),
126        to_str(tGroup[3]),
127        to_str(tGroup[4])
128    ), end="")
129
130    if args.throughput:
131        print("%-11s%-11s" % (
132            to_str(tBPS),
133            to_str(tPPS)
134        ))
135    else:
136        print()
137
138
139def print_result(b):
140    # --------- print tx queues ---------------
141    print(asctime(localtime(time())))
142    print("TX")
143    table = b['tx_q']
144    print_table(table, tx_num)
145    b['tx_q'].clear()
146
147    # --------- print rx queues ---------------
148    print("")
149    print("RX")
150    table = b['rx_q']
151    print_table(table, rx_num)
152    b['rx_q'].clear()
153    if args.throughput:
154        print("-"*95)
155    else:
156        print("-"*77)
157
158############## specify network interface #################
159parser = argparse.ArgumentParser(description="")
160parser.add_argument("--name", "-n", type=str, default="")
161parser.add_argument("--interval", "-i", type=float, default=1)
162parser.add_argument("--throughput", "-t", action="store_true")
163parser.add_argument("--ebpf", action="store_true", help=argparse.SUPPRESS)
164args = parser.parse_args()
165
166if args.ebpf:
167    with open(EBPF_FILE) as fileobj:
168        progtxt = fileobj.read()
169        print(progtxt)
170    exit()
171
172if args.name == "":
173	print ("Please specify a network interface.")
174	exit()
175else:
176	dev_name = args.name
177
178if len(dev_name) > IFNAMSIZ-1:
179    print ("NIC name too long")
180    exit()
181
182print_interval = args.interval + 0.0
183if print_interval == 0:
184    print ("print interval must be non-zero")
185    exit()
186
187################ get number of queues #####################
188tx_num = 0
189rx_num = 0
190path = ROOT_PATH + "/" + dev_name + "/queues"
191if not os.path.exists(path):
192	print ("Net interface", dev_name, "does not exits.")
193	exit()
194
195list = os.listdir(path)
196for s in list:
197    if s[0] == 'r':
198        rx_num += 1
199    if s[0] == 't':
200        tx_num += 1
201
202if tx_num > MAX_QUEUE_NUM or rx_num > MAX_QUEUE_NUM:
203    print ("number of queues over 1024 is not supported.")
204    exit()
205
206################## start tracing ##################
207b = BPF(src_file = EBPF_FILE)
208# --------- set hash array --------
209devname_map = b['name_map']
210_name = Devname()
211_name.name = dev_name.encode()
212devname_map[0] = _name
213
214while 1:
215    try:
216        sleep(print_interval)
217        print_result(b)
218    except KeyboardInterrupt:
219        exit()
220