xref: /aosp_15_r20/external/bcc/tools/ext4dist.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# ext4dist  Summarize ext4 operation latency.
5*387f9dfdSAndroid Build Coastguard Worker#           For Linux, uses BCC, eBPF.
6*387f9dfdSAndroid Build Coastguard Worker#
7*387f9dfdSAndroid Build Coastguard Worker# USAGE: ext4dist [-h] [-T] [-m] [-p PID] [interval] [count]
8*387f9dfdSAndroid Build Coastguard Worker#
9*387f9dfdSAndroid Build Coastguard Worker# Copyright 2016 Netflix, Inc.
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# 12-Feb-2016   Brendan Gregg   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# symbols
20*387f9dfdSAndroid Build Coastguard Workerkallsyms = "/proc/kallsyms"
21*387f9dfdSAndroid Build Coastguard Worker
22*387f9dfdSAndroid Build Coastguard Worker# arguments
23*387f9dfdSAndroid Build Coastguard Workerexamples = """examples:
24*387f9dfdSAndroid Build Coastguard Worker    ./ext4dist            # show operation latency as a histogram
25*387f9dfdSAndroid Build Coastguard Worker    ./ext4dist -p 181     # trace PID 181 only
26*387f9dfdSAndroid Build Coastguard Worker    ./ext4dist 1 10       # print 1 second summaries, 10 times
27*387f9dfdSAndroid Build Coastguard Worker    ./ext4dist -m 5       # 5s summaries, milliseconds
28*387f9dfdSAndroid Build Coastguard Worker"""
29*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser(
30*387f9dfdSAndroid Build Coastguard Worker    description="Summarize ext4 operation latency",
31*387f9dfdSAndroid Build Coastguard Worker    formatter_class=argparse.RawDescriptionHelpFormatter,
32*387f9dfdSAndroid Build Coastguard Worker    epilog=examples)
33*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-T", "--notimestamp", action="store_true",
34*387f9dfdSAndroid Build Coastguard Worker    help="don't include timestamp on interval output")
35*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-m", "--milliseconds", action="store_true",
36*387f9dfdSAndroid Build Coastguard Worker    help="output in milliseconds")
37*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid",
38*387f9dfdSAndroid Build Coastguard Worker    help="trace this PID only")
39*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("interval", nargs="?",
40*387f9dfdSAndroid Build Coastguard Worker    help="output interval, in seconds")
41*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("count", nargs="?", default=99999999,
42*387f9dfdSAndroid Build Coastguard Worker    help="number of outputs")
43*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true",
44*387f9dfdSAndroid Build Coastguard Worker    help=argparse.SUPPRESS)
45*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args()
46*387f9dfdSAndroid Build Coastguard Workerpid = args.pid
47*387f9dfdSAndroid Build Coastguard Workercountdown = int(args.count)
48*387f9dfdSAndroid Build Coastguard Workerif args.milliseconds:
49*387f9dfdSAndroid Build Coastguard Worker    factor = 1000000
50*387f9dfdSAndroid Build Coastguard Worker    label = "msecs"
51*387f9dfdSAndroid Build Coastguard Workerelse:
52*387f9dfdSAndroid Build Coastguard Worker    factor = 1000
53*387f9dfdSAndroid Build Coastguard Worker    label = "usecs"
54*387f9dfdSAndroid Build Coastguard Workerif args.interval and int(args.interval) == 0:
55*387f9dfdSAndroid Build Coastguard Worker    print("ERROR: interval 0. Exiting.")
56*387f9dfdSAndroid Build Coastguard Worker    exit()
57*387f9dfdSAndroid Build Coastguard Workerdebug = 0
58*387f9dfdSAndroid Build Coastguard Worker
59*387f9dfdSAndroid Build Coastguard Worker# define BPF program
60*387f9dfdSAndroid Build Coastguard Workerbpf_text = """
61*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h>
62*387f9dfdSAndroid Build Coastguard Worker#include <linux/fs.h>
63*387f9dfdSAndroid Build Coastguard Worker#include <linux/sched.h>
64*387f9dfdSAndroid Build Coastguard Worker
65*387f9dfdSAndroid Build Coastguard Worker#define OP_NAME_LEN 8
66*387f9dfdSAndroid Build Coastguard Workertypedef struct dist_key {
67*387f9dfdSAndroid Build Coastguard Worker    char op[OP_NAME_LEN];
68*387f9dfdSAndroid Build Coastguard Worker    u64 slot;
69*387f9dfdSAndroid Build Coastguard Worker} dist_key_t;
70*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(start, u32);
71*387f9dfdSAndroid Build Coastguard WorkerBPF_HISTOGRAM(dist, dist_key_t);
72*387f9dfdSAndroid Build Coastguard Worker
73*387f9dfdSAndroid Build Coastguard Worker// time operation
74*387f9dfdSAndroid Build Coastguard Workerint trace_entry(struct pt_regs *ctx)
75*387f9dfdSAndroid Build Coastguard Worker{
76*387f9dfdSAndroid Build Coastguard Worker    u64 pid_tgid = bpf_get_current_pid_tgid();
77*387f9dfdSAndroid Build Coastguard Worker    u32 pid = pid_tgid >> 32;
78*387f9dfdSAndroid Build Coastguard Worker    u32 tid = (u32)pid_tgid;
79*387f9dfdSAndroid Build Coastguard Worker
80*387f9dfdSAndroid Build Coastguard Worker    if (FILTER_PID)
81*387f9dfdSAndroid Build Coastguard Worker        return 0;
82*387f9dfdSAndroid Build Coastguard Worker    u64 ts = bpf_ktime_get_ns();
83*387f9dfdSAndroid Build Coastguard Worker    start.update(&tid, &ts);
84*387f9dfdSAndroid Build Coastguard Worker    return 0;
85*387f9dfdSAndroid Build Coastguard Worker}
86*387f9dfdSAndroid Build Coastguard Worker
87*387f9dfdSAndroid Build Coastguard WorkerEXT4_TRACE_READ_CODE
88*387f9dfdSAndroid Build Coastguard Worker
89*387f9dfdSAndroid Build Coastguard Workerstatic int trace_return(struct pt_regs *ctx, const char *op)
90*387f9dfdSAndroid Build Coastguard Worker{
91*387f9dfdSAndroid Build Coastguard Worker    u64 *tsp;
92*387f9dfdSAndroid Build Coastguard Worker    u64 pid_tgid = bpf_get_current_pid_tgid();
93*387f9dfdSAndroid Build Coastguard Worker    u32 pid = pid_tgid >> 32;
94*387f9dfdSAndroid Build Coastguard Worker    u32 tid = (u32)pid_tgid;
95*387f9dfdSAndroid Build Coastguard Worker
96*387f9dfdSAndroid Build Coastguard Worker    // fetch timestamp and calculate delta
97*387f9dfdSAndroid Build Coastguard Worker    tsp = start.lookup(&tid);
98*387f9dfdSAndroid Build Coastguard Worker    if (tsp == 0) {
99*387f9dfdSAndroid Build Coastguard Worker        return 0;   // missed start or filtered
100*387f9dfdSAndroid Build Coastguard Worker    }
101*387f9dfdSAndroid Build Coastguard Worker    u64 delta = bpf_ktime_get_ns() - *tsp;
102*387f9dfdSAndroid Build Coastguard Worker    start.delete(&tid);
103*387f9dfdSAndroid Build Coastguard Worker
104*387f9dfdSAndroid Build Coastguard Worker    // Skip entries with backwards time: temp workaround for #728
105*387f9dfdSAndroid Build Coastguard Worker    if ((s64) delta < 0)
106*387f9dfdSAndroid Build Coastguard Worker        return 0;
107*387f9dfdSAndroid Build Coastguard Worker
108*387f9dfdSAndroid Build Coastguard Worker    delta /= FACTOR;
109*387f9dfdSAndroid Build Coastguard Worker
110*387f9dfdSAndroid Build Coastguard Worker    // store as histogram
111*387f9dfdSAndroid Build Coastguard Worker    dist_key_t key = {.slot = bpf_log2l(delta)};
112*387f9dfdSAndroid Build Coastguard Worker    __builtin_memcpy(&key.op, op, sizeof(key.op));
113*387f9dfdSAndroid Build Coastguard Worker    dist.atomic_increment(key);
114*387f9dfdSAndroid Build Coastguard Worker
115*387f9dfdSAndroid Build Coastguard Worker    return 0;
116*387f9dfdSAndroid Build Coastguard Worker}
117*387f9dfdSAndroid Build Coastguard Worker
118*387f9dfdSAndroid Build Coastguard Workerint trace_read_return(struct pt_regs *ctx)
119*387f9dfdSAndroid Build Coastguard Worker{
120*387f9dfdSAndroid Build Coastguard Worker    char *op = "read";
121*387f9dfdSAndroid Build Coastguard Worker    return trace_return(ctx, op);
122*387f9dfdSAndroid Build Coastguard Worker}
123*387f9dfdSAndroid Build Coastguard Worker
124*387f9dfdSAndroid Build Coastguard Workerint trace_write_return(struct pt_regs *ctx)
125*387f9dfdSAndroid Build Coastguard Worker{
126*387f9dfdSAndroid Build Coastguard Worker    char *op = "write";
127*387f9dfdSAndroid Build Coastguard Worker    return trace_return(ctx, op);
128*387f9dfdSAndroid Build Coastguard Worker}
129*387f9dfdSAndroid Build Coastguard Worker
130*387f9dfdSAndroid Build Coastguard Workerint trace_open_return(struct pt_regs *ctx)
131*387f9dfdSAndroid Build Coastguard Worker{
132*387f9dfdSAndroid Build Coastguard Worker    char *op = "open";
133*387f9dfdSAndroid Build Coastguard Worker    return trace_return(ctx, op);
134*387f9dfdSAndroid Build Coastguard Worker}
135*387f9dfdSAndroid Build Coastguard Worker
136*387f9dfdSAndroid Build Coastguard Workerint trace_fsync_return(struct pt_regs *ctx)
137*387f9dfdSAndroid Build Coastguard Worker{
138*387f9dfdSAndroid Build Coastguard Worker    char *op = "fsync";
139*387f9dfdSAndroid Build Coastguard Worker    return trace_return(ctx, op);
140*387f9dfdSAndroid Build Coastguard Worker}
141*387f9dfdSAndroid Build Coastguard Worker"""
142*387f9dfdSAndroid Build Coastguard Worker
143*387f9dfdSAndroid Build Coastguard Worker# Starting from Linux 4.10 ext4_file_operations.read_iter has been changed from
144*387f9dfdSAndroid Build Coastguard Worker# using generic_file_read_iter() to its own ext4_file_read_iter().
145*387f9dfdSAndroid Build Coastguard Worker#
146*387f9dfdSAndroid Build Coastguard Worker# To detect the proper function to trace check if ext4_file_read_iter() is
147*387f9dfdSAndroid Build Coastguard Worker# defined in /proc/kallsyms, if it's defined attach to that function, otherwise
148*387f9dfdSAndroid Build Coastguard Worker# use generic_file_read_iter() and inside the trace hook filter on ext4 read
149*387f9dfdSAndroid Build Coastguard Worker# events (checking if file->f_op == ext4_file_operations).
150*387f9dfdSAndroid Build Coastguard Workerif BPF.get_kprobe_functions(b'ext4_file_read_iter'):
151*387f9dfdSAndroid Build Coastguard Worker    ext4_read_fn = 'ext4_file_read_iter'
152*387f9dfdSAndroid Build Coastguard Worker    ext4_trace_read_fn = 'trace_entry'
153*387f9dfdSAndroid Build Coastguard Worker    ext4_trace_read_code = ''
154*387f9dfdSAndroid Build Coastguard Workerelse:
155*387f9dfdSAndroid Build Coastguard Worker    ext4_read_fn = 'generic_file_read_iter'
156*387f9dfdSAndroid Build Coastguard Worker    ext4_trace_read_fn = 'trace_read_entry'
157*387f9dfdSAndroid Build Coastguard Worker    ext4_file_ops_addr = ''
158*387f9dfdSAndroid Build Coastguard Worker    with open(kallsyms) as syms:
159*387f9dfdSAndroid Build Coastguard Worker        for line in syms:
160*387f9dfdSAndroid Build Coastguard Worker            (addr, size, name) = line.rstrip().split(" ", 2)
161*387f9dfdSAndroid Build Coastguard Worker            name = name.split("\t")[0]
162*387f9dfdSAndroid Build Coastguard Worker            if name == "ext4_file_operations":
163*387f9dfdSAndroid Build Coastguard Worker                ext4_file_ops_addr = "0x" + addr
164*387f9dfdSAndroid Build Coastguard Worker                break
165*387f9dfdSAndroid Build Coastguard Worker        if ext4_file_ops_addr == '':
166*387f9dfdSAndroid Build Coastguard Worker            print("ERROR: no ext4_file_operations in /proc/kallsyms. Exiting.")
167*387f9dfdSAndroid Build Coastguard Worker            print("HINT: the kernel should be built with CONFIG_KALLSYMS_ALL.")
168*387f9dfdSAndroid Build Coastguard Worker            exit()
169*387f9dfdSAndroid Build Coastguard Worker    ext4_trace_read_code = """
170*387f9dfdSAndroid Build Coastguard Workerint trace_read_entry(struct pt_regs *ctx, struct kiocb *iocb)
171*387f9dfdSAndroid Build Coastguard Worker{
172*387f9dfdSAndroid Build Coastguard Worker    u64 pid_tgid = bpf_get_current_pid_tgid();
173*387f9dfdSAndroid Build Coastguard Worker    u32 pid = pid_tgid >> 32;
174*387f9dfdSAndroid Build Coastguard Worker    u32 tid = (u32)pid_tgid;
175*387f9dfdSAndroid Build Coastguard Worker
176*387f9dfdSAndroid Build Coastguard Worker    if (FILTER_PID)
177*387f9dfdSAndroid Build Coastguard Worker        return 0;
178*387f9dfdSAndroid Build Coastguard Worker
179*387f9dfdSAndroid Build Coastguard Worker    // ext4 filter on file->f_op == ext4_file_operations
180*387f9dfdSAndroid Build Coastguard Worker    struct file *fp = iocb->ki_filp;
181*387f9dfdSAndroid Build Coastguard Worker    if ((u64)fp->f_op != %s)
182*387f9dfdSAndroid Build Coastguard Worker        return 0;
183*387f9dfdSAndroid Build Coastguard Worker
184*387f9dfdSAndroid Build Coastguard Worker    u64 ts = bpf_ktime_get_ns();
185*387f9dfdSAndroid Build Coastguard Worker    start.update(&tid, &ts);
186*387f9dfdSAndroid Build Coastguard Worker    return 0;
187*387f9dfdSAndroid Build Coastguard Worker}""" % ext4_file_ops_addr
188*387f9dfdSAndroid Build Coastguard Worker
189*387f9dfdSAndroid Build Coastguard Worker# code replacements
190*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('EXT4_TRACE_READ_CODE', ext4_trace_read_code)
191*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('FACTOR', str(factor))
192*387f9dfdSAndroid Build Coastguard Workerif args.pid:
193*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER_PID', 'pid != %s' % pid)
194*387f9dfdSAndroid Build Coastguard Workerelse:
195*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER_PID', '0')
196*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf:
197*387f9dfdSAndroid Build Coastguard Worker    print(bpf_text)
198*387f9dfdSAndroid Build Coastguard Worker    if args.ebpf:
199*387f9dfdSAndroid Build Coastguard Worker        exit()
200*387f9dfdSAndroid Build Coastguard Worker
201*387f9dfdSAndroid Build Coastguard Worker# load BPF program
202*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text)
203*387f9dfdSAndroid Build Coastguard Worker
204*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event=ext4_read_fn, fn_name=ext4_trace_read_fn)
205*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="ext4_file_write_iter", fn_name="trace_entry")
206*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="ext4_file_open", fn_name="trace_entry")
207*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="ext4_sync_file", fn_name="trace_entry")
208*387f9dfdSAndroid Build Coastguard Workerb.attach_kretprobe(event=ext4_read_fn, fn_name='trace_read_return')
209*387f9dfdSAndroid Build Coastguard Workerb.attach_kretprobe(event="ext4_file_write_iter", fn_name="trace_write_return")
210*387f9dfdSAndroid Build Coastguard Workerb.attach_kretprobe(event="ext4_file_open", fn_name="trace_open_return")
211*387f9dfdSAndroid Build Coastguard Workerb.attach_kretprobe(event="ext4_sync_file", fn_name="trace_fsync_return")
212*387f9dfdSAndroid Build Coastguard Worker
213*387f9dfdSAndroid Build Coastguard Workerprint("Tracing ext4 operation latency... Hit Ctrl-C to end.")
214*387f9dfdSAndroid Build Coastguard Worker
215*387f9dfdSAndroid Build Coastguard Worker# output
216*387f9dfdSAndroid Build Coastguard Workerexiting = 0
217*387f9dfdSAndroid Build Coastguard Workerdist = b.get_table("dist")
218*387f9dfdSAndroid Build Coastguard Workerwhile (1):
219*387f9dfdSAndroid Build Coastguard Worker    try:
220*387f9dfdSAndroid Build Coastguard Worker        if args.interval:
221*387f9dfdSAndroid Build Coastguard Worker            sleep(int(args.interval))
222*387f9dfdSAndroid Build Coastguard Worker        else:
223*387f9dfdSAndroid Build Coastguard Worker            sleep(99999999)
224*387f9dfdSAndroid Build Coastguard Worker    except KeyboardInterrupt:
225*387f9dfdSAndroid Build Coastguard Worker        exiting = 1
226*387f9dfdSAndroid Build Coastguard Worker
227*387f9dfdSAndroid Build Coastguard Worker    print()
228*387f9dfdSAndroid Build Coastguard Worker    if args.interval and (not args.notimestamp):
229*387f9dfdSAndroid Build Coastguard Worker        print(strftime("%H:%M:%S:"))
230*387f9dfdSAndroid Build Coastguard Worker
231*387f9dfdSAndroid Build Coastguard Worker    dist.print_log2_hist(label, "operation", section_print_fn=bytes.decode)
232*387f9dfdSAndroid Build Coastguard Worker    dist.clear()
233*387f9dfdSAndroid Build Coastguard Worker
234*387f9dfdSAndroid Build Coastguard Worker    countdown -= 1
235*387f9dfdSAndroid Build Coastguard Worker    if exiting or countdown == 0:
236*387f9dfdSAndroid Build Coastguard Worker        exit()
237