Added detailed announce and path request traffic stats

This commit is contained in:
Mark Qvist 2026-08-21 13:06:48 +02:00
parent 7488336985
commit 5f2f4438d0
No known key found for this signature in database
9 changed files with 255 additions and 77 deletions

View file

@ -523,17 +523,25 @@ class BackboneInterface(Interface):
return True return True
def received_announce(self, from_spawned=False): def received_announce(self, size=0, from_spawned=False):
if from_spawned: self.ia_freq_deque.append(time.time()) if from_spawned:
self.ia_freq_deque.append(time.time())
self.arxb += size
def sent_announce(self, from_spawned=False): def sent_announce(self, size=0, from_spawned=False):
if from_spawned: self.oa_freq_deque.append(time.time()) if from_spawned:
self.oa_freq_deque.append(time.time())
self.atxb += size
def received_path_request(self, from_spawned=False): def received_path_request(self, size=0, from_spawned=False):
if from_spawned: self.ip_freq_deque.append(time.time()) if from_spawned:
self.ip_freq_deque.append(time.time())
self.prxb += size
def sent_path_request(self, from_spawned=False): def sent_path_request(self, size=0, from_spawned=False):
if from_spawned: self.op_freq_deque.append(time.time()) if from_spawned:
self.op_freq_deque.append(time.time())
self.ptxb += size
def process_outgoing(self, data): def process_outgoing(self, data):
pass pass

View file

@ -871,17 +871,25 @@ class I2PInterface(Interface):
def process_outgoing(self, data): def process_outgoing(self, data):
pass pass
def received_announce(self, from_spawned=False): def received_announce(self, size=0, from_spawned=False):
if from_spawned: self.ia_freq_deque.append(time.time()) if from_spawned:
self.ia_freq_deque.append(time.time())
self.arxb += size
def sent_announce(self, from_spawned=False): def sent_announce(self, size=0, from_spawned=False):
if from_spawned: self.oa_freq_deque.append(time.time()) if from_spawned:
self.oa_freq_deque.append(time.time())
self.atxb += size
def received_path_request(self, from_spawned=False): def received_path_request(self, size=0, from_spawned=False):
if from_spawned: self.ip_freq_deque.append(time.time()) if from_spawned:
self.ip_freq_deque.append(time.time())
self.prxb += size
def sent_path_request(self, from_spawned=False): def sent_path_request(self, size=0, from_spawned=False):
if from_spawned: self.op_freq_deque.append(time.time()) if from_spawned:
self.op_freq_deque.append(time.time())
self.ptxb += size
def detach(self): def detach(self):
RNS.log("Detaching "+str(self), RNS.LOG_DEBUG) RNS.log("Detaching "+str(self), RNS.LOG_DEBUG)

View file

