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# virtiostat Show virtio devices input/output statistics. 5*387f9dfdSAndroid Build Coastguard Worker# For Linux, uses BCC, eBPF. 6*387f9dfdSAndroid Build Coastguard Worker# 7*387f9dfdSAndroid Build Coastguard Worker# USAGE: virtiostat [-h] [-T] [-D] [-d DRIVER] [-n DEVNAME] [INTERVAL] [COUNT] 8*387f9dfdSAndroid Build Coastguard Worker# 9*387f9dfdSAndroid Build Coastguard Worker# Copyright (c) 2021 zhenwei pi 10*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License") 11*387f9dfdSAndroid Build Coastguard Worker# 12*387f9dfdSAndroid Build Coastguard Worker# 13-Feb-2021 zhenwei pi Created this. 13*387f9dfdSAndroid Build Coastguard Worker 14*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 15*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF 16*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep, strftime 17*387f9dfdSAndroid Build Coastguard Workerimport argparse 18*387f9dfdSAndroid Build Coastguard Worker 19*387f9dfdSAndroid Build Coastguard Worker# arguments 20*387f9dfdSAndroid Build Coastguard Workerexamples = """examples: 21*387f9dfdSAndroid Build Coastguard Worker ./virtiostat # print 3(default) second summaries 22*387f9dfdSAndroid Build Coastguard Worker ./virtiostat 1 10 # print 1 second summaries, 10 times 23*387f9dfdSAndroid Build Coastguard Worker ./virtiostat -T # show timestamps 24*387f9dfdSAndroid Build Coastguard Worker ./virtiostat -d virtio_blk # only show virtio block devices 25*387f9dfdSAndroid Build Coastguard Worker ./virtiostat -n virtio0 # only show virtio0 device 26*387f9dfdSAndroid Build Coastguard Worker ./virtiostat -D # show debug bpf text 27*387f9dfdSAndroid Build Coastguard Worker""" 28*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser( 29*387f9dfdSAndroid Build Coastguard Worker description="Show virtio devices input/output statistics", 30*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 31*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 32*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("interval", nargs="?", default=3, 33*387f9dfdSAndroid Build Coastguard Worker help="output interval, in seconds") 34*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("count", nargs="?", default=99999999, 35*387f9dfdSAndroid Build Coastguard Worker help="number of outputs") 36*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-T", "--timestamp", action="store_true", 37*387f9dfdSAndroid Build Coastguard Worker help="show timestamp on output") 38*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-d", "--driver", 39*387f9dfdSAndroid Build Coastguard Worker help="filter for driver name") 40*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-n", "--devname", 41*387f9dfdSAndroid Build Coastguard Worker help="filter for device name") 42*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-D", "--debug", action="store_true", 43*387f9dfdSAndroid Build Coastguard Worker help="print BPF program before starting (for debugging purposes)") 44*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true", 45*387f9dfdSAndroid Build Coastguard Worker help=argparse.SUPPRESS) 46*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 47*387f9dfdSAndroid Build Coastguard Worker 48*387f9dfdSAndroid Build Coastguard Worker# define BPF program 49*387f9dfdSAndroid Build Coastguard Workerbpf_text = """ 50*387f9dfdSAndroid Build Coastguard Worker#include <linux/virtio.h> 51*387f9dfdSAndroid Build Coastguard Worker#include <bcc/proto.h> 52*387f9dfdSAndroid Build Coastguard Worker 53*387f9dfdSAndroid Build Coastguard Worker/* typically virtio scsi has max SGs of 6 */ 54*387f9dfdSAndroid Build Coastguard Worker#define VIRTIO_MAX_SGS 6 55*387f9dfdSAndroid Build Coastguard Worker/* typically virtio blk has max SEG of 128 */ 56*387f9dfdSAndroid Build Coastguard Worker#define SG_MAX 128 57*387f9dfdSAndroid Build Coastguard Worker 58*387f9dfdSAndroid Build Coastguard Worker/* local strcmp function, max length 16 to protect instruction loops */ 59*387f9dfdSAndroid Build Coastguard Worker#define CMPMAX 16 60*387f9dfdSAndroid Build Coastguard Worker 61*387f9dfdSAndroid Build Coastguard Workerstatic int local_strcmp(const char *cs, const char *ct) 62*387f9dfdSAndroid Build Coastguard Worker{ 63*387f9dfdSAndroid Build Coastguard Worker int len = 0; 64*387f9dfdSAndroid Build Coastguard Worker unsigned char c1, c2; 65*387f9dfdSAndroid Build Coastguard Worker 66*387f9dfdSAndroid Build Coastguard Worker while (len++ < CMPMAX) { 67*387f9dfdSAndroid Build Coastguard Worker c1 = *cs++; 68*387f9dfdSAndroid Build Coastguard Worker c2 = *ct++; 69*387f9dfdSAndroid Build Coastguard Worker if (c1 != c2) 70*387f9dfdSAndroid Build Coastguard Worker return c1 < c2 ? -1 : 1; 71*387f9dfdSAndroid Build Coastguard Worker if (!c1) 72*387f9dfdSAndroid Build Coastguard Worker break; 73*387f9dfdSAndroid Build Coastguard Worker } 74*387f9dfdSAndroid Build Coastguard Worker return 0; 75*387f9dfdSAndroid Build Coastguard Worker} 76*387f9dfdSAndroid Build Coastguard Worker 77*387f9dfdSAndroid Build Coastguard Workertypedef struct virtio_stat { 78*387f9dfdSAndroid Build Coastguard Worker char driver[16]; 79*387f9dfdSAndroid Build Coastguard Worker char dev[12]; 80*387f9dfdSAndroid Build Coastguard Worker char vqname[12]; 81*387f9dfdSAndroid Build Coastguard Worker u32 in_sgs; 82*387f9dfdSAndroid Build Coastguard Worker u32 out_sgs; 83*387f9dfdSAndroid Build Coastguard Worker u64 in_bw; 84*387f9dfdSAndroid Build Coastguard Worker u64 out_bw; 85*387f9dfdSAndroid Build Coastguard Worker} virtio_stat_t; 86*387f9dfdSAndroid Build Coastguard Worker 87*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(stats, u64, virtio_stat_t); 88*387f9dfdSAndroid Build Coastguard Worker 89*387f9dfdSAndroid Build Coastguard Workerstatic struct scatterlist *__sg_next(struct scatterlist *sgp) 90*387f9dfdSAndroid Build Coastguard Worker{ 91*387f9dfdSAndroid Build Coastguard Worker struct scatterlist sg; 92*387f9dfdSAndroid Build Coastguard Worker 93*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&sg, sizeof(sg), sgp); 94*387f9dfdSAndroid Build Coastguard Worker if (sg_is_last(&sg)) 95*387f9dfdSAndroid Build Coastguard Worker return NULL; 96*387f9dfdSAndroid Build Coastguard Worker 97*387f9dfdSAndroid Build Coastguard Worker sgp++; 98*387f9dfdSAndroid Build Coastguard Worker 99*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&sg, sizeof(sg), sgp); 100*387f9dfdSAndroid Build Coastguard Worker if (unlikely(sg_is_chain(&sg))) 101*387f9dfdSAndroid Build Coastguard Worker sgp = sg_chain_ptr(&sg); 102*387f9dfdSAndroid Build Coastguard Worker 103*387f9dfdSAndroid Build Coastguard Worker return sgp; 104*387f9dfdSAndroid Build Coastguard Worker} 105*387f9dfdSAndroid Build Coastguard Worker 106*387f9dfdSAndroid Build Coastguard Workerstatic u64 count_len(struct scatterlist **sgs, unsigned int num) 107*387f9dfdSAndroid Build Coastguard Worker{ 108*387f9dfdSAndroid Build Coastguard Worker u64 length = 0; 109*387f9dfdSAndroid Build Coastguard Worker unsigned int i, n; 110*387f9dfdSAndroid Build Coastguard Worker struct scatterlist *sgp = NULL; 111*387f9dfdSAndroid Build Coastguard Worker 112*387f9dfdSAndroid Build Coastguard Worker for (i = 0; (i < VIRTIO_MAX_SGS) && (i < num); i++) { 113*387f9dfdSAndroid Build Coastguard Worker for (n = 0, sgp = sgs[i]; sgp && (n < SG_MAX); sgp = __sg_next(sgp)) { 114*387f9dfdSAndroid Build Coastguard Worker length += sgp->length; 115*387f9dfdSAndroid Build Coastguard Worker n++; 116*387f9dfdSAndroid Build Coastguard Worker } 117*387f9dfdSAndroid Build Coastguard Worker 118*387f9dfdSAndroid Build Coastguard Worker /* Suggested by Yonghong Song: 119*387f9dfdSAndroid Build Coastguard Worker * IndVarSimplifyPass with clang 12 may cause verifier failure: 120*387f9dfdSAndroid Build Coastguard Worker * ; for (i = 0; (i < VIRTIO_MAX_SGS) && (i < num); i++) { // Line 60 121*387f9dfdSAndroid Build Coastguard Worker * 90: 15 08 15 00 00 00 00 00 if r8 == 0 goto +21 122*387f9dfdSAndroid Build Coastguard Worker * 91: bf 81 00 00 00 00 00 00 r1 = r8 123*387f9dfdSAndroid Build Coastguard Worker * 92: 07 01 00 00 ff ff ff ff r1 += -1 124*387f9dfdSAndroid Build Coastguard Worker * 93: 67 01 00 00 20 00 00 00 r1 <<= 32 125*387f9dfdSAndroid Build Coastguard Worker * 94: 77 01 00 00 20 00 00 00 r1 >>= 32 126*387f9dfdSAndroid Build Coastguard Worker * 95: b7 02 00 00 05 00 00 00 r2 = 5 127*387f9dfdSAndroid Build Coastguard Worker * 96: 2d 12 01 00 00 00 00 00 if r2 > r1 goto +1 128*387f9dfdSAndroid Build Coastguard Worker * 97: b7 08 00 00 06 00 00 00 r8 = 6 129*387f9dfdSAndroid Build Coastguard Worker * 98: b7 02 00 00 00 00 00 00 r2 = 0 130*387f9dfdSAndroid Build Coastguard Worker * 99: b7 09 00 00 00 00 00 00 r9 = 0 131*387f9dfdSAndroid Build Coastguard Worker * 100: 7b 8a 68 ff 00 00 00 00 *(u64 *)(r10 - 152) = r8 132*387f9dfdSAndroid Build Coastguard Worker * 101: 05 00 35 00 00 00 00 00 goto +53 133*387f9dfdSAndroid Build Coastguard Worker * Note that r1 is refined by r8 is saved to stack for later use. 134*387f9dfdSAndroid Build Coastguard Worker * This will give verifier u64_max loop bound and eventually cause 135*387f9dfdSAndroid Build Coastguard Worker * verification failure. Workaround with the below asm code. 136*387f9dfdSAndroid Build Coastguard Worker */ 137*387f9dfdSAndroid Build Coastguard Worker#if __clang_major__ >= 7 138*387f9dfdSAndroid Build Coastguard Worker asm volatile("" : "=r"(i) : "0"(i)); 139*387f9dfdSAndroid Build Coastguard Worker#endif 140*387f9dfdSAndroid Build Coastguard Worker } 141*387f9dfdSAndroid Build Coastguard Worker 142*387f9dfdSAndroid Build Coastguard Worker return length; 143*387f9dfdSAndroid Build Coastguard Worker} 144*387f9dfdSAndroid Build Coastguard Worker 145*387f9dfdSAndroid Build Coastguard Workerstatic void record(struct virtqueue *vq, struct scatterlist **sgs, 146*387f9dfdSAndroid Build Coastguard Worker unsigned int out_sgs, unsigned int in_sgs) 147*387f9dfdSAndroid Build Coastguard Worker{ 148*387f9dfdSAndroid Build Coastguard Worker virtio_stat_t newvs = {0}; 149*387f9dfdSAndroid Build Coastguard Worker virtio_stat_t *vs; 150*387f9dfdSAndroid Build Coastguard Worker u64 key = (u64)vq; 151*387f9dfdSAndroid Build Coastguard Worker u64 in_bw = 0; 152*387f9dfdSAndroid Build Coastguard Worker 153*387f9dfdSAndroid Build Coastguard Worker DRIVERFILTER 154*387f9dfdSAndroid Build Coastguard Worker DEVNAMEFILTER 155*387f9dfdSAndroid Build Coastguard Worker 156*387f9dfdSAndroid Build Coastguard Worker /* Workaround: separate two count_len() calls, one here and the 157*387f9dfdSAndroid Build Coastguard Worker * other below. Otherwise, compiler may generate some spills which 158*387f9dfdSAndroid Build Coastguard Worker * harms verifier pruning. This happens in llvm12, but not llvm4. 159*387f9dfdSAndroid Build Coastguard Worker * Below code works on both cases. 160*387f9dfdSAndroid Build Coastguard Worker */ 161*387f9dfdSAndroid Build Coastguard Worker if (in_sgs) 162*387f9dfdSAndroid Build Coastguard Worker in_bw = count_len(sgs + out_sgs, in_sgs); 163*387f9dfdSAndroid Build Coastguard Worker 164*387f9dfdSAndroid Build Coastguard Worker vs = stats.lookup(&key); 165*387f9dfdSAndroid Build Coastguard Worker if (!vs) { 166*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel_str(newvs.driver, sizeof(newvs.driver), vq->vdev->dev.driver->name); 167*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel_str(newvs.dev, sizeof(newvs.dev), vq->vdev->dev.kobj.name); 168*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel_str(newvs.vqname, sizeof(newvs.vqname), vq->name); 169*387f9dfdSAndroid Build Coastguard Worker newvs.out_sgs = out_sgs; 170*387f9dfdSAndroid Build Coastguard Worker newvs.in_sgs = in_sgs; 171*387f9dfdSAndroid Build Coastguard Worker if (out_sgs) 172*387f9dfdSAndroid Build Coastguard Worker newvs.out_bw = count_len(sgs, out_sgs); 173*387f9dfdSAndroid Build Coastguard Worker newvs.in_bw = in_bw; 174*387f9dfdSAndroid Build Coastguard Worker stats.update(&key, &newvs); 175*387f9dfdSAndroid Build Coastguard Worker } else { 176*387f9dfdSAndroid Build Coastguard Worker vs->out_sgs += out_sgs; 177*387f9dfdSAndroid Build Coastguard Worker vs->in_sgs += in_sgs; 178*387f9dfdSAndroid Build Coastguard Worker if (out_sgs) 179*387f9dfdSAndroid Build Coastguard Worker vs->out_bw += count_len(sgs, out_sgs); 180*387f9dfdSAndroid Build Coastguard Worker vs->in_bw += in_bw; 181*387f9dfdSAndroid Build Coastguard Worker } 182*387f9dfdSAndroid Build Coastguard Worker} 183*387f9dfdSAndroid Build Coastguard Worker 184*387f9dfdSAndroid Build Coastguard Workerint trace_virtqueue_add_sgs(struct pt_regs *ctx, struct virtqueue *vq, 185*387f9dfdSAndroid Build Coastguard Worker struct scatterlist **sgs, unsigned int out_sgs, 186*387f9dfdSAndroid Build Coastguard Worker unsigned int in_sgs, void *data, gfp_t gfp) 187*387f9dfdSAndroid Build Coastguard Worker 188*387f9dfdSAndroid Build Coastguard Worker{ 189*387f9dfdSAndroid Build Coastguard Worker record(vq, sgs, out_sgs, in_sgs); 190*387f9dfdSAndroid Build Coastguard Worker 191*387f9dfdSAndroid Build Coastguard Worker return 0; 192*387f9dfdSAndroid Build Coastguard Worker} 193*387f9dfdSAndroid Build Coastguard Worker 194*387f9dfdSAndroid Build Coastguard Workerint trace_virtqueue_add_outbuf(struct pt_regs *ctx, struct virtqueue *vq, 195*387f9dfdSAndroid Build Coastguard Worker struct scatterlist *sg, unsigned int num, 196*387f9dfdSAndroid Build Coastguard Worker void *data, gfp_t gfp) 197*387f9dfdSAndroid Build Coastguard Worker{ 198*387f9dfdSAndroid Build Coastguard Worker record(vq, &sg, 1, 0); 199*387f9dfdSAndroid Build Coastguard Worker 200*387f9dfdSAndroid Build Coastguard Worker return 0; 201*387f9dfdSAndroid Build Coastguard Worker} 202*387f9dfdSAndroid Build Coastguard Worker 203*387f9dfdSAndroid Build Coastguard Workerint trace_virtqueue_add_inbuf(struct pt_regs *ctx, struct virtqueue *vq, 204*387f9dfdSAndroid Build Coastguard Worker struct scatterlist *sg, unsigned int num, 205*387f9dfdSAndroid Build Coastguard Worker void *data, gfp_t gfp) 206*387f9dfdSAndroid Build Coastguard Worker{ 207*387f9dfdSAndroid Build Coastguard Worker record(vq, &sg, 0, 1); 208*387f9dfdSAndroid Build Coastguard Worker 209*387f9dfdSAndroid Build Coastguard Worker return 0; 210*387f9dfdSAndroid Build Coastguard Worker} 211*387f9dfdSAndroid Build Coastguard Worker 212*387f9dfdSAndroid Build Coastguard Workerint trace_virtqueue_add_inbuf_ctx(struct pt_regs *ctx, struct virtqueue *vq, 213*387f9dfdSAndroid Build Coastguard Worker struct scatterlist *sg, unsigned int num, 214*387f9dfdSAndroid Build Coastguard Worker void *data, void *_ctx, gfp_t gfp) 215*387f9dfdSAndroid Build Coastguard Worker{ 216*387f9dfdSAndroid Build Coastguard Worker record(vq, &sg, 0, 1); 217*387f9dfdSAndroid Build Coastguard Worker 218*387f9dfdSAndroid Build Coastguard Worker return 0; 219*387f9dfdSAndroid Build Coastguard Worker} 220*387f9dfdSAndroid Build Coastguard Worker""" 221*387f9dfdSAndroid Build Coastguard Worker 222*387f9dfdSAndroid Build Coastguard Worker# filter for driver name 223*387f9dfdSAndroid Build Coastguard Workerif args.driver: 224*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('DRIVERFILTER', 225*387f9dfdSAndroid Build Coastguard Worker """char filter_driver[] = \"%s\"; 226*387f9dfdSAndroid Build Coastguard Worker char driver[16]; 227*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel_str(driver, sizeof(driver), vq->vdev->dev.driver->name); 228*387f9dfdSAndroid Build Coastguard Worker if (local_strcmp(filter_driver, driver)) 229*387f9dfdSAndroid Build Coastguard Worker return;""" % (args.driver)) 230*387f9dfdSAndroid Build Coastguard Workerelse: 231*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('DRIVERFILTER', '') 232*387f9dfdSAndroid Build Coastguard Worker 233*387f9dfdSAndroid Build Coastguard Worker# filter for dev name 234*387f9dfdSAndroid Build Coastguard Workerif args.devname: 235*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('DEVNAMEFILTER', 236*387f9dfdSAndroid Build Coastguard Worker """char filter_devname[] = \"%s\"; 237*387f9dfdSAndroid Build Coastguard Worker char devname[16]; 238*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel_str(devname, sizeof(devname), vq->vdev->dev.kobj.name); 239*387f9dfdSAndroid Build Coastguard Worker if (local_strcmp(filter_devname, devname)) 240*387f9dfdSAndroid Build Coastguard Worker return;""" % (args.devname)) 241*387f9dfdSAndroid Build Coastguard Workerelse: 242*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('DEVNAMEFILTER', '') 243*387f9dfdSAndroid Build Coastguard Worker 244*387f9dfdSAndroid Build Coastguard Worker 245*387f9dfdSAndroid Build Coastguard Worker# debug mode: print bpf text 246*387f9dfdSAndroid Build Coastguard Workerif args.debug: 247*387f9dfdSAndroid Build Coastguard Worker print(bpf_text) 248*387f9dfdSAndroid Build Coastguard Worker 249*387f9dfdSAndroid Build Coastguard Worker# dump mode: print bpf text and exit 250*387f9dfdSAndroid Build Coastguard Workerif args.ebpf: 251*387f9dfdSAndroid Build Coastguard Worker print(bpf_text) 252*387f9dfdSAndroid Build Coastguard Worker exit() 253*387f9dfdSAndroid Build Coastguard Worker 254*387f9dfdSAndroid Build Coastguard Worker# load BPF program 255*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text) 256*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="virtqueue_add_sgs", fn_name="trace_virtqueue_add_sgs") 257*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="virtqueue_add_outbuf", fn_name="trace_virtqueue_add_outbuf") 258*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="virtqueue_add_inbuf", fn_name="trace_virtqueue_add_inbuf") 259*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="virtqueue_add_inbuf_ctx", fn_name="trace_virtqueue_add_inbuf_ctx") 260*387f9dfdSAndroid Build Coastguard Worker 261*387f9dfdSAndroid Build Coastguard Workerprint("Tracing virtio devices statistics ... Hit Ctrl-C to end.") 262*387f9dfdSAndroid Build Coastguard Worker 263*387f9dfdSAndroid Build Coastguard Worker# start main loop 264*387f9dfdSAndroid Build Coastguard Workerexiting = 0 if args.interval else 1 265*387f9dfdSAndroid Build Coastguard Workerseconds = 0 266*387f9dfdSAndroid Build Coastguard Workerwhile (1): 267*387f9dfdSAndroid Build Coastguard Worker try: 268*387f9dfdSAndroid Build Coastguard Worker sleep(int(args.interval)) 269*387f9dfdSAndroid Build Coastguard Worker seconds = seconds + int(args.interval) 270*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 271*387f9dfdSAndroid Build Coastguard Worker exiting = 1 272*387f9dfdSAndroid Build Coastguard Worker 273*387f9dfdSAndroid Build Coastguard Worker if args.timestamp: 274*387f9dfdSAndroid Build Coastguard Worker print("%-8s\n" % strftime("%H:%M:%S"), end="") 275*387f9dfdSAndroid Build Coastguard Worker else: 276*387f9dfdSAndroid Build Coastguard Worker print("--------", end="\n") 277*387f9dfdSAndroid Build Coastguard Worker 278*387f9dfdSAndroid Build Coastguard Worker print("%14s %8s %10s %7s %7s %14s %14s" % ("Driver", "Device", "VQ Name", "In SGs", "Out SGs", "In BW", "Out BW")) 279*387f9dfdSAndroid Build Coastguard Worker stats = b.get_table("stats") 280*387f9dfdSAndroid Build Coastguard Worker for k, v in sorted(stats.items(), key=lambda vs: vs[1].dev): 281*387f9dfdSAndroid Build Coastguard Worker print("%14s %8s %10s %7d %7d %14d %14d" % (v.driver, v.dev, v.vqname, v.in_sgs, v.out_sgs, v.in_bw, v.out_bw)) 282*387f9dfdSAndroid Build Coastguard Worker 283*387f9dfdSAndroid Build Coastguard Worker stats.clear() 284*387f9dfdSAndroid Build Coastguard Worker 285*387f9dfdSAndroid Build Coastguard Worker if exiting or seconds >= int(args.count): 286*387f9dfdSAndroid Build Coastguard Worker exit() 287