xref: /aosp_15_r20/external/bcc/tools/nfsdist.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# nfsdist   Summarize NFS operation latency
5*387f9dfdSAndroid Build Coastguard Worker#           for Linux, uses BCC and eBPF
6*387f9dfdSAndroid Build Coastguard Worker#
7*387f9dfdSAndroid Build Coastguard Worker# USAGE: nfsdist [-h] [-T] [-m] [-p PID] [interval] [count]
8*387f9dfdSAndroid Build Coastguard Worker#
9*387f9dfdSAndroid Build Coastguard Worker# 4-Sep-2017    Samuel Nair     created this
10*387f9dfdSAndroid Build Coastguard Worker
11*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function
12*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF
13*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep, strftime
14*387f9dfdSAndroid Build Coastguard Workerimport argparse
15*387f9dfdSAndroid Build Coastguard Worker
16*387f9dfdSAndroid Build Coastguard Worker# arguments
17*387f9dfdSAndroid Build Coastguard Workerexamples = """examples:
18*387f9dfdSAndroid Build Coastguard Worker    ./nfsdist            # show operation latency as a histogram
19*387f9dfdSAndroid Build Coastguard Worker    ./nfsdist -p 181     # trace PID 181 only
20*387f9dfdSAndroid Build Coastguard Worker    ./nfsdist 1 10       # print 1 second summaries, 10 times
21*387f9dfdSAndroid Build Coastguard Worker    ./nfsdist -m 5       # 5s summaries, milliseconds
22*387f9dfdSAndroid Build Coastguard Worker"""
23*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser(
24*387f9dfdSAndroid Build Coastguard Worker        description="Summarize NFS operation latency",
25*387f9dfdSAndroid Build Coastguard Worker        formatter_class=argparse.RawDescriptionHelpFormatter,
26*387f9dfdSAndroid Build Coastguard Worker        epilog=examples)
27*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-T", "--notimestamp", action="store_true",
28*387f9dfdSAndroid Build Coastguard Worker                    help="don't include timestamp on interval output")
29*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-m", "--milliseconds", action="store_true",
30*387f9dfdSAndroid Build Coastguard Worker                    help="output in milliseconds")
31*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid",
32*387f9dfdSAndroid Build Coastguard Worker                    help="trace this PID only")
33*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("interval", nargs="?",
34*387f9dfdSAndroid Build Coastguard Worker                    help="output interval, in seconds")
35*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("count", nargs="?", default=99999999,
36*387f9dfdSAndroid Build Coastguard Worker                    help="number of outputs")
37*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true",
38*387f9dfdSAndroid Build Coastguard Worker                    help=argparse.SUPPRESS)
39*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args()
40*387f9dfdSAndroid Build Coastguard Workerpid = args.pid
41*387f9dfdSAndroid Build Coastguard Workercountdown = int(args.count)
42*387f9dfdSAndroid Build Coastguard Workerif args.milliseconds:
43*387f9dfdSAndroid Build Coastguard Worker    factor = 1000000
44*387f9dfdSAndroid Build Coastguard Worker    label = "msecs"
45*387f9dfdSAndroid Build Coastguard Workerelse:
46*387f9dfdSAndroid Build Coastguard Worker    factor = 1000
47*387f9dfdSAndroid Build Coastguard Worker    label = "usecs"
48*387f9dfdSAndroid Build Coastguard Worker    if args.interval and int(args.interval) == 0:
49*387f9dfdSAndroid Build Coastguard Worker        print("ERROR: interval 0. Exiting.")
50*387f9dfdSAndroid Build Coastguard Worker        exit()
51*387f9dfdSAndroid Build Coastguard Workerdebug = 0
52*387f9dfdSAndroid Build Coastguard Worker
53*387f9dfdSAndroid Build Coastguard Worker# define BPF program
54*387f9dfdSAndroid Build Coastguard Workerbpf_text = """
55*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h>
56*387f9dfdSAndroid Build Coastguard Worker#include <linux/fs.h>
57*387f9dfdSAndroid Build Coastguard Worker#include <linux/sched.h>
58*387f9dfdSAndroid Build Coastguard Worker
59*387f9dfdSAndroid Build Coastguard Worker#define OP_NAME_LEN 8
60*387f9dfdSAndroid Build Coastguard Workertypedef struct dist_key {
61*387f9dfdSAndroid Build Coastguard Worker    char op[OP_NAME_LEN];
62*387f9dfdSAndroid Build Coastguard Worker    u64 slot;
63*387f9dfdSAndroid Build Coastguard Worker} dist_key_t;
64*387f9dfdSAndroid Build Coastguard Worker
65*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(start, u32);
66*387f9dfdSAndroid Build Coastguard WorkerBPF_HISTOGRAM(dist, dist_key_t);
67*387f9dfdSAndroid Build Coastguard Worker
68*387f9dfdSAndroid Build Coastguard Worker// time operation
69*387f9dfdSAndroid Build Coastguard Workerint trace_entry(struct pt_regs *ctx)
70*387f9dfdSAndroid Build Coastguard Worker{
71*387f9dfdSAndroid Build Coastguard Worker    u64 pid_tgid = bpf_get_current_pid_tgid();
72*387f9dfdSAndroid Build Coastguard Worker    u32 pid = pid_tgid >> 32;
73*387f9dfdSAndroid Build Coastguard Worker    u32 tid = (u32)pid_tgid;
74*387f9dfdSAndroid Build Coastguard Worker
75*387f9dfdSAndroid Build Coastguard Worker    if (FILTER_PID)
76*387f9dfdSAndroid Build Coastguard Worker        return 0;
77*387f9dfdSAndroid Build Coastguard Worker    u64 ts = bpf_ktime_get_ns();
78*387f9dfdSAndroid Build Coastguard Worker    start.update(&tid, &ts);
79*387f9dfdSAndroid Build Coastguard Worker    return 0;
80*387f9dfdSAndroid Build Coastguard Worker}
81*387f9dfdSAndroid Build Coastguard Worker
82*387f9dfdSAndroid Build Coastguard Workerstatic int trace_return(struct pt_regs *ctx, const char *op)
83*387f9dfdSAndroid Build Coastguard Worker{
84*387f9dfdSAndroid Build Coastguard Worker    u64 *tsp;
85*387f9dfdSAndroid Build Coastguard Worker    u64 pid_tgid = bpf_get_current_pid_tgid();
86*387f9dfdSAndroid Build Coastguard Worker    u32 pid = pid_tgid >> 32;
87*387f9dfdSAndroid Build Coastguard Worker    u32 tid = (u32)pid_tgid;
88*387f9dfdSAndroid Build Coastguard Worker
89*387f9dfdSAndroid Build Coastguard Worker    // fetch timestamp and calculate delta
90*387f9dfdSAndroid Build Coastguard Worker    tsp = start.lookup(&tid);
91*387f9dfdSAndroid Build Coastguard Worker    if (tsp == 0) {
92*387f9dfdSAndroid Build Coastguard Worker        return 0;   // missed start or filtered
93*387f9dfdSAndroid Build Coastguard Worker    }
94*387f9dfdSAndroid Build Coastguard Worker    u64 delta = (bpf_ktime_get_ns() - *tsp) / FACTOR;
95*387f9dfdSAndroid Build Coastguard Worker
96*387f9dfdSAndroid Build Coastguard Worker    // store as histogram
97*387f9dfdSAndroid Build Coastguard Worker    dist_key_t key = {.slot = bpf_log2l(delta)};
98*387f9dfdSAndroid Build Coastguard Worker    __builtin_memcpy(&key.op, op, sizeof(key.op));
99*387f9dfdSAndroid Build Coastguard Worker    dist.atomic_increment(key);
100*387f9dfdSAndroid Build Coastguard Worker
101*387f9dfdSAndroid Build Coastguard Worker    start.delete(&tid);
102*387f9dfdSAndroid Build Coastguard Worker    return 0;
103*387f9dfdSAndroid Build Coastguard Worker}
104*387f9dfdSAndroid Build Coastguard Worker
105*387f9dfdSAndroid Build Coastguard Workerint trace_read_return(struct pt_regs *ctx)
106*387f9dfdSAndroid Build Coastguard Worker{
107*387f9dfdSAndroid Build Coastguard Worker    char *op = "read";
108*387f9dfdSAndroid Build Coastguard Worker    return trace_return(ctx, op);
109*387f9dfdSAndroid Build Coastguard Worker}
110*387f9dfdSAndroid Build Coastguard Worker
111*387f9dfdSAndroid Build Coastguard Workerint trace_write_return(struct pt_regs *ctx)
112*387f9dfdSAndroid Build Coastguard Worker{
113*387f9dfdSAndroid Build Coastguard Worker    char *op = "write";
114*387f9dfdSAndroid Build Coastguard Worker    return trace_return(ctx, op);
115*387f9dfdSAndroid Build Coastguard Worker}
116*387f9dfdSAndroid Build Coastguard Worker
117*387f9dfdSAndroid Build Coastguard Workerint trace_open_return(struct pt_regs *ctx)
118*387f9dfdSAndroid Build Coastguard Worker{
119*387f9dfdSAndroid Build Coastguard Worker    char *op = "open";
120*387f9dfdSAndroid Build Coastguard Worker    return trace_return(ctx, op);
121*387f9dfdSAndroid Build Coastguard Worker}
122*387f9dfdSAndroid Build Coastguard Worker
123*387f9dfdSAndroid Build Coastguard Workerint trace_getattr_return(struct pt_regs *ctx)
124*387f9dfdSAndroid Build Coastguard Worker{
125*387f9dfdSAndroid Build Coastguard Worker    char *op = "getattr";
126*387f9dfdSAndroid Build Coastguard Worker    return trace_return(ctx, op);
127*387f9dfdSAndroid Build Coastguard Worker}
128*387f9dfdSAndroid Build Coastguard Worker"""
129*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('FACTOR', str(factor))
130*387f9dfdSAndroid Build Coastguard Workerif args.pid:
131*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER_PID', 'pid != %s' % pid)
132*387f9dfdSAndroid Build Coastguard Workerelse:
133*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER_PID', '0')
134*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf:
135*387f9dfdSAndroid Build Coastguard Worker    print(bpf_text)
136*387f9dfdSAndroid Build Coastguard Worker    if args.ebpf:
137*387f9dfdSAndroid Build Coastguard Worker        exit()
138*387f9dfdSAndroid Build Coastguard Worker
139*387f9dfdSAndroid Build Coastguard Worker# load BPF program
140*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text)
141*387f9dfdSAndroid Build Coastguard Worker
142*387f9dfdSAndroid Build Coastguard Worker# common file functions
143*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="nfs_file_read", fn_name="trace_entry")
144*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="nfs_file_write", fn_name="trace_entry")
145*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="nfs_file_open", fn_name="trace_entry")
146*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="nfs_getattr", fn_name="trace_entry")
147*387f9dfdSAndroid Build Coastguard Worker
148*387f9dfdSAndroid Build Coastguard Workerb.attach_kretprobe(event="nfs_file_read", fn_name="trace_read_return")
149*387f9dfdSAndroid Build Coastguard Workerb.attach_kretprobe(event="nfs_file_write", fn_name="trace_write_return")
150*387f9dfdSAndroid Build Coastguard Workerb.attach_kretprobe(event="nfs_file_open", fn_name="trace_open_return")
151*387f9dfdSAndroid Build Coastguard Workerb.attach_kretprobe(event="nfs_getattr", fn_name="trace_getattr_return")
152*387f9dfdSAndroid Build Coastguard Worker
153*387f9dfdSAndroid Build Coastguard Workerif BPF.get_kprobe_functions(b'nfs4_file_open'):
154*387f9dfdSAndroid Build Coastguard Worker    b.attach_kprobe(event="nfs4_file_open", fn_name="trace_entry")
155*387f9dfdSAndroid Build Coastguard Worker    b.attach_kretprobe(event="nfs4_file_open", fn_name="trace_open_return")
156*387f9dfdSAndroid Build Coastguard Workerelse:
157*387f9dfdSAndroid Build Coastguard Worker    b.attach_kprobe(event="nfs_file_open", fn_name="trace_entry")
158*387f9dfdSAndroid Build Coastguard Worker    b.attach_kretprobe(event="nfs_file_open", fn_name="trace_open_return")
159*387f9dfdSAndroid Build Coastguard Worker
160*387f9dfdSAndroid Build Coastguard Workerprint("Tracing NFS operation latency... Hit Ctrl-C to end.")
161*387f9dfdSAndroid Build Coastguard Worker
162*387f9dfdSAndroid Build Coastguard Worker# output
163*387f9dfdSAndroid Build Coastguard Workerexiting = 0
164*387f9dfdSAndroid Build Coastguard Workerdist = b.get_table("dist")
165*387f9dfdSAndroid Build Coastguard Workerwhile (1):
166*387f9dfdSAndroid Build Coastguard Worker    try:
167*387f9dfdSAndroid Build Coastguard Worker        if args.interval:
168*387f9dfdSAndroid Build Coastguard Worker            sleep(int(args.interval))
169*387f9dfdSAndroid Build Coastguard Worker        else:
170*387f9dfdSAndroid Build Coastguard Worker            sleep(99999999)
171*387f9dfdSAndroid Build Coastguard Worker    except KeyboardInterrupt:
172*387f9dfdSAndroid Build Coastguard Worker        exiting = 1
173*387f9dfdSAndroid Build Coastguard Worker
174*387f9dfdSAndroid Build Coastguard Worker    print()
175*387f9dfdSAndroid Build Coastguard Worker    if args.interval and (not args.notimestamp):
176*387f9dfdSAndroid Build Coastguard Worker        print(strftime("%H:%M:%S:"))
177*387f9dfdSAndroid Build Coastguard Worker
178*387f9dfdSAndroid Build Coastguard Worker    dist.print_log2_hist(label, "operation", section_print_fn=bytes.decode)
179*387f9dfdSAndroid Build Coastguard Worker    dist.clear()
180*387f9dfdSAndroid Build Coastguard Worker
181*387f9dfdSAndroid Build Coastguard Worker    countdown -= 1
182*387f9dfdSAndroid Build Coastguard Worker    if exiting or countdown == 0:
183*387f9dfdSAndroid Build Coastguard Worker        exit()
184