@ -97,6 +97,10 @@ class Interface:
def __init__(self): def __init__(self):
self.rxb = 0 self.rxb = 0
self.txb = 0 self.txb = 0
self.arxb = 0
self.atxb = 0
self.prxb = 0
self.ptxb = 0
self.gravity = 0 self.gravity = 0
self.created = time.time() self.created = time.time()
self.detached = False self.detached = False
@ -258,25 +262,29 @@ class Interface:
RNS.log("An error occurred while processing held announces for "+str(self), RNS.LOG_ERROR) RNS.log("An error occurred while processing held announces for "+str(self), RNS.LOG_ERROR)
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
def received_announce(self, from_spawned=False): def received_announce(self, size=0, from_spawned=False):
self.arxb += size
self.ia_freq_deque.append(time.time()) self.ia_freq_deque.append(time.time())
if hasattr(self, "parent_interface") and self.parent_interface != None: if hasattr(self, "parent_interface") and self.parent_interface != None:
self.parent_interface.received_announce(from_spawned=True) self.parent_interface.received_announce(size=size, from_spawned=True)
def sent_announce(self, from_spawned=False): def sent_announce(self, size=0, from_spawned=False):
self.atxb += size
self.oa_freq_deque.append(time.time()) self.oa_freq_deque.append(time.time())
if hasattr(self, "parent_interface") and self.parent_interface != None: if hasattr(self, "parent_interface") and self.parent_interface != None:
self.parent_interface.sent_announce(from_spawned=True) self.parent_interface.sent_announce(size=size, from_spawned=True)
def received_path_request(self, from_spawned=False): def received_path_request(self, size=0, from_spawned=False):
self.prxb += size
self.ip_freq_deque.append(time.time()) self.ip_freq_deque.append(time.time())
if hasattr(self, "parent_interface") and self.parent_interface != None: if hasattr(self, "parent_interface") and self.parent_interface != None:
self.parent_interface.received_path_request(from_spawned=True) self.parent_interface.received_path_request(size=size, from_spawned=True)
def sent_path_request(self, from_spawned=False): def sent_path_request(self, size=0, from_spawned=False):
self.ptxb += size
self.op_freq_deque.append(time.time()) self.op_freq_deque.append(time.time())
if hasattr(self, "parent_interface") and self.parent_interface != None: if hasattr(self, "parent_interface") and self.parent_interface != None:
self.parent_interface.sent_path_request(from_spawned=True) self.parent_interface.sent_path_request(size=size, from_spawned=True)
@property @property
def ic_burst_count(self): return None def ic_burst_count(self): return None
@ -351,12 +359,13 @@ class Interface:
selected = entries[0] selected = entries[0]
now = time.time() now = time.time()
tx_time = (len(selected["raw"])*8) / self.bitrate tx_size = len(selected["raw"])
tx_time = (tx_size*8) / self.bitrate
wait_time = (tx_time / self.announce_cap) wait_time = (tx_time / self.announce_cap)
self.announce_allowed_at = now + wait_time self.announce_allowed_at = now + wait_time
self.process_outgoing(selected["raw"]) self.process_outgoing(selected["raw"])
self.sent_announce() self.sent_announce(tx_size)
if selected in self.announce_queue: if selected in self.announce_queue:
self.announce_queue.remove(selected) self.announce_queue.remove(selected)

View file

@ -481,17 +481,25 @@ class LocalServerInterface(Interface):
def process_outgoing(self, data): def process_outgoing(self, data):
pass pass
def received_announce(self, from_spawned=False): def received_announce(self, size=0, from_spawned=False):
if from_spawned: self.ia_freq_deque.append(time.time()) if from_spawned:
self.ia_freq_deque.append(time.time())
self.arxb += size
def sent_announce(self, from_spawned=False): def sent_announce(self, size=0, from_spawned=False):
if from_spawned: self.oa_freq_deque.append(time.time()) if from_spawned:
self.oa_freq_deque.append(time.time())
self.atxb += size
def received_path_request(self, from_spawned=False): def received_path_request(self, size=0, from_spawned=False):
if from_spawned: self.ip_freq_deque.append(time.time()) if from_spawned:
self.ip_freq_deque.append(time.time())
self.prxb += size
def sent_path_request(self, from_spawned=False): def sent_path_request(self, size=0, from_spawned=False):
if from_spawned: self.op_freq_deque.append(time.time()) if from_spawned:
self.op_freq_deque.append(time.time())
self.ptxb += size
def __str__(self): def __str__(self):
if self.socket_path: return "Shared Instance["+str(self.socket_path.replace("\0", ""))+"]" if self.socket_path: return "Shared Instance["+str(self.socket_path.replace("\0", ""))+"]"

View file

@ -543,17 +543,25 @@ class RNodeMultiInterface(Interface):
if written != len(frame): if written != len(frame):
raise IOError("Serial interface only wrote "+str(written)+" bytes of "+str(len(data))) raise IOError("Serial interface only wrote "+str(written)+" bytes of "+str(len(data)))
def received_announce(self, from_spawned=False): def received_announce(self, size=0, from_spawned=False):
if from_spawned: self.ia_freq_deque.append(time.time()) if from_spawned:
self.ia_freq_deque.append(time.time())
self.arxb += size
def sent_announce(self, from_spawned=False): def sent_announce(self, size=0, from_spawned=False):
if from_spawned: self.oa_freq_deque.append(time.time()) if from_spawned:
self.oa_freq_deque.append(time.time())
self.atxb += size
def received_path_request(self, from_spawned=False): def received_path_request(self, size=0, from_spawned=False):
if from_spawned: self.ip_freq_deque.append(time.time()) if from_spawned:
self.ip_freq_deque.append(time.time())
self.prxb += size
def sent_path_request(self, from_spawned=False): def sent_path_request(self, size=0, from_spawned=False):
if from_spawned: self.op_freq_deque.append(time.time()) if from_spawned:
self.op_freq_deque.append(time.time())
self.ptxb += size
def readLoop(self): def readLoop(self):
try: try:

