1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python 2*387f9dfdSAndroid Build Coastguard Worker# @lint-avoid-python-3-compatibility-imports 3*387f9dfdSAndroid Build Coastguard Worker# 4*387f9dfdSAndroid Build Coastguard Worker# tcprtt Summarize TCP RTT as a histogram. For Linux, uses BCC, eBPF. 5*387f9dfdSAndroid Build Coastguard Worker# 6*387f9dfdSAndroid Build Coastguard Worker# USAGE: tcprtt [-h] [-T] [-D] [-m] [-i INTERVAL] [-d DURATION] 7*387f9dfdSAndroid Build Coastguard Worker# [-p LPORT] [-P RPORT] [-a LADDR] [-A RADDR] [-b] [-B] [-e] 8*387f9dfdSAndroid Build Coastguard Worker# [-4 | -6] 9*387f9dfdSAndroid Build Coastguard Worker# 10*387f9dfdSAndroid Build Coastguard Worker# Copyright (c) 2020 zhenwei pi 11*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License") 12*387f9dfdSAndroid Build Coastguard Worker# 13*387f9dfdSAndroid Build Coastguard Worker# 23-AUG-2020 zhenwei pi Created this. 14*387f9dfdSAndroid Build Coastguard Worker 15*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 16*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF 17*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep, strftime 18*387f9dfdSAndroid Build Coastguard Workerfrom socket import inet_ntop, inet_pton, AF_INET, AF_INET6 19*387f9dfdSAndroid Build Coastguard Workerimport socket, struct 20*387f9dfdSAndroid Build Coastguard Workerimport argparse 21*387f9dfdSAndroid Build Coastguard Workerimport ctypes 22*387f9dfdSAndroid Build Coastguard Worker 23*387f9dfdSAndroid Build Coastguard Worker# arguments 24*387f9dfdSAndroid Build Coastguard Workerexamples = """examples: 25*387f9dfdSAndroid Build Coastguard Worker ./tcprtt # summarize TCP RTT 26*387f9dfdSAndroid Build Coastguard Worker ./tcprtt -i 1 -d 10 # print 1 second summaries, 10 times 27*387f9dfdSAndroid Build Coastguard Worker ./tcprtt -m -T # summarize in millisecond, and timestamps 28*387f9dfdSAndroid Build Coastguard Worker ./tcprtt -p # filter for local port 29*387f9dfdSAndroid Build Coastguard Worker ./tcprtt -P # filter for remote port 30*387f9dfdSAndroid Build Coastguard Worker ./tcprtt -a # filter for local address 31*387f9dfdSAndroid Build Coastguard Worker ./tcprtt -A # filter for remote address 32*387f9dfdSAndroid Build Coastguard Worker ./tcprtt -b # show sockets histogram by local address 33*387f9dfdSAndroid Build Coastguard Worker ./tcprtt -B # show sockets histogram by remote address 34*387f9dfdSAndroid Build Coastguard Worker ./tcprtt -D # show debug bpf text 35*387f9dfdSAndroid Build Coastguard Worker ./tcprtt -e # show extension summary(average) 36*387f9dfdSAndroid Build Coastguard Worker ./tcprtt -4 # trace only IPv4 family 37*387f9dfdSAndroid Build Coastguard Worker ./tcprtt -6 # trace only IPv6 family 38*387f9dfdSAndroid Build Coastguard Worker""" 39*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser( 40*387f9dfdSAndroid Build Coastguard Worker description="Summarize TCP RTT as a histogram", 41*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 42*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 43*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-i", "--interval", 44*387f9dfdSAndroid Build Coastguard Worker help="summary interval, seconds") 45*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-d", "--duration", type=int, default=99999, 46*387f9dfdSAndroid Build Coastguard Worker help="total duration of trace, seconds") 47*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-T", "--timestamp", action="store_true", 48*387f9dfdSAndroid Build Coastguard Worker help="include timestamp on output") 49*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-m", "--milliseconds", action="store_true", 50*387f9dfdSAndroid Build Coastguard Worker help="millisecond histogram") 51*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--lport", 52*387f9dfdSAndroid Build Coastguard Worker help="filter for local port") 53*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-P", "--rport", 54*387f9dfdSAndroid Build Coastguard Worker help="filter for remote port") 55*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-a", "--laddr", 56*387f9dfdSAndroid Build Coastguard Worker help="filter for local address") 57*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-A", "--raddr", 58*387f9dfdSAndroid Build Coastguard Worker help="filter for remote address") 59*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-b", "--byladdr", action="store_true", 60*387f9dfdSAndroid Build Coastguard Worker help="show sockets histogram by local address") 61*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-B", "--byraddr", action="store_true", 62*387f9dfdSAndroid Build Coastguard Worker help="show sockets histogram by remote address") 63*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-e", "--extension", action="store_true", 64*387f9dfdSAndroid Build Coastguard Worker help="show extension summary(average)") 65*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-D", "--debug", action="store_true", 66*387f9dfdSAndroid Build Coastguard Worker help="print BPF program before starting (for debugging purposes)") 67*387f9dfdSAndroid Build Coastguard Workergroup = parser.add_mutually_exclusive_group() 68*387f9dfdSAndroid Build Coastguard Workergroup.add_argument("-4", "--ipv4", action="store_true", 69*387f9dfdSAndroid Build Coastguard Worker help="trace IPv4 family only") 70*387f9dfdSAndroid Build Coastguard Workergroup.add_argument("-6", "--ipv6", action="store_true", 71*387f9dfdSAndroid Build Coastguard Worker help="trace IPv6 family only") 72*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true", 73*387f9dfdSAndroid Build Coastguard Worker help=argparse.SUPPRESS) 74*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 75*387f9dfdSAndroid Build Coastguard Workerif not args.interval: 76*387f9dfdSAndroid Build Coastguard Worker args.interval = args.duration 77*387f9dfdSAndroid Build Coastguard Worker 78*387f9dfdSAndroid Build Coastguard Worker# define BPF program 79*387f9dfdSAndroid Build Coastguard Workerbpf_text = """ 80*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h> 81*387f9dfdSAndroid Build Coastguard Worker#include <linux/tcp.h> 82*387f9dfdSAndroid Build Coastguard Worker#include <net/sock.h> 83*387f9dfdSAndroid Build Coastguard Worker#include <net/inet_sock.h> 84*387f9dfdSAndroid Build Coastguard Worker#include <bcc/proto.h> 85*387f9dfdSAndroid Build Coastguard Worker 86*387f9dfdSAndroid Build Coastguard Workertypedef struct sock_key { 87*387f9dfdSAndroid Build Coastguard Worker u64 addr; 88*387f9dfdSAndroid Build Coastguard Worker u64 slot; 89*387f9dfdSAndroid Build Coastguard Worker} sock_key_t; 90*387f9dfdSAndroid Build Coastguard Worker 91*387f9dfdSAndroid Build Coastguard Workertypedef struct sock_latenty { 92*387f9dfdSAndroid Build Coastguard Worker u64 latency; 93*387f9dfdSAndroid Build Coastguard Worker u64 count; 94*387f9dfdSAndroid Build Coastguard Worker} sock_latency_t; 95*387f9dfdSAndroid Build Coastguard Worker 96*387f9dfdSAndroid Build Coastguard WorkerBPF_HISTOGRAM(hist_srtt, sock_key_t); 97*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(latency, u64, sock_latency_t); 98*387f9dfdSAndroid Build Coastguard Worker 99*387f9dfdSAndroid Build Coastguard Workerint trace_tcp_rcv(struct pt_regs *ctx, struct sock *sk, struct sk_buff *skb) 100*387f9dfdSAndroid Build Coastguard Worker{ 101*387f9dfdSAndroid Build Coastguard Worker struct tcp_sock *ts = (struct tcp_sock *)sk; 102*387f9dfdSAndroid Build Coastguard Worker u32 srtt = ts->srtt_us >> 3; 103*387f9dfdSAndroid Build Coastguard Worker const struct inet_sock *inet = (struct inet_sock *)sk; 104*387f9dfdSAndroid Build Coastguard Worker 105*387f9dfdSAndroid Build Coastguard Worker /* filters */ 106*387f9dfdSAndroid Build Coastguard Worker u16 sport = 0; 107*387f9dfdSAndroid Build Coastguard Worker u16 dport = 0; 108*387f9dfdSAndroid Build Coastguard Worker u32 saddr = 0; 109*387f9dfdSAndroid Build Coastguard Worker u32 daddr = 0; 110*387f9dfdSAndroid Build Coastguard Worker __u8 saddr6[16]; 111*387f9dfdSAndroid Build Coastguard Worker __u8 daddr6[16]; 112*387f9dfdSAndroid Build Coastguard Worker u16 family = 0; 113*387f9dfdSAndroid Build Coastguard Worker 114*387f9dfdSAndroid Build Coastguard Worker /* for histogram */ 115*387f9dfdSAndroid Build Coastguard Worker sock_key_t key; 116*387f9dfdSAndroid Build Coastguard Worker 117*387f9dfdSAndroid Build Coastguard Worker /* for avg latency, if no saddr/daddr specified, use 0(addr) as key */ 118*387f9dfdSAndroid Build Coastguard Worker u64 addr = 0; 119*387f9dfdSAndroid Build Coastguard Worker 120*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&sport, sizeof(sport), (void *)&inet->inet_sport); 121*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&dport, sizeof(dport), (void *)&inet->inet_dport); 122*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&family, sizeof(family), (void *)&sk->__sk_common.skc_family); 123*387f9dfdSAndroid Build Coastguard Worker if (family == AF_INET6) { 124*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&saddr6, sizeof(saddr6), 125*387f9dfdSAndroid Build Coastguard Worker (void *)&sk->__sk_common.skc_v6_rcv_saddr.s6_addr); 126*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&daddr6, sizeof(daddr6), 127*387f9dfdSAndroid Build Coastguard Worker (void *)&sk->__sk_common.skc_v6_daddr.s6_addr); 128*387f9dfdSAndroid Build Coastguard Worker } else { 129*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&saddr, sizeof(saddr), (void *)&inet->inet_saddr); 130*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&daddr, sizeof(daddr), (void *)&inet->inet_daddr); 131*387f9dfdSAndroid Build Coastguard Worker } 132*387f9dfdSAndroid Build Coastguard Worker 133*387f9dfdSAndroid Build Coastguard Worker LPORTFILTER 134*387f9dfdSAndroid Build Coastguard Worker RPORTFILTER 135*387f9dfdSAndroid Build Coastguard Worker LADDRFILTER 136*387f9dfdSAndroid Build Coastguard Worker RADDRFILTER 137*387f9dfdSAndroid Build Coastguard Worker FAMILYFILTER 138*387f9dfdSAndroid Build Coastguard Worker 139*387f9dfdSAndroid Build Coastguard Worker FACTOR 140*387f9dfdSAndroid Build Coastguard Worker 141*387f9dfdSAndroid Build Coastguard Worker STORE_HIST 142*387f9dfdSAndroid Build Coastguard Worker key.slot = bpf_log2l(srtt); 143*387f9dfdSAndroid Build Coastguard Worker hist_srtt.atomic_increment(key); 144*387f9dfdSAndroid Build Coastguard Worker 145*387f9dfdSAndroid Build Coastguard Worker STORE_LATENCY 146*387f9dfdSAndroid Build Coastguard Worker 147*387f9dfdSAndroid Build Coastguard Worker return 0; 148*387f9dfdSAndroid Build Coastguard Worker} 149*387f9dfdSAndroid Build Coastguard Worker""" 150*387f9dfdSAndroid Build Coastguard Worker 151*387f9dfdSAndroid Build Coastguard Worker# filter for local port 152*387f9dfdSAndroid Build Coastguard Workerif args.lport: 153*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('LPORTFILTER', 154*387f9dfdSAndroid Build Coastguard Worker """if (ntohs(sport) != %d) 155*387f9dfdSAndroid Build Coastguard Worker return 0;""" % int(args.lport)) 156*387f9dfdSAndroid Build Coastguard Workerelse: 157*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('LPORTFILTER', '') 158*387f9dfdSAndroid Build Coastguard Worker 159*387f9dfdSAndroid Build Coastguard Worker# filter for remote port 160*387f9dfdSAndroid Build Coastguard Workerif args.rport: 161*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('RPORTFILTER', 162*387f9dfdSAndroid Build Coastguard Worker """if (ntohs(dport) != %d) 163*387f9dfdSAndroid Build Coastguard Worker return 0;""" % int(args.rport)) 164*387f9dfdSAndroid Build Coastguard Workerelse: 165*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('RPORTFILTER', '') 166*387f9dfdSAndroid Build Coastguard Worker 167*387f9dfdSAndroid Build Coastguard Workerdef addrfilter(addr, src_or_dest): 168*387f9dfdSAndroid Build Coastguard Worker try: 169*387f9dfdSAndroid Build Coastguard Worker naddr = socket.inet_pton(AF_INET, addr) 170*387f9dfdSAndroid Build Coastguard Worker except: 171*387f9dfdSAndroid Build Coastguard Worker naddr = socket.inet_pton(AF_INET6, addr) 172*387f9dfdSAndroid Build Coastguard Worker s = ('\\' + struct.unpack("=16s", naddr)[0].hex('\\')).replace('\\', '\\x') 173*387f9dfdSAndroid Build Coastguard Worker filter = "if (memcmp(%s6, \"%s\", 16)) return 0;" % (src_or_dest, s) 174*387f9dfdSAndroid Build Coastguard Worker else: 175*387f9dfdSAndroid Build Coastguard Worker filter = "if (%s != %d) return 0;" % (src_or_dest, struct.unpack("=I", naddr)[0]) 176*387f9dfdSAndroid Build Coastguard Worker return filter 177*387f9dfdSAndroid Build Coastguard Worker 178*387f9dfdSAndroid Build Coastguard Worker# filter for local address 179*387f9dfdSAndroid Build Coastguard Workerif args.laddr: 180*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('LADDRFILTER', addrfilter(args.laddr, 'saddr')) 181*387f9dfdSAndroid Build Coastguard Workerelse: 182*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('LADDRFILTER', '') 183*387f9dfdSAndroid Build Coastguard Worker 184*387f9dfdSAndroid Build Coastguard Worker# filter for remote address 185*387f9dfdSAndroid Build Coastguard Workerif args.raddr: 186*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('RADDRFILTER', addrfilter(args.raddr, 'daddr')) 187*387f9dfdSAndroid Build Coastguard Workerelse: 188*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('RADDRFILTER', '') 189*387f9dfdSAndroid Build Coastguard Workerif args.ipv4: 190*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FAMILYFILTER', 191*387f9dfdSAndroid Build Coastguard Worker 'if (family != AF_INET) { return 0; }') 192*387f9dfdSAndroid Build Coastguard Workerelif args.ipv6: 193*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FAMILYFILTER', 194*387f9dfdSAndroid Build Coastguard Worker 'if (family != AF_INET6) { return 0; }') 195*387f9dfdSAndroid Build Coastguard Workerelse: 196*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FAMILYFILTER', '') 197*387f9dfdSAndroid Build Coastguard Worker# show msecs or usecs[default] 198*387f9dfdSAndroid Build Coastguard Workerif args.milliseconds: 199*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FACTOR', 'srtt /= 1000;') 200*387f9dfdSAndroid Build Coastguard Worker label = "msecs" 201*387f9dfdSAndroid Build Coastguard Workerelse: 202*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FACTOR', '') 203*387f9dfdSAndroid Build Coastguard Worker label = "usecs" 204*387f9dfdSAndroid Build Coastguard Worker 205*387f9dfdSAndroid Build Coastguard Workerprint_header = "srtt" 206*387f9dfdSAndroid Build Coastguard Worker# show byladdr/byraddr histogram 207*387f9dfdSAndroid Build Coastguard Workerif args.byladdr: 208*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('STORE_HIST', 'key.addr = addr = saddr;') 209*387f9dfdSAndroid Build Coastguard Worker print_header = "Local Address" 210*387f9dfdSAndroid Build Coastguard Workerelif args.byraddr: 211*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('STORE_HIST', 'key.addr = addr = daddr;') 212*387f9dfdSAndroid Build Coastguard Worker print_header = "Remote Addres" 213*387f9dfdSAndroid Build Coastguard Workerelse: 214*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('STORE_HIST', 'key.addr = addr = 0;') 215*387f9dfdSAndroid Build Coastguard Worker print_header = "All Addresses" 216*387f9dfdSAndroid Build Coastguard Worker 217*387f9dfdSAndroid Build Coastguard Workerif args.extension: 218*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('STORE_LATENCY', """ 219*387f9dfdSAndroid Build Coastguard Worker sock_latency_t newlat = {0}; 220*387f9dfdSAndroid Build Coastguard Worker sock_latency_t *lat; 221*387f9dfdSAndroid Build Coastguard Worker lat = latency.lookup(&addr); 222*387f9dfdSAndroid Build Coastguard Worker if (!lat) { 223*387f9dfdSAndroid Build Coastguard Worker newlat.latency += srtt; 224*387f9dfdSAndroid Build Coastguard Worker newlat.count += 1; 225*387f9dfdSAndroid Build Coastguard Worker latency.update(&addr, &newlat); 226*387f9dfdSAndroid Build Coastguard Worker } else { 227*387f9dfdSAndroid Build Coastguard Worker lat->latency +=srtt; 228*387f9dfdSAndroid Build Coastguard Worker lat->count += 1; 229*387f9dfdSAndroid Build Coastguard Worker } 230*387f9dfdSAndroid Build Coastguard Worker """) 231*387f9dfdSAndroid Build Coastguard Workerelse: 232*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('STORE_LATENCY', '') 233*387f9dfdSAndroid Build Coastguard Worker 234*387f9dfdSAndroid Build Coastguard Worker# debug/dump ebpf enable or not 235*387f9dfdSAndroid Build Coastguard Workerif args.debug or args.ebpf: 236*387f9dfdSAndroid Build Coastguard Worker print(bpf_text) 237*387f9dfdSAndroid Build Coastguard Worker if args.ebpf: 238*387f9dfdSAndroid Build Coastguard Worker exit() 239*387f9dfdSAndroid Build Coastguard Worker 240*387f9dfdSAndroid Build Coastguard Worker# load BPF program 241*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text) 242*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="tcp_rcv_established", fn_name="trace_tcp_rcv") 243*387f9dfdSAndroid Build Coastguard Worker 244*387f9dfdSAndroid Build Coastguard Workerprint("Tracing TCP RTT... Hit Ctrl-C to end.") 245*387f9dfdSAndroid Build Coastguard Worker 246*387f9dfdSAndroid Build Coastguard Workerdef print_section(addr): 247*387f9dfdSAndroid Build Coastguard Worker addrstr = "*******" 248*387f9dfdSAndroid Build Coastguard Worker if (addr): 249*387f9dfdSAndroid Build Coastguard Worker addrstr = inet_ntop(AF_INET, struct.pack("I", addr)) 250*387f9dfdSAndroid Build Coastguard Worker 251*387f9dfdSAndroid Build Coastguard Worker avglat = "" 252*387f9dfdSAndroid Build Coastguard Worker if args.extension: 253*387f9dfdSAndroid Build Coastguard Worker lats = b.get_table("latency") 254*387f9dfdSAndroid Build Coastguard Worker lat = lats[ctypes.c_ulong(addr)] 255*387f9dfdSAndroid Build Coastguard Worker avglat = " [AVG %d]" % (lat.latency / lat.count) 256*387f9dfdSAndroid Build Coastguard Worker 257*387f9dfdSAndroid Build Coastguard Worker return addrstr + avglat 258*387f9dfdSAndroid Build Coastguard Worker 259*387f9dfdSAndroid Build Coastguard Worker# output 260*387f9dfdSAndroid Build Coastguard Workerexiting = 0 if args.interval else 1 261*387f9dfdSAndroid Build Coastguard Workerdist = b.get_table("hist_srtt") 262*387f9dfdSAndroid Build Coastguard Workerlathash = b.get_table("latency") 263*387f9dfdSAndroid Build Coastguard Workerseconds = 0 264*387f9dfdSAndroid Build Coastguard Workerwhile (1): 265*387f9dfdSAndroid Build Coastguard Worker try: 266*387f9dfdSAndroid Build Coastguard Worker sleep(int(args.interval)) 267*387f9dfdSAndroid Build Coastguard Worker seconds = seconds + int(args.interval) 268*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 269*387f9dfdSAndroid Build Coastguard Worker exiting = 1 270*387f9dfdSAndroid Build Coastguard Worker 271*387f9dfdSAndroid Build Coastguard Worker print() 272*387f9dfdSAndroid Build Coastguard Worker if args.timestamp: 273*387f9dfdSAndroid Build Coastguard Worker print("%-8s\n" % strftime("%H:%M:%S"), end="") 274*387f9dfdSAndroid Build Coastguard Worker 275*387f9dfdSAndroid Build Coastguard Worker dist.print_log2_hist(label, section_header=print_header, section_print_fn=print_section) 276*387f9dfdSAndroid Build Coastguard Worker dist.clear() 277*387f9dfdSAndroid Build Coastguard Worker lathash.clear() 278*387f9dfdSAndroid Build Coastguard Worker 279*387f9dfdSAndroid Build Coastguard Worker if exiting or seconds >= args.duration: 280*387f9dfdSAndroid Build Coastguard Worker exit() 281