xref: /aosp_15_r20/external/bcc/tools/biosnoop.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
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(&sector_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(&sector_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