View file

@ -646,17 +646,25 @@ class TCPServerInterface(Interface):
self.spawned_interfaces.append(spawned_interface) self.spawned_interfaces.append(spawned_interface)
spawned_interface.read_loop() spawned_interface.read_loop()
def received_announce(self, from_spawned=False): def received_announce(self, size=0, from_spawned=False):
if from_spawned: self.ia_freq_deque.append(time.time()) if from_spawned:
self.ia_freq_deque.append(time.time())
self.arxb += size
def sent_announce(self, from_spawned=False): def sent_announce(self, size=0, from_spawned=False):
if from_spawned: self.oa_freq_deque.append(time.time()) if from_spawned:
self.oa_freq_deque.append(time.time())
self.atxb += size
def received_path_request(self, from_spawned=False): def received_path_request(self, size=0, from_spawned=False):
if from_spawned: self.ip_freq_deque.append(time.time()) if from_spawned:
self.ip_freq_deque.append(time.time())
self.prxb += size
def sent_path_request(self, from_spawned=False): def sent_path_request(self, size=0, from_spawned=False):
if from_spawned: self.op_freq_deque.append(time.time()) if from_spawned:
self.op_freq_deque.append(time.time())
self.ptxb += size
def process_outgoing(self, data): def process_outgoing(self, data):
pass pass

View file

@ -1471,6 +1471,26 @@ class Reticulum:
else: ifstats["txs"] = 0 else: ifstats["txs"] = 0
else: ifstats["txs"] = 0 else: ifstats["txs"] = 0
if hasattr(interface, "current_arx_speed"):
if interface.current_arx_speed != None: ifstats["arxs"] = interface.current_arx_speed
else: ifstats["arxs"] = 0
else: ifstats["arxs"] = 0
if hasattr(interface, "current_atx_speed"):
if interface.current_atx_speed != None: ifstats["atxs"] = interface.current_atx_speed
else: ifstats["atxs"] = 0
else: ifstats["atxs"] = 0
if hasattr(interface, "current_prx_speed"):
if interface.current_prx_speed != None: ifstats["prxs"] = interface.current_prx_speed
else: ifstats["prxs"] = 0
else: ifstats["prxs"] = 0
if hasattr(interface, "current_ptx_speed"):
if interface.current_ptx_speed != None: ifstats["ptxs"] = interface.current_ptx_speed
else: ifstats["ptxs"] = 0
else: ifstats["ptxs"] = 0
if hasattr(interface, "peers"): if hasattr(interface, "peers"):
if interface.peers != None: ifstats["peers"] = len(interface.peers) if interface.peers != None: ifstats["peers"] = len(interface.peers)
else: ifstats["peers"] = None else: ifstats["peers"] = None
@ -1503,6 +1523,10 @@ class Reticulum:
ifstats["type"] = str(type(interface).__name__) ifstats["type"] = str(type(interface).__name__)
ifstats["rxb"] = interface.rxb ifstats["rxb"] = interface.rxb
ifstats["txb"] = interface.txb ifstats["txb"] = interface.txb
ifstats["arxb"] = interface.arxb
ifstats["atxb"] = interface.atxb
ifstats["prxb"] = interface.prxb
ifstats["ptxb"] = interface.ptxb
ifstats["incoming_announce_frequency"] = interface.incoming_announce_frequency() ifstats["incoming_announce_frequency"] = interface.incoming_announce_frequency()
ifstats["outgoing_announce_frequency"] = interface.outgoing_announce_frequency() ifstats["outgoing_announce_frequency"] = interface.outgoing_announce_frequency()
ifstats["incoming_pr_frequency"] = interface.incoming_pr_frequency() ifstats["incoming_pr_frequency"] = interface.incoming_pr_frequency()
@ -1537,6 +1561,14 @@ class Reticulum:
stats["txb"] = RNS.Transport.traffic_txb stats["txb"] = RNS.Transport.traffic_txb
stats["rxs"] = RNS.Transport.speed_rx stats["rxs"] = RNS.Transport.speed_rx
stats["txs"] = RNS.Transport.speed_tx stats["txs"] = RNS.Transport.speed_tx
stats["arxb"] = RNS.Transport.announce_rxb
stats["atxb"] = RNS.Transport.announce_txb
stats["arxs"] = RNS.Transport.announce_speed_rx
stats["atxs"] = RNS.Transport.announce_speed_tx
stats["prxb"] = RNS.Transport.pr_rxb
stats["ptxb"] = RNS.Transport.pr_txb
stats["prxs"] = RNS.Transport.pr_speed_rx
stats["ptxs"] = RNS.Transport.pr_speed_tx
stats["rxqt"] = qsnapshot[0] stats["rxqt"] = qsnapshot[0]
stats["rxqd"] = qsnapshot[1][0] stats["rxqd"] = qsnapshot[1][0]
stats["rxqa"] = qsnapshot[1][1] stats["rxqa"] = qsnapshot[1][1]

