blob: 9e4a7615659da8a3f68f8fecfb813c9eb33d509b [file] [log] [blame]
#!/usr/bin/env python
from __future__ import print_function
from bcc import BPF
from ctypes import *
import argparse
import os
from time import sleep,time,localtime,asctime
# pre defines -------------------------------
ROOT_PATH = "/sys/class/net"
IFNAMSIZ = 16
COL_WIDTH = 10
MAX_QUEUE_NUM = 1024
EBPF_FILE = "netqtop.c"
# structure for network interface name array
class Devname(Structure):
_fields_=[
('name', c_char*IFNAMSIZ)
]
################## printer for results ###################
def to_str(num):
s = ""
if num > 1000000:
return str(round(num/(1024*1024.0), 2)) + 'M'
elif num > 1000:
return str(round(num/1024.0, 2)) + 'K'
else:
if isinstance(num, float):
return str(round(num, 2))
else:
return str(num)
def print_table(table, qnum):
global print_interval
# ---- print headers ----------------
headers = [
"QueueID",
"avg_size",
"[0, 64)",
"[64, 512)",
"[512, 2K)",
"[2K, 16K)",
"[16K, 64K)"
]
if args.throughput:
headers.append("BPS")
headers.append("PPS")
print(" ", end="")
for hd in headers:
print( "%-11s" % hd, end="")
print()
# ------- calculates --------------
qids=[]
tBPS = 0
tPPS = 0
tAVG = 0
tGroup = [0,0,0,0,0]
tpkt = 0
tlen = 0
for k, v in table.items():
qids += [k.value]
tlen += v.total_pkt_len
tpkt += v.num_pkt
tGroup[0] += v.size_64B
tGroup[1] += v.size_512B
tGroup[2] += v.size_2K
tGroup[3] += v.size_16K
tGroup[4] += v.size_64K
tBPS = tlen / print_interval
tPPS = tpkt / print_interval
if tpkt != 0:
tAVG = tlen / tpkt
# -------- print table --------------
for k in range(qnum):
if k in qids:
item = table[c_ushort(k)]
data = [
k,
item.total_pkt_len,
item.num_pkt,
item.size_64B,
item.size_512B,
item.size_2K,
item.size_16K,
item.size_64K
]
else:
data = [k,0,0,0,0,0,0,0]
# print a line per queue
avg = 0
if data[2] != 0:
avg = data[1] / data[2]
print(" %-11d%-11s%-11s%-11s%-11s%-11s%-11s" % (
data[0],
to_str(avg),
to_str(data[3]),
to_str(data[4]),
to_str(data[5]),
to_str(data[6]),
to_str(data[7])
), end="")
if args.throughput:
BPS = data[1] / print_interval
PPS = data[2] / print_interval
print("%-11s%-11s" % (
to_str(BPS),
to_str(PPS)
))
else:
print()
# ------- print total --------------
print(" Total %-11s%-11s%-11s%-11s%-11s%-11s" % (
to_str(tAVG),
to_str(tGroup[0]),
to_str(tGroup[1]),
to_str(tGroup[2]),
to_str(tGroup[3]),
to_str(tGroup[4])
), end="")
if args.throughput:
print("%-11s%-11s" % (
to_str(tBPS),
to_str(tPPS)
))
else:
print()
def print_result(b):
# --------- print tx queues ---------------
print(asctime(localtime(time())))
print("TX")
table = b['tx_q']
print_table(table, tx_num)
b['tx_q'].clear()
# --------- print rx queues ---------------
print("")
print("RX")
table = b['rx_q']
print_table(table, rx_num)
b['rx_q'].clear()
if args.throughput:
print("-"*95)
else:
print("-"*77)
############## specify network interface #################
parser = argparse.ArgumentParser(description="")
parser.add_argument("--name", "-n", type=str, default="")
parser.add_argument("--interval", "-i", type=float, default=1)
parser.add_argument("--throughput", "-t", action="store_true")
parser.add_argument("--ebpf", action="store_true", help=argparse.SUPPRESS)
args = parser.parse_args()
if args.ebpf:
with open(EBPF_FILE) as fileobj:
progtxt = fileobj.read()
print(progtxt)
exit()
if args.name == "":
print ("Please specify a network interface.")
exit()
else:
dev_name = args.name
if len(dev_name) > IFNAMSIZ-1:
print ("NIC name too long")
exit()
print_interval = args.interval + 0.0
if print_interval == 0:
print ("print interval must be non-zero")
exit()
################ get number of queues #####################
tx_num = 0
rx_num = 0
path = ROOT_PATH + "/" + dev_name + "/queues"
if not os.path.exists(path):
print ("Net interface", dev_name, "does not exits.")
exit()
list = os.listdir(path)
for s in list:
if s[0] == 'r':
rx_num += 1
if s[0] == 't':
tx_num += 1
if tx_num > MAX_QUEUE_NUM or rx_num > MAX_QUEUE_NUM:
print ("number of queues over 1024 is not supported.")
exit()
################## start tracing ##################
b = BPF(src_file = EBPF_FILE)
# --------- set hash array --------
devname_map = b['name_map']
_name = Devname()
_name.name = dev_name.encode()
devname_map[0] = _name
while 1:
try:
sleep(print_interval)
print_result(b)
except KeyboardInterrupt:
exit()