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# biosnoop Trace block device I/O and print details including issuing PID. 5*387f9dfdSAndroid Build Coastguard Worker# For Linux, uses BCC, eBPF. 6*387f9dfdSAndroid Build Coastguard Worker# 7*387f9dfdSAndroid Build Coastguard Worker# This uses in-kernel eBPF maps to cache process details (PID and comm) by I/O 8*387f9dfdSAndroid Build Coastguard Worker# request, as well as a starting timestamp for calculating I/O latency. 9*387f9dfdSAndroid Build Coastguard Worker# 10*387f9dfdSAndroid Build Coastguard Worker# Copyright (c) 2015 Brendan Gregg. 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# 16-Sep-2015 Brendan Gregg Created this. 14*387f9dfdSAndroid Build Coastguard Worker# 11-Feb-2016 Allan McAleavy updated for BPF_PERF_OUTPUT 15*387f9dfdSAndroid Build Coastguard Worker# 21-Jun-2022 Rocky Xing Added disk filter support. 16*387f9dfdSAndroid Build Coastguard Worker# 13-Oct-2022 Rocky Xing Added support for displaying block I/O pattern. 17*387f9dfdSAndroid Build Coastguard Worker# 01-Aug-2023 Jerome Marchand Added support for block tracepoints 18*387f9dfdSAndroid Build Coastguard Worker 19*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 20*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF 21*387f9dfdSAndroid Build Coastguard Workerimport argparse 22*387f9dfdSAndroid Build Coastguard Workerimport os 23*387f9dfdSAndroid Build Coastguard Worker 24*387f9dfdSAndroid Build Coastguard Worker# arguments 25*387f9dfdSAndroid Build Coastguard Workerexamples = """examples: 26*387f9dfdSAndroid Build Coastguard Worker ./biosnoop # trace all block I/O 27*387f9dfdSAndroid Build Coastguard Worker ./biosnoop -Q # include OS queued time 28*387f9dfdSAndroid Build Coastguard Worker ./biosnoop -d sdc # trace sdc only 29*387f9dfdSAndroid Build Coastguard Worker ./biosnoop -P # display block I/O pattern 30*387f9dfdSAndroid Build Coastguard Worker""" 31*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser( 32*387f9dfdSAndroid Build Coastguard Worker description="Trace block I/O", 33*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 34*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 35*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-Q", "--queue", action="store_true", 36*387f9dfdSAndroid Build Coastguard Worker help="include OS queued time") 37*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-d", "--disk", type=str, 38*387f9dfdSAndroid Build Coastguard Worker help="trace this disk only") 39*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-P", "--pattern", action="store_true", 40*387f9dfdSAndroid Build Coastguard Worker help="display block I/O pattern (sequential or random)") 41*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true", 42*387f9dfdSAndroid Build Coastguard Worker help=argparse.SUPPRESS) 43*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 44*387f9dfdSAndroid Build Coastguard Workerdebug = 0 45*387f9dfdSAndroid Build Coastguard Worker 46*387f9dfdSAndroid Build Coastguard Worker# define BPF program 47*387f9dfdSAndroid Build Coastguard Workerbpf_text = """ 48*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h> 49*387f9dfdSAndroid Build Coastguard Worker#include <linux/blk-mq.h> 50*387f9dfdSAndroid Build Coastguard Worker""" 51*387f9dfdSAndroid Build Coastguard Worker 52*387f9dfdSAndroid Build Coastguard Workerif args.pattern: 53*387f9dfdSAndroid Build Coastguard Worker bpf_text += "#define INCLUDE_PATTERN\n" 54*387f9dfdSAndroid Build Coastguard Worker 55*387f9dfdSAndroid Build Coastguard Workerbpf_text += """ 56*387f9dfdSAndroid Build Coastguard Worker// for saving the timestamp and __data_len of each request 57*387f9dfdSAndroid Build Coastguard Workerstruct start_req_t { 58*387f9dfdSAndroid Build Coastguard Worker u64 ts; 59*387f9dfdSAndroid Build Coastguard Worker u64 data_len; 60*387f9dfdSAndroid Build Coastguard Worker}; 61*387f9dfdSAndroid Build Coastguard Worker 62*387f9dfdSAndroid Build Coastguard Workerstruct val_t { 63*387f9dfdSAndroid Build Coastguard Worker u64 ts; 64*387f9dfdSAndroid Build Coastguard Worker u32 pid; 65*387f9dfdSAndroid Build Coastguard Worker char name[TASK_COMM_LEN]; 66*387f9dfdSAndroid Build Coastguard Worker}; 67*387f9dfdSAndroid Build Coastguard Worker 68*387f9dfdSAndroid Build Coastguard Workerstruct tp_args { 69*387f9dfdSAndroid Build Coastguard Worker u64 __unused__; 70*387f9dfdSAndroid Build Coastguard Worker dev_t dev; 71*387f9dfdSAndroid Build Coastguard Worker sector_t sector; 72*387f9dfdSAndroid Build Coastguard Worker unsigned int nr_sector; 73*387f9dfdSAndroid Build Coastguard Worker unsigned int bytes; 74*387f9dfdSAndroid Build Coastguard Worker char rwbs[8]; 75*387f9dfdSAndroid Build Coastguard Worker char comm[16]; 76*387f9dfdSAndroid Build Coastguard Worker char cmd[]; 77*387f9dfdSAndroid Build Coastguard Worker}; 78*387f9dfdSAndroid Build Coastguard Worker 79*387f9dfdSAndroid Build Coastguard Workerstruct hash_key { 80*387f9dfdSAndroid Build Coastguard Worker dev_t dev; 81*387f9dfdSAndroid Build Coastguard Worker u32 rwflag; 82*387f9dfdSAndroid Build Coastguard Worker sector_t sector; 83*387f9dfdSAndroid Build Coastguard Worker}; 84*387f9dfdSAndroid Build Coastguard Worker 85*387f9dfdSAndroid Build Coastguard Worker 86*387f9dfdSAndroid Build Coastguard Worker#ifdef INCLUDE_PATTERN 87*387f9dfdSAndroid Build Coastguard Workerstruct sector_key_t { 88*387f9dfdSAndroid Build Coastguard Worker u32 dev_major; 89*387f9dfdSAndroid Build Coastguard Worker u32 dev_minor; 90*387f9dfdSAndroid Build Coastguard Worker}; 91*387f9dfdSAndroid Build Coastguard Worker 92*387f9dfdSAndroid Build Coastguard Workerenum bio_pattern { 93*387f9dfdSAndroid Build Coastguard Worker UNKNOWN, 94*387f9dfdSAndroid Build Coastguard Worker SEQUENTIAL, 95*387f9dfdSAndroid Build Coastguard Worker RANDOM, 96*387f9dfdSAndroid Build Coastguard Worker}; 97*387f9dfdSAndroid Build Coastguard Worker#endif 98*387f9dfdSAndroid Build Coastguard Worker 99*387f9dfdSAndroid Build Coastguard Workerstruct data_t { 100*387f9dfdSAndroid Build Coastguard Worker u32 pid; 101*387f9dfdSAndroid Build Coastguard Worker u32 dev; 102*387f9dfdSAndroid Build Coastguard Worker u64 rwflag; 103*387f9dfdSAndroid Build Coastguard Worker u64 delta; 104*387f9dfdSAndroid Build Coastguard Worker u64 qdelta; 105*387f9dfdSAndroid Build Coastguard Worker u64 sector; 106*387f9dfdSAndroid Build Coastguard Worker u64 len; 107*387f9dfdSAndroid Build Coastguard Worker#ifdef INCLUDE_PATTERN 108*387f9dfdSAndroid Build Coastguard Worker enum bio_pattern pattern; 109*387f9dfdSAndroid Build Coastguard Worker#endif 110*387f9dfdSAndroid Build Coastguard Worker u64 ts; 111*387f9dfdSAndroid Build Coastguard Worker char name[TASK_COMM_LEN]; 112*387f9dfdSAndroid Build Coastguard Worker}; 113*387f9dfdSAndroid Build Coastguard Worker 114*387f9dfdSAndroid Build Coastguard Worker#ifdef INCLUDE_PATTERN 115*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(last_sectors, struct sector_key_t, u64); 116*387f9dfdSAndroid Build Coastguard Worker#endif 117*387f9dfdSAndroid Build Coastguard Worker 118*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(start, struct hash_key, struct start_req_t); 119*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(infobyreq, struct hash_key, struct val_t); 120*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(events); 121*387f9dfdSAndroid Build Coastguard Worker 122*387f9dfdSAndroid Build Coastguard Workerstatic dev_t ddevt(struct gendisk *disk) { 123*387f9dfdSAndroid Build Coastguard Worker return (disk->major << 20) | disk->first_minor; 124*387f9dfdSAndroid Build Coastguard Worker} 125*387f9dfdSAndroid Build Coastguard Worker 126*387f9dfdSAndroid Build Coastguard Worker/* 127*387f9dfdSAndroid Build Coastguard Worker * The following deals with a kernel version change (in mainline 4.7, although 128*387f9dfdSAndroid Build Coastguard Worker * it may be backported to earlier kernels) with how block request write flags 129*387f9dfdSAndroid Build Coastguard Worker * are tested. We handle both pre- and post-change versions here. Please avoid 130*387f9dfdSAndroid Build Coastguard Worker * kernel version tests like this as much as possible: they inflate the code, 131*387f9dfdSAndroid Build Coastguard Worker * test, and maintenance burden. 132*387f9dfdSAndroid Build Coastguard Worker */ 133*387f9dfdSAndroid Build Coastguard Workerstatic int get_rwflag(u32 cmd_flags) { 134*387f9dfdSAndroid Build Coastguard Worker#ifdef REQ_WRITE 135*387f9dfdSAndroid Build Coastguard Worker return !!(cmd_flags & REQ_WRITE); 136*387f9dfdSAndroid Build Coastguard Worker#elif defined(REQ_OP_SHIFT) 137*387f9dfdSAndroid Build Coastguard Worker return !!((cmd_flags >> REQ_OP_SHIFT) == REQ_OP_WRITE); 138*387f9dfdSAndroid Build Coastguard Worker#else 139*387f9dfdSAndroid Build Coastguard Worker return !!((cmd_flags & REQ_OP_MASK) == REQ_OP_WRITE); 140*387f9dfdSAndroid Build Coastguard Worker#endif 141*387f9dfdSAndroid Build Coastguard Worker} 142*387f9dfdSAndroid Build Coastguard Worker 143*387f9dfdSAndroid Build Coastguard Worker#define RWBS_LEN 8 144*387f9dfdSAndroid Build Coastguard Worker 145*387f9dfdSAndroid Build Coastguard Workerstatic int get_rwflag_tp(char *rwbs) { 146*387f9dfdSAndroid Build Coastguard Worker for (int i = 0; i < RWBS_LEN; i++) { 147*387f9dfdSAndroid Build Coastguard Worker if (rwbs[i] == 'W') 148*387f9dfdSAndroid Build Coastguard Worker return 1; 149*387f9dfdSAndroid Build Coastguard Worker if (rwbs[i] == '\\0') 150*387f9dfdSAndroid Build Coastguard Worker return 0; 151*387f9dfdSAndroid Build Coastguard Worker } 152*387f9dfdSAndroid Build Coastguard Worker return 0; 153*387f9dfdSAndroid Build Coastguard Worker} 154*387f9dfdSAndroid Build Coastguard Worker 155*387f9dfdSAndroid Build Coastguard Worker// cache PID and comm by-req 156*387f9dfdSAndroid Build Coastguard Workerstatic int __trace_pid_start(struct hash_key key) 157*387f9dfdSAndroid Build Coastguard Worker{ 158*387f9dfdSAndroid Build Coastguard Worker DISK_FILTER 159*387f9dfdSAndroid Build Coastguard Worker 160*387f9dfdSAndroid Build Coastguard Worker struct val_t val = {}; 161*387f9dfdSAndroid Build Coastguard Worker u64 ts; 162*387f9dfdSAndroid Build Coastguard Worker 163*387f9dfdSAndroid Build Coastguard Worker if (bpf_get_current_comm(&val.name, sizeof(val.name)) == 0) { 164*387f9dfdSAndroid Build Coastguard Worker val.pid = bpf_get_current_pid_tgid() >> 32; 165*387f9dfdSAndroid Build Coastguard Worker if (##QUEUE##) { 166*387f9dfdSAndroid Build Coastguard Worker val.ts = bpf_ktime_get_ns(); 167*387f9dfdSAndroid Build Coastguard Worker } 168*387f9dfdSAndroid Build Coastguard Worker infobyreq.update(&key, &val); 169*387f9dfdSAndroid Build Coastguard Worker } 170*387f9dfdSAndroid Build Coastguard Worker return 0; 171*387f9dfdSAndroid Build Coastguard Worker} 172*387f9dfdSAndroid Build Coastguard Worker 173*387f9dfdSAndroid Build Coastguard Worker 174*387f9dfdSAndroid Build Coastguard Workerint trace_pid_start(struct pt_regs *ctx, struct request *req) 175*387f9dfdSAndroid Build Coastguard Worker{ 176*387f9dfdSAndroid Build Coastguard Worker struct hash_key key = { 177*387f9dfdSAndroid Build Coastguard Worker .dev = ddevt(req->__RQ_DISK__), 178*387f9dfdSAndroid Build Coastguard Worker .rwflag = get_rwflag(req->cmd_flags), 179*387f9dfdSAndroid Build Coastguard Worker .sector = req->__sector 180*387f9dfdSAndroid Build Coastguard Worker }; 181*387f9dfdSAndroid Build Coastguard Worker 182*387f9dfdSAndroid Build Coastguard Worker return __trace_pid_start(key); 183*387f9dfdSAndroid Build Coastguard Worker} 184*387f9dfdSAndroid Build Coastguard Worker 185*387f9dfdSAndroid Build Coastguard Workerint trace_pid_start_tp(struct tp_args *args) 186*387f9dfdSAndroid Build Coastguard Worker{ 187*387f9dfdSAndroid Build Coastguard Worker struct hash_key key = { 188*387f9dfdSAndroid Build Coastguard Worker .dev = args->dev, 189*387f9dfdSAndroid Build Coastguard Worker .rwflag = get_rwflag_tp(args->rwbs), 190*387f9dfdSAndroid Build Coastguard Worker .sector = args->sector 191*387f9dfdSAndroid Build Coastguard Worker }; 192*387f9dfdSAndroid Build Coastguard Worker 193*387f9dfdSAndroid Build Coastguard Worker return __trace_pid_start(key); 194*387f9dfdSAndroid Build Coastguard Worker} 195*387f9dfdSAndroid Build Coastguard Worker 196*387f9dfdSAndroid Build Coastguard Worker// time block I/O 197*387f9dfdSAndroid Build Coastguard Workerint trace_req_start(struct pt_regs *ctx, struct request *req) 198*387f9dfdSAndroid Build Coastguard Worker{ 199*387f9dfdSAndroid Build Coastguard Worker struct hash_key key = { 200*387f9dfdSAndroid Build Coastguard Worker .dev = ddevt(req->__RQ_DISK__), 201*387f9dfdSAndroid Build Coastguard Worker .rwflag = get_rwflag(req->cmd_flags), 202*387f9dfdSAndroid Build Coastguard Worker .sector = req->__sector 203*387f9dfdSAndroid Build Coastguard Worker }; 204*387f9dfdSAndroid Build Coastguard Worker 205*387f9dfdSAndroid Build Coastguard Worker DISK_FILTER 206*387f9dfdSAndroid Build Coastguard Worker 207*387f9dfdSAndroid Build Coastguard Worker struct start_req_t start_req = { 208*387f9dfdSAndroid Build Coastguard Worker .ts = bpf_ktime_get_ns(), 209*387f9dfdSAndroid Build Coastguard Worker .data_len = req->__data_len 210*387f9dfdSAndroid Build Coastguard Worker }; 211*387f9dfdSAndroid Build Coastguard Worker start.update(&key, &start_req); 212*387f9dfdSAndroid Build Coastguard Worker return 0; 213*387f9dfdSAndroid Build Coastguard Worker} 214*387f9dfdSAndroid Build Coastguard Worker 215*387f9dfdSAndroid Build Coastguard Worker// output 216*387f9dfdSAndroid Build Coastguard Workerstatic int __trace_req_completion(void *ctx, struct hash_key key) 217*387f9dfdSAndroid Build Coastguard Worker{ 218*387f9dfdSAndroid Build Coastguard Worker struct start_req_t *startp; 219*387f9dfdSAndroid Build Coastguard Worker struct val_t *valp; 220*387f9dfdSAndroid Build Coastguard Worker struct data_t data = {}; 221*387f9dfdSAndroid Build Coastguard Worker //struct gendisk *rq_disk; 222*387f9dfdSAndroid Build Coastguard Worker u64 ts; 223*387f9dfdSAndroid Build Coastguard Worker 224*387f9dfdSAndroid Build Coastguard Worker // fetch timestamp and calculate delta 225*387f9dfdSAndroid Build Coastguard Worker startp = start.lookup(&key); 226*387f9dfdSAndroid Build Coastguard Worker if (startp == 0) { 227*387f9dfdSAndroid Build Coastguard Worker // missed tracing issue 228*387f9dfdSAndroid Build Coastguard Worker return 0; 229*387f9dfdSAndroid Build Coastguard Worker } 230*387f9dfdSAndroid Build Coastguard Worker ts = bpf_ktime_get_ns(); 231*387f9dfdSAndroid Build Coastguard Worker //rq_disk = req->__RQ_DISK__; 232*387f9dfdSAndroid Build Coastguard Worker data.delta = ts - startp->ts; 233*387f9dfdSAndroid Build Coastguard Worker data.ts = ts / 1000; 234*387f9dfdSAndroid Build Coastguard Worker data.qdelta = 0; 235*387f9dfdSAndroid Build Coastguard Worker data.len = startp->data_len; 236*387f9dfdSAndroid Build Coastguard Worker 237*387f9dfdSAndroid Build Coastguard Worker valp = infobyreq.lookup(&key); 238*387f9dfdSAndroid Build Coastguard Worker if (valp == 0) { 239*387f9dfdSAndroid Build Coastguard Worker data.name[0] = '?'; 240*387f9dfdSAndroid Build Coastguard Worker data.name[1] = 0; 241*387f9dfdSAndroid Build Coastguard Worker } else { 242*387f9dfdSAndroid Build Coastguard Worker if (##QUEUE##) { 243*387f9dfdSAndroid Build Coastguard Worker data.qdelta = startp->ts - valp->ts; 244*387f9dfdSAndroid Build Coastguard Worker } 245*387f9dfdSAndroid Build Coastguard Worker data.pid = valp->pid; 246*387f9dfdSAndroid Build Coastguard Worker data.sector = key.sector; 247*387f9dfdSAndroid Build Coastguard Worker data.dev = key.dev; 248*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&data.name, sizeof(data.name), valp->name); 249*387f9dfdSAndroid Build Coastguard Worker } 250*387f9dfdSAndroid Build Coastguard Worker 251*387f9dfdSAndroid Build Coastguard Worker#ifdef INCLUDE_PATTERN 252*387f9dfdSAndroid Build Coastguard Worker data.pattern = UNKNOWN; 253*387f9dfdSAndroid Build Coastguard Worker 254*387f9dfdSAndroid Build Coastguard Worker u64 *sector, last_sector; 255*387f9dfdSAndroid Build Coastguard Worker 256*387f9dfdSAndroid Build Coastguard Worker struct sector_key_t sector_key = { 257*387f9dfdSAndroid Build Coastguard Worker .dev_major = key.dev >> 20, 258*387f9dfdSAndroid Build Coastguard Worker .dev_minor = key.dev & ((1 << 20) - 1) 259*387f9dfdSAndroid Build Coastguard Worker }; 260*387f9dfdSAndroid Build Coastguard Worker 261*387f9dfdSAndroid Build Coastguard Worker sector = last_sectors.lookup(§or_key); 262*387f9dfdSAndroid Build Coastguard Worker if (sector != 0) { 263*387f9dfdSAndroid Build Coastguard Worker data.pattern = req->__sector == *sector ? SEQUENTIAL : RANDOM; 264*387f9dfdSAndroid Build Coastguard Worker } 265*387f9dfdSAndroid Build Coastguard Worker 266*387f9dfdSAndroid Build Coastguard Worker last_sector = req->__sector + data.len / 512; 267*387f9dfdSAndroid Build Coastguard Worker last_sectors.update(§or_key, &last_sector); 268*387f9dfdSAndroid Build Coastguard Worker#endif 269*387f9dfdSAndroid Build Coastguard Worker 270*387f9dfdSAndroid Build Coastguard Worker data.rwflag = key.rwflag; 271*387f9dfdSAndroid Build Coastguard Worker 272*387f9dfdSAndroid Build Coastguard Worker events.perf_submit(ctx, &data, sizeof(data)); 273*387f9dfdSAndroid Build Coastguard Worker start.delete(&key); 274*387f9dfdSAndroid Build Coastguard Worker infobyreq.delete(&key); 275*387f9dfdSAndroid Build Coastguard Worker 276*387f9dfdSAndroid Build Coastguard Worker return 0; 277*387f9dfdSAndroid Build Coastguard Worker} 278*387f9dfdSAndroid Build Coastguard Worker 279*387f9dfdSAndroid Build Coastguard Workerint trace_req_completion(struct pt_regs *ctx, struct request *req) 280*387f9dfdSAndroid Build Coastguard Worker{ 281*387f9dfdSAndroid Build Coastguard Worker struct hash_key key = { 282*387f9dfdSAndroid Build Coastguard Worker .dev = ddevt(req->__RQ_DISK__), 283*387f9dfdSAndroid Build Coastguard Worker .rwflag = get_rwflag(req->cmd_flags), 284*387f9dfdSAndroid Build Coastguard Worker .sector = req->__sector 285*387f9dfdSAndroid Build Coastguard Worker }; 286*387f9dfdSAndroid Build Coastguard Worker 287*387f9dfdSAndroid Build Coastguard Worker return __trace_req_completion(ctx, key); 288*387f9dfdSAndroid Build Coastguard Worker} 289*387f9dfdSAndroid Build Coastguard Worker 290*387f9dfdSAndroid Build Coastguard Workerint trace_req_completion_tp(struct tp_args *args) 291*387f9dfdSAndroid Build Coastguard Worker{ 292*387f9dfdSAndroid Build Coastguard Worker struct hash_key key = { 293*387f9dfdSAndroid Build Coastguard Worker .dev = args->dev, 294*387f9dfdSAndroid Build Coastguard Worker .rwflag = get_rwflag_tp(args->rwbs), 295*387f9dfdSAndroid Build Coastguard Worker .sector = args->sector 296*387f9dfdSAndroid Build Coastguard Worker }; 297*387f9dfdSAndroid Build Coastguard Worker 298*387f9dfdSAndroid Build Coastguard Worker return __trace_req_completion(args, key); 299*387f9dfdSAndroid Build Coastguard Worker} 300*387f9dfdSAndroid Build Coastguard Worker""" 301*387f9dfdSAndroid Build Coastguard Workerif args.queue: 302*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('##QUEUE##', '1') 303*387f9dfdSAndroid Build Coastguard Workerelse: 304*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('##QUEUE##', '0') 305*387f9dfdSAndroid Build Coastguard Workerif BPF.kernel_struct_has_field(b'request', b'rq_disk') == 1: 306*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('__RQ_DISK__', 'rq_disk') 307*387f9dfdSAndroid Build Coastguard Workerelse: 308*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('__RQ_DISK__', 'q->disk') 309*387f9dfdSAndroid Build Coastguard Worker 310*387f9dfdSAndroid Build Coastguard Workerif args.disk is not None: 311*387f9dfdSAndroid Build Coastguard Worker disk_path = os.path.join('/dev', args.disk) 312*387f9dfdSAndroid Build Coastguard Worker if not os.path.exists(disk_path): 313*387f9dfdSAndroid Build Coastguard Worker print("no such disk '%s'" % args.disk) 314*387f9dfdSAndroid Build Coastguard Worker exit(1) 315*387f9dfdSAndroid Build Coastguard Worker 316*387f9dfdSAndroid Build Coastguard Worker stat_info = os.stat(disk_path) 317*387f9dfdSAndroid Build Coastguard Worker dev = os.major(stat_info.st_rdev) << 20 | os.minor(stat_info.st_rdev) 318*387f9dfdSAndroid Build Coastguard Worker 319*387f9dfdSAndroid Build Coastguard Worker disk_filter_str = """ 320*387f9dfdSAndroid Build Coastguard Worker if(key.dev != %s) { 321*387f9dfdSAndroid Build Coastguard Worker return 0; 322*387f9dfdSAndroid Build Coastguard Worker } 323*387f9dfdSAndroid Build Coastguard Worker """ % (dev) 324*387f9dfdSAndroid Build Coastguard Worker 325*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('DISK_FILTER', disk_filter_str) 326*387f9dfdSAndroid Build Coastguard Workerelse: 327*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('DISK_FILTER', '') 328*387f9dfdSAndroid Build Coastguard Worker 329*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf: 330*387f9dfdSAndroid Build Coastguard Worker print(bpf_text) 331*387f9dfdSAndroid Build Coastguard Worker if args.ebpf: 332*387f9dfdSAndroid Build Coastguard Worker exit() 333*387f9dfdSAndroid Build Coastguard Worker 334*387f9dfdSAndroid Build Coastguard Worker# initialize BPF 335*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text) 336*387f9dfdSAndroid Build Coastguard Workerif BPF.get_kprobe_functions(b'__blk_account_io_start'): 337*387f9dfdSAndroid Build Coastguard Worker b.attach_kprobe(event="__blk_account_io_start", fn_name="trace_pid_start") 338*387f9dfdSAndroid Build Coastguard Workerelif BPF.get_kprobe_functions(b'blk_account_io_start'): 339*387f9dfdSAndroid Build Coastguard Worker b.attach_kprobe(event="blk_account_io_start", fn_name="trace_pid_start") 340*387f9dfdSAndroid Build Coastguard Workerelse: 341*387f9dfdSAndroid Build Coastguard Worker b.attach_tracepoint(tp="block:block_io_start", fn_name="trace_pid_start_tp") 342*387f9dfdSAndroid Build Coastguard Workerif BPF.get_kprobe_functions(b'blk_start_request'): 343*387f9dfdSAndroid Build Coastguard Worker b.attach_kprobe(event="blk_start_request", fn_name="trace_req_start") 344*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="blk_mq_start_request", fn_name="trace_req_start") 345*387f9dfdSAndroid Build Coastguard Workerif BPF.get_kprobe_functions(b'__blk_account_io_done'): 346*387f9dfdSAndroid Build Coastguard Worker b.attach_kprobe(event="__blk_account_io_done", fn_name="trace_req_completion") 347*387f9dfdSAndroid Build Coastguard Workerelif BPF.get_kprobe_functions(b'blk_account_io_done'): 348*387f9dfdSAndroid Build Coastguard Worker b.attach_kprobe(event="blk_account_io_done", fn_name="trace_req_completion") 349*387f9dfdSAndroid Build Coastguard Workerelse: 350*387f9dfdSAndroid Build Coastguard Worker b.attach_tracepoint(tp="block:block_io_done", fn_name="trace_req_completion_tp") 351*387f9dfdSAndroid Build Coastguard Worker 352*387f9dfdSAndroid Build Coastguard Worker# header 353*387f9dfdSAndroid Build Coastguard Workerprint("%-11s %-14s %-7s %-9s %-1s %-10s %-7s" % ("TIME(s)", "COMM", "PID", 354*387f9dfdSAndroid Build Coastguard Worker "DISK", "T", "SECTOR", "BYTES"), end="") 355*387f9dfdSAndroid Build Coastguard Workerif args.pattern: 356*387f9dfdSAndroid Build Coastguard Worker print("%-1s " % ("P"), end="") 357*387f9dfdSAndroid Build Coastguard Workerif args.queue: 358*387f9dfdSAndroid Build Coastguard Worker print("%7s " % ("QUE(ms)"), end="") 359*387f9dfdSAndroid Build Coastguard Workerprint("%7s" % "LAT(ms)") 360*387f9dfdSAndroid Build Coastguard Worker 361*387f9dfdSAndroid Build Coastguard Worker 362*387f9dfdSAndroid Build Coastguard Worker# cache disk major,minor -> diskname 363*387f9dfdSAndroid Build Coastguard Workerdiskstats = "/proc/diskstats" 364*387f9dfdSAndroid Build Coastguard Workerdisklookup = {} 365*387f9dfdSAndroid Build Coastguard Workerwith open(diskstats) as stats: 366*387f9dfdSAndroid Build Coastguard Worker for line in stats: 367*387f9dfdSAndroid Build Coastguard Worker a = line.split() 368*387f9dfdSAndroid Build Coastguard Worker disklookup[a[0] + "," + a[1]] = a[2] 369*387f9dfdSAndroid Build Coastguard Worker 370*387f9dfdSAndroid Build Coastguard Workerdef disk_print(d): 371*387f9dfdSAndroid Build Coastguard Worker major = d >> 20 372*387f9dfdSAndroid Build Coastguard Worker minor = d & ((1 << 20) - 1) 373*387f9dfdSAndroid Build Coastguard Worker 374*387f9dfdSAndroid Build Coastguard Worker disk = str(major) + "," + str(minor) 375*387f9dfdSAndroid Build Coastguard Worker if disk in disklookup: 376*387f9dfdSAndroid Build Coastguard Worker diskname = disklookup[disk] 377*387f9dfdSAndroid Build Coastguard Worker else: 378*387f9dfdSAndroid Build Coastguard Worker diskname = "<unknown>" 379*387f9dfdSAndroid Build Coastguard Worker 380*387f9dfdSAndroid Build Coastguard Worker return diskname 381*387f9dfdSAndroid Build Coastguard Worker 382*387f9dfdSAndroid Build Coastguard Workerrwflg = "" 383*387f9dfdSAndroid Build Coastguard Workerpattern = "" 384*387f9dfdSAndroid Build Coastguard Workerstart_ts = 0 385*387f9dfdSAndroid Build Coastguard Workerprev_ts = 0 386*387f9dfdSAndroid Build Coastguard Workerdelta = 0 387*387f9dfdSAndroid Build Coastguard Worker 388*387f9dfdSAndroid Build Coastguard WorkerP_SEQUENTIAL = 1 389*387f9dfdSAndroid Build Coastguard WorkerP_RANDOM = 2 390*387f9dfdSAndroid Build Coastguard Worker 391*387f9dfdSAndroid Build Coastguard Worker# process event 392*387f9dfdSAndroid Build Coastguard Workerdef print_event(cpu, data, size): 393*387f9dfdSAndroid Build Coastguard Worker event = b["events"].event(data) 394*387f9dfdSAndroid Build Coastguard Worker 395*387f9dfdSAndroid Build Coastguard Worker global start_ts 396*387f9dfdSAndroid Build Coastguard Worker if start_ts == 0: 397*387f9dfdSAndroid Build Coastguard Worker start_ts = event.ts 398*387f9dfdSAndroid Build Coastguard Worker 399*387f9dfdSAndroid Build Coastguard Worker if event.rwflag == 1: 400*387f9dfdSAndroid Build Coastguard Worker rwflg = "W" 401*387f9dfdSAndroid Build Coastguard Worker else: 402*387f9dfdSAndroid Build Coastguard Worker rwflg = "R" 403*387f9dfdSAndroid Build Coastguard Worker 404*387f9dfdSAndroid Build Coastguard Worker delta = float(event.ts) - start_ts 405*387f9dfdSAndroid Build Coastguard Worker 406*387f9dfdSAndroid Build Coastguard Worker disk_name = disk_print(event.dev) 407*387f9dfdSAndroid Build Coastguard Worker 408*387f9dfdSAndroid Build Coastguard Worker print("%-11.6f %-14.14s %-7s %-9s %-1s %-10s %-7s" % ( 409*387f9dfdSAndroid Build Coastguard Worker delta / 1000000, event.name.decode('utf-8', 'replace'), event.pid, 410*387f9dfdSAndroid Build Coastguard Worker disk_name, rwflg, event.sector, event.len), end="") 411*387f9dfdSAndroid Build Coastguard Worker if args.pattern: 412*387f9dfdSAndroid Build Coastguard Worker if event.pattern == P_SEQUENTIAL: 413*387f9dfdSAndroid Build Coastguard Worker pattern = "S" 414*387f9dfdSAndroid Build Coastguard Worker elif event.pattern == P_RANDOM: 415*387f9dfdSAndroid Build Coastguard Worker pattern = "R" 416*387f9dfdSAndroid Build Coastguard Worker else: 417*387f9dfdSAndroid Build Coastguard Worker pattern = "?" 418*387f9dfdSAndroid Build Coastguard Worker print("%-1s " % pattern, end="") 419*387f9dfdSAndroid Build Coastguard Worker if args.queue: 420*387f9dfdSAndroid Build Coastguard Worker print("%7.2f " % (float(event.qdelta) / 1000000), end="") 421*387f9dfdSAndroid Build Coastguard Worker print("%7.2f" % (float(event.delta) / 1000000)) 422*387f9dfdSAndroid Build Coastguard Worker 423*387f9dfdSAndroid Build Coastguard Worker# loop with callback to print_event 424*387f9dfdSAndroid Build Coastguard Workerb["events"].open_perf_buffer(print_event, page_cnt=64) 425*387f9dfdSAndroid Build Coastguard Workerwhile 1: 426*387f9dfdSAndroid Build Coastguard Worker try: 427*387f9dfdSAndroid Build Coastguard Worker b.perf_buffer_poll() 428*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 429*387f9dfdSAndroid Build Coastguard Worker exit() 430