View file

@ -265,8 +265,16 @@ class Transport:
traffic_rxb = 0 traffic_rxb = 0
traffic_txb = 0 traffic_txb = 0
announce_rxb = 0
announce_txb = 0
pr_rxb = 0
pr_txb = 0
speed_rx = 0 speed_rx = 0
speed_tx = 0 speed_tx = 0
announce_speed_rx = 0
announce_speed_tx = 0
pr_speed_rx = 0
pr_speed_tx = 0
traffic_captured = None traffic_captured = None
lowest_interface_bitrate = None lowest_interface_bitrate = None
highest_interface_bitrate = None highest_interface_bitrate = None
@ -541,9 +549,9 @@ class Transport:
try: Transport.interfaces.sort(key=lambda interface: interface.bitrate, reverse=True) try: Transport.interfaces.sort(key=lambda interface: interface.bitrate, reverse=True)
except Exception as e: RNS.log(f"Could not prioritize interfaces according to bitrate. The contained exception was: {e}", RNS.LOG_ERROR) except Exception as e: RNS.log(f"Could not prioritize interfaces according to bitrate. The contained exception was: {e}", RNS.LOG_ERROR)
try: Transport.lowest_interface_bitrate = min((interface.bitrate for interface in Transport.interfaces if interface.online and interface.bitrate)) try: Transport.lowest_interface_bitrate = min((interface.bitrate for interface in Transport.interfaces if interface.online and interface.bitrate))
except Exception as e: RNS.log(f"Could not get lowest interface bitrate. The contained exception was: {e}", RNS.LOG_ERROR) except Exception as e: RNS.log(f"Could not get lowest interface bitrate. The contained exception was: {e}", RNS.LOG_DEBUG)
try: Transport.highest_interface_bitrate = max((interface.bitrate for interface in Transport.interfaces if interface.online and interface.bitrate)) try: Transport.highest_interface_bitrate = max((interface.bitrate for interface in Transport.interfaces if interface.online and interface.bitrate))
except Exception as e: RNS.log(f"Could not get highest interface bitrate. The contained exception was: {e}", RNS.LOG_ERROR) except Exception as e: RNS.log(f"Could not get highest interface bitrate. The contained exception was: {e}", RNS.LOG_DEBUG)
@staticmethod @staticmethod
def enable_discovery(): def enable_discovery():
@ -567,31 +575,62 @@ class Transport:
while True: while True:
time.sleep(1) time.sleep(1)
try: try:
rxb = 0; txb = 0; rxb = 0; txb = 0; rxs = 0; txs = 0;
rxs = 0; txs = 0; arxb = 0; atxb = 0; arxs = 0; atxs = 0;
prxb = 0; ptxb = 0; prxs = 0; ptxs = 0;
for interface in Transport.interfaces: for interface in Transport.interfaces:
if not hasattr(interface, "parent_interface") or interface.parent_interface == None: if not hasattr(interface, "parent_interface") or interface.parent_interface == None:
if hasattr(interface, "transport_traffic_counter"): if hasattr(interface, "transport_traffic_counter"):
now = time.time(); irxb = interface.rxb; itxb = interface.txb now = time.time()
irxb = interface.rxb; itxb = interface.txb
iarxb = interface.arxb; iatxb = interface.atxb
iprxb = interface.prxb; iptxb = interface.ptxb
tc = interface.transport_traffic_counter tc = interface.transport_traffic_counter
rx_diff = irxb - tc["rxb"]
tx_diff = itxb - tc["txb"]
ts_diff = now - tc["ts"] ts_diff = now - tc["ts"]
rxb += rx_diff; crxs = (rx_diff*8)/ts_diff
txb += tx_diff; ctxs = (tx_diff*8)/ts_diff rx_diff = irxb - tc["rxb"]; tx_diff = itxb - tc["txb"]
interface.current_rx_speed = crxs; rxs += crxs arx_diff = iarxb - tc["arxb"]; atx_diff = iatxb - tc["atxb"]
interface.current_tx_speed = ctxs; txs += ctxs prx_diff = iprxb - tc["prxb"]; ptx_diff = iptxb - tc["ptxb"]
tc["rxb"] = irxb;
tc["txb"] = itxb; rxb += rx_diff; crxs = (rx_diff*8)/ts_diff
tc["ts"] = now; txb += tx_diff; ctxs = (tx_diff*8)/ts_diff
arxb += arx_diff; carxs = (arx_diff*8)/ts_diff
atxb += atx_diff; catxs = (atx_diff*8)/ts_diff
prxb += prx_diff; cprxs = (prx_diff*8)/ts_diff
ptxb += ptx_diff; cptxs = (ptx_diff*8)/ts_diff
interface.current_rx_speed = crxs; rxs += crxs
interface.current_tx_speed = ctxs; txs += ctxs
interface.current_arx_speed = carxs; arxs += carxs
interface.current_atx_speed = catxs; atxs += catxs
interface.current_prx_speed = cprxs; prxs += cprxs
interface.current_ptx_speed = cptxs; ptxs += cptxs
tc["ts"] = now
tc["rxb"] = irxb; tc["txb"] = itxb
tc["arxb"] = iarxb; tc["atxb"] = iatxb
tc["prxb"] = iprxb; tc["ptxb"] = iptxb
else: else:
interface.transport_traffic_counter = {"ts": time.time(), "rxb": interface.rxb, "txb": interface.txb} interface.transport_traffic_counter = { "ts": time.time(), "rxb": interface.rxb, "txb": interface.txb,
"arxb": interface.arxb, "atxb": interface.atxb,
"prxb": interface.prxb, "ptxb": interface.ptxb }
Transport.traffic_rxb += rxb Transport.traffic_rxb += rxb
Transport.traffic_txb += txb Transport.traffic_txb += txb
Transport.speed_rx = rxs Transport.speed_rx = rxs
Transport.speed_tx = txs Transport.speed_tx = txs
Transport.announce_rxb += arxb
Transport.announce_txb += atxb
Transport.announce_speed_rx = arxs
Transport.announce_speed_tx = atxs
Transport.pr_rxb += prxb
Transport.pr_txb += ptxb
Transport.pr_speed_rx = prxs
Transport.pr_speed_tx = ptxs
except Exception as e: RNS.log(f"An error occurred while counting interface traffic: {e}", RNS.LOG_ERROR) except Exception as e: RNS.log(f"An error occurred while counting interface traffic: {e}", RNS.LOG_ERROR)
@ -1467,8 +1506,8 @@ class Transport:
else: raw = Transport.mangle_hops(packet.raw, Transport.local_hops_delta, transport_insert=packet.header_type==RNS.Packet.HEADER_1) else: raw = Transport.mangle_hops(packet.raw, Transport.local_hops_delta, transport_insert=packet.header_type==RNS.Packet.HEADER_1)
Transport.transmit(interface, raw) Transport.transmit(interface, raw)
if packet.packet_type == RNS.Packet.ANNOUNCE: interface.sent_announce() if packet.packet_type == RNS.Packet.ANNOUNCE: interface.sent_announce(size=len(raw))
if packet.destination.type == RNS.Destination.PLAIN and packet.is_outbound_pr: interface.sent_path_request() if packet.destination.type == RNS.Destination.PLAIN and packet.is_outbound_pr: interface.sent_path_request(size=len(raw))
packet_sent(packet) packet_sent(packet)
sent = True sent = True
@ -1626,7 +1665,7 @@ class Transport:
if not tc: traffic_class = Transport.TC_ANNOUNCE if not tc: traffic_class = Transport.TC_ANNOUNCE
announce_signature_valid = RNS.Identity.validate_announce(packet, only_validate_signature=True) announce_signature_valid = RNS.Identity.validate_announce(packet, only_validate_signature=True)
if not announce_signature_valid: return if not announce_signature_valid: return
elif packet.receiving_interface != None: packet.receiving_interface.received_announce() elif packet.receiving_interface != None: packet.receiving_interface.received_announce(size=len(packet.raw))
announced_destination_known = packet.destination_hash in Transport.path_table announced_destination_known = packet.destination_hash in Transport.path_table
if not announced_destination_known: if not announced_destination_known:
@ -1670,7 +1709,7 @@ class Transport:
RNS.log("Ignoring duplicate path request for "+RNS.prettyhexrep(destination_hash)+" with tag "+RNS.prettyhexrep(unique_tag), RNS.LOG_EXTREME) if RNS.sl(RNS.LOG_EXTREME) else None RNS.log("Ignoring duplicate path request for "+RNS.prettyhexrep(destination_hash)+" with tag "+RNS.prettyhexrep(unique_tag), RNS.LOG_EXTREME) if RNS.sl(RNS.LOG_EXTREME) else None
return return
if packet.receiving_interface: packet.receiving_interface.received_path_request() if packet.receiving_interface: packet.receiving_interface.received_path_request(size=len(raw))
if interface.should_ingress_limit_pr(): if interface.should_ingress_limit_pr():
traffic_class = Transport.TC_INGRESS_LIMITED traffic_class = Transport.TC_INGRESS_LIMITED

View file

@ -603,8 +603,16 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
cspec = "c" cspec = "c"
if clients == None and "peers" in ifstat and ifstat["peers"]: clients = ifstat["peers"]; cspec = "p" if clients == None and "peers" in ifstat and ifstat["peers"]: clients = ifstat["peers"]; cspec = "p"
if clients != None and clients > 0: pc_str = f"{RNS.prettyfrequency(ifstat['outgoing_announce_frequency']/clients, d=1, lpf=True)}/{cspec}" if clients != None and clients > 0: pc_str = f" {RNS.prettyfrequency(ifstat['outgoing_announce_frequency']/clients, d=1, lpf=True)}/{cspec}"
else: pc_str = "" else: pc_str = ""
if "prxs" in ifstat and "rxs" in ifstat and "ptxs" in ifstat and "txs" in ifstat:
arxspct = min(100.0, (ifstat["arxs"] / ifstat["rxs"])*100.0) if ifstat["rxs"] and ifstat["arxs"] else 0.0
atxspct = min(100.0, (ifstat["atxs"] / ifstat["txs"])*100.0) if ifstat["txs"] and ifstat["atxs"] else 0.0
apctstr = f"(↓{int(arxspct)}% / ↑{int(atxspct)}% of flow)"
if pc_str: pc_str = f"{pc_str} {apctstr}"
else: pc_str = f"{apctstr}"
asr = True asr = True
psr = False psr = False
@ -620,8 +628,16 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
ipf = RNS.prettyfrequency(ipn,d=1, lpf=True)+"↓" ipf = RNS.prettyfrequency(ipn,d=1, lpf=True)+"↓"
cspec = "c" cspec = "c"
if clients == None and "peers" in ifstat and ifstat["peers"]: clients = ifstat["peers"]; cspec = "p" if clients == None and "peers" in ifstat and ifstat["peers"]: clients = ifstat["peers"]; cspec = "p"
if clients != None and clients > 0: rpc_str = f"{RNS.prettyfrequency(ifstat['outgoing_pr_frequency']/clients, d=1, lpf=True)}/{cspec}" if clients != None and clients > 0: rpc_str = f" {RNS.prettyfrequency(ifstat['outgoing_pr_frequency']/clients, d=1, lpf=True)}/{cspec}"
else: rpc_str = "" else: rpc_str = ""
if "prxs" in ifstat and "rxs" in ifstat and "ptxs" in ifstat and "txs" in ifstat:
prxspct = min(100.0, (ifstat["prxs"] / ifstat["rxs"])*100.0) if ifstat["rxs"] and ifstat["prxs"] else 0.0
ptxspct = min(100.0, (ifstat["ptxs"] / ifstat["txs"])*100.0) if ifstat["txs"] and ifstat["ptxs"] else 0.0
ppctstr = f"(↓{int(prxspct)}% / ↑{int(ptxspct)}% of flow)"
if rpc_str: rpc_str = f"{rpc_str} {ppctstr}"
else: rpc_str = f"{ppctstr}"
psr = True psr = True
if not asr: iaf = ""; oaf = "" if not asr: iaf = ""; oaf = ""
@ -638,11 +654,11 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
txb_str += (mlen-len(txb_str))*" " txb_str += (mlen-len(txb_str))*" "
if psr: if psr:
print(f" Path Rqs. : {opf} {rpc_str}") print(f" Path Rqs. : {opf} {rpc_str}")
print(f" {ipf} {pburst_str}") print(f" {ipf} {pburst_str}")
if asr: if asr:
print(f" Announces : {oaf} {pc_str}") print(f" Announces : {oaf} {pc_str}")
print(f" {iaf} {art_str}{burst_str}") print(f" {iaf} {art_str}{burst_str}")
rxstat = rxb_str rxstat = rxb_str
@ -670,8 +686,50 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
rxstat = rxb_str+" "+RNS.prettyspeed(stats["rxs"]) rxstat = rxb_str+" "+RNS.prettyspeed(stats["rxs"])
txstat = txb_str+" "+RNS.prettyspeed(stats["txs"]) txstat = txb_str+" "+RNS.prettyspeed(stats["txs"])
if pstats or astats:
if "prxs" in stats and "ptxs" in stats and "arxs" in stats and "atxs" in stats:
parxs = stats["prxs"]+stats["arxs"]
patxs = stats["ptxs"]+stats["atxs"]
mrxpct = 100.0-min(100.0, (parxs / stats["rxs"])*100.0) if stats["rxs"] else 100.0
mtxpct = 100.0-min(100.0, (patxs / stats["txs"])*100.0) if stats["txs"] else 100.0
if stats["rxs"] > 0: rxstat = f"{rxstat}, {int(mrxpct)}% data"
if stats["txs"] > 0: txstat = f"{txstat}, {int(mtxpct)}% data"
print(f"\n Totals : {txstat}\n {rxstat}") print(f"\n Totals : {txstat}\n {rxstat}")
if pstats:
if "prxb" in stats and "ptxb" in stats and "prxs" in stats and "ptxs" in stats:
prxb_str = "↓"+RNS.prettysize(stats["prxb"])
ptxb_str = "↑"+RNS.prettysize(stats["ptxb"])
strdiff = len(prxb_str)-len(ptxb_str)
if strdiff > 0: ptxb_str += " "*strdiff
elif strdiff < 0: prxb_str += " "*-strdiff
prxspct = min(100.0, (stats["prxs"] / stats["rxs"])*100.0) if stats["rxs"] and stats["prxs"] else 0.0
ptxspct = min(100.0, (stats["ptxs"] / stats["txs"])*100.0) if stats["txs"] and stats["ptxs"] else 0.0
prxstat = prxb_str+" "+RNS.prettyspeed(stats["prxs"])+f", {int(prxspct)}% of flow"
ptxstat = ptxb_str+" "+RNS.prettyspeed(stats["ptxs"])+f", {int(ptxspct)}% of flow"
print(f"\n Path Reqs. : {ptxstat}\n {prxstat}")
if astats:
if "arxb" in stats and "atxb" in stats and "arxs" in stats and "atxs" in stats:
arxb_str = "↓"+RNS.prettysize(stats["arxb"])
atxb_str = "↑"+RNS.prettysize(stats["atxb"])
strdiff = len(arxb_str)-len(atxb_str)
if strdiff > 0: atxb_str += " "*strdiff
elif strdiff < 0: arxb_str += " "*-strdiff
arxspct = min(100.0, (stats["arxs"] / stats["rxs"])*100.0) if stats["rxs"] and stats["arxs"] else 0.0
atxspct = min(100.0, (stats["atxs"] / stats["txs"])*100.0) if stats["txs"] and stats["atxs"] else 0.0
arxstat = arxb_str+" "+RNS.prettyspeed(stats["arxs"])+f", {int(arxspct)}% of flow"
atxstat = atxb_str+" "+RNS.prettyspeed(stats["atxs"])+f", {int(atxspct)}% of flow"
print(f"\n Announces : {atxstat}\n {arxstat}")
if queue_stats: if queue_stats:
tqdp = f", {stats['rxqtd']} dropped" if stats['rxqtd'] else "" tqdp = f", {stats['rxqtd']} dropped" if stats['rxqtd'] else ""
dqdp = f", {stats['rxqdd']} dropped" if stats['rxqdd'] else "" dqdp = f", {stats['rxqdd']} dropped" if stats['rxqdd'] else ""