xref: /aosp_15_r20/external/bcc/tools/nfsslower.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# nfsslower     Trace slow NFS operations
5*387f9dfdSAndroid Build Coastguard Worker#               for Linux using BCC & eBPF
6*387f9dfdSAndroid Build Coastguard Worker#
7*387f9dfdSAndroid Build Coastguard Worker# Usage: nfsslower [-h] [-p PID] [min_ms]
8*387f9dfdSAndroid Build Coastguard Worker#
9*387f9dfdSAndroid Build Coastguard Worker# This script traces some common NFS operations: read, write, opens and
10*387f9dfdSAndroid Build Coastguard Worker# getattr. It measures the time spent in these operations, and prints details
11*387f9dfdSAndroid Build Coastguard Worker# for each that exceeded a threshold.
12*387f9dfdSAndroid Build Coastguard Worker# The script also traces commit operations, which is specific to nfs and could
13*387f9dfdSAndroid Build Coastguard Worker# be pretty slow.
14*387f9dfdSAndroid Build Coastguard Worker#
15*387f9dfdSAndroid Build Coastguard Worker# WARNING: This adds low-overhead instrumentation to these NFS operations,
16*387f9dfdSAndroid Build Coastguard Worker# including reads and writes from the file system cache. Such reads and writes
17*387f9dfdSAndroid Build Coastguard Worker# can be very frequent (depending on the workload; eg, 1M/sec), at which
18*387f9dfdSAndroid Build Coastguard Worker# point the overhead of this tool (even if it prints no "slower" events) can
19*387f9dfdSAndroid Build Coastguard Worker# begin to become significant.
20*387f9dfdSAndroid Build Coastguard Worker#
21*387f9dfdSAndroid Build Coastguard Worker# Most of this code is copied from similar tools (ext4slower, zfsslower etc)
22*387f9dfdSAndroid Build Coastguard Worker#
23*387f9dfdSAndroid Build Coastguard Worker# By default, a minimum millisecond threshold of 10 is used.
24*387f9dfdSAndroid Build Coastguard Worker#
25*387f9dfdSAndroid Build Coastguard Worker# This tool uses kprobes to instrument the kernel for entry and exit
26*387f9dfdSAndroid Build Coastguard Worker# information, in the future a preferred way would be to use tracepoints.
27*387f9dfdSAndroid Build Coastguard Worker# Currently there aren't any tracepoints available for nfs_read_file,
28*387f9dfdSAndroid Build Coastguard Worker# nfs_write_file and nfs_open_file, nfs_getattr does have entry and exit
29*387f9dfdSAndroid Build Coastguard Worker# tracepoints but we chose to use kprobes for consistency
30*387f9dfdSAndroid Build Coastguard Worker# Raw tracepoints are used to trace nfs:nfs_initiate_commit and
31*387f9dfdSAndroid Build Coastguard Worker# nfs:nfs_commit_done.
32*387f9dfdSAndroid Build Coastguard Worker#
33*387f9dfdSAndroid Build Coastguard Worker# 31-Aug-2017   Samuel Nair created this. Should work with NFSv{3,4}
34*387f9dfdSAndroid Build Coastguard Worker
35*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function
36*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF
37*387f9dfdSAndroid Build Coastguard Workerimport argparse
38*387f9dfdSAndroid Build Coastguard Workerfrom time import strftime
39*387f9dfdSAndroid Build Coastguard Worker
40*387f9dfdSAndroid Build Coastguard Workerexamples = """
41*387f9dfdSAndroid Build Coastguard Worker    ./nfsslower         # trace operations slower than 10ms
42*387f9dfdSAndroid Build Coastguard Worker    ./nfsslower 1       # trace operations slower than 1ms
43*387f9dfdSAndroid Build Coastguard Worker    ./nfsslower -j 1    # ... 1 ms, parsable output (csv)
44*387f9dfdSAndroid Build Coastguard Worker    ./nfsslower 0       # trace all nfs operations
45*387f9dfdSAndroid Build Coastguard Worker    ./nfsslower -p 121  # trace pid 121 only
46*387f9dfdSAndroid Build Coastguard Worker"""
47*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser(
48*387f9dfdSAndroid Build Coastguard Worker    description="""Trace READ, WRITE, OPEN, GETATTR \
49*387f9dfdSAndroid Build Coastguard Workerand COMMIT NFS calls slower than a threshold,\
50*387f9dfdSAndroid Build Coastguard Workersupports NFSv{3,4}""",
51*387f9dfdSAndroid Build Coastguard Worker    formatter_class=argparse.RawDescriptionHelpFormatter,
52*387f9dfdSAndroid Build Coastguard Worker    epilog=examples)
53*387f9dfdSAndroid Build Coastguard Worker
54*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-j", "--csv", action="store_true",
55*387f9dfdSAndroid Build Coastguard Worker                    help="just print fields: comma-separated values")
56*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid", help="Trace this pid only")
57*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("min_ms", nargs="?", default='10',
58*387f9dfdSAndroid Build Coastguard Worker                    help="Minimum IO duration to trace in ms (default=10ms)")
59*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true",
60*387f9dfdSAndroid Build Coastguard Worker                    help=argparse.SUPPRESS)
61*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args()
62*387f9dfdSAndroid Build Coastguard Workermin_ms = int(args.min_ms)
63*387f9dfdSAndroid Build Coastguard Workerpid = args.pid
64*387f9dfdSAndroid Build Coastguard Workercsv = args.csv
65*387f9dfdSAndroid Build Coastguard Workerdebug = 0
66*387f9dfdSAndroid Build Coastguard Worker
67*387f9dfdSAndroid Build Coastguard Workerbpf_text = """
68*387f9dfdSAndroid Build Coastguard Worker
69*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h>
70*387f9dfdSAndroid Build Coastguard Worker#include <linux/fs.h>
71*387f9dfdSAndroid Build Coastguard Worker#include <linux/sched.h>
72*387f9dfdSAndroid Build Coastguard Worker#include <linux/dcache.h>
73*387f9dfdSAndroid Build Coastguard Worker#include <linux/nfs_fs.h>
74*387f9dfdSAndroid Build Coastguard Worker
75*387f9dfdSAndroid Build Coastguard Worker#define TRACE_READ 0
76*387f9dfdSAndroid Build Coastguard Worker#define TRACE_WRITE 1
77*387f9dfdSAndroid Build Coastguard Worker#define TRACE_OPEN 2
78*387f9dfdSAndroid Build Coastguard Worker#define TRACE_GETATTR 3
79*387f9dfdSAndroid Build Coastguard Worker#define TRACE_COMMIT 4
80*387f9dfdSAndroid Build Coastguard Worker
81*387f9dfdSAndroid Build Coastguard Workerstruct val_t {
82*387f9dfdSAndroid Build Coastguard Worker    u64 ts;
83*387f9dfdSAndroid Build Coastguard Worker    u64 offset;
84*387f9dfdSAndroid Build Coastguard Worker    struct file *fp;
85*387f9dfdSAndroid Build Coastguard Worker    struct dentry *d;
86*387f9dfdSAndroid Build Coastguard Worker};
87*387f9dfdSAndroid Build Coastguard Worker
88*387f9dfdSAndroid Build Coastguard Workerstruct commit_t {
89*387f9dfdSAndroid Build Coastguard Worker    u64 ts;
90*387f9dfdSAndroid Build Coastguard Worker    u64 offset;
91*387f9dfdSAndroid Build Coastguard Worker    u64 count;
92*387f9dfdSAndroid Build Coastguard Worker};
93*387f9dfdSAndroid Build Coastguard Worker
94*387f9dfdSAndroid Build Coastguard Workerstruct data_t {
95*387f9dfdSAndroid Build Coastguard Worker    // XXX: switch some to u32's when supported
96*387f9dfdSAndroid Build Coastguard Worker    u64 ts_us;
97*387f9dfdSAndroid Build Coastguard Worker    u64 type;
98*387f9dfdSAndroid Build Coastguard Worker    u64 size;
99*387f9dfdSAndroid Build Coastguard Worker    u64 offset;
100*387f9dfdSAndroid Build Coastguard Worker    u64 delta_us;
101*387f9dfdSAndroid Build Coastguard Worker    u32 pid;
102*387f9dfdSAndroid Build Coastguard Worker    char task[TASK_COMM_LEN];
103*387f9dfdSAndroid Build Coastguard Worker    char file[DNAME_INLINE_LEN];
104*387f9dfdSAndroid Build Coastguard Worker};
105*387f9dfdSAndroid Build Coastguard Worker
106*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(entryinfo, u64, struct val_t);
107*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(events);
108*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(commitinfo, u64, struct commit_t);
109*387f9dfdSAndroid Build Coastguard Worker
110*387f9dfdSAndroid Build Coastguard Workerint trace_rw_entry(struct pt_regs *ctx, struct kiocb *iocb,
111*387f9dfdSAndroid Build Coastguard Worker                                struct iov_iter *data)
112*387f9dfdSAndroid Build Coastguard Worker{
113*387f9dfdSAndroid Build Coastguard Worker    u64 id = bpf_get_current_pid_tgid();
114*387f9dfdSAndroid Build Coastguard Worker    u32 pid = id >> 32; // PID is higher part
115*387f9dfdSAndroid Build Coastguard Worker
116*387f9dfdSAndroid Build Coastguard Worker    if(FILTER_PID)
117*387f9dfdSAndroid Build Coastguard Worker        return 0;
118*387f9dfdSAndroid Build Coastguard Worker
119*387f9dfdSAndroid Build Coastguard Worker    // store filep and timestamp by id
120*387f9dfdSAndroid Build Coastguard Worker    struct val_t val = {};
121*387f9dfdSAndroid Build Coastguard Worker    val.ts = bpf_ktime_get_ns();
122*387f9dfdSAndroid Build Coastguard Worker    val.fp = iocb->ki_filp;
123*387f9dfdSAndroid Build Coastguard Worker    val.d = NULL;
124*387f9dfdSAndroid Build Coastguard Worker    val.offset = iocb->ki_pos;
125*387f9dfdSAndroid Build Coastguard Worker
126*387f9dfdSAndroid Build Coastguard Worker    if (val.fp)
127*387f9dfdSAndroid Build Coastguard Worker        entryinfo.update(&id, &val);
128*387f9dfdSAndroid Build Coastguard Worker
129*387f9dfdSAndroid Build Coastguard Worker    return 0;
130*387f9dfdSAndroid Build Coastguard Worker}
131*387f9dfdSAndroid Build Coastguard Worker
132*387f9dfdSAndroid Build Coastguard Workerint trace_file_open_entry (struct pt_regs *ctx, struct inode *inode,
133*387f9dfdSAndroid Build Coastguard Worker                                struct file *filp)
134*387f9dfdSAndroid Build Coastguard Worker{
135*387f9dfdSAndroid Build Coastguard Worker    u64 id = bpf_get_current_pid_tgid();
136*387f9dfdSAndroid Build Coastguard Worker    u32 pid = id >> 32; // PID is higher part
137*387f9dfdSAndroid Build Coastguard Worker
138*387f9dfdSAndroid Build Coastguard Worker    if(FILTER_PID)
139*387f9dfdSAndroid Build Coastguard Worker        return 0;
140*387f9dfdSAndroid Build Coastguard Worker
141*387f9dfdSAndroid Build Coastguard Worker    // store filep and timestamp by id
142*387f9dfdSAndroid Build Coastguard Worker    struct val_t val = {};
143*387f9dfdSAndroid Build Coastguard Worker    val.ts = bpf_ktime_get_ns();
144*387f9dfdSAndroid Build Coastguard Worker    val.fp = filp;
145*387f9dfdSAndroid Build Coastguard Worker    val.d = NULL;
146*387f9dfdSAndroid Build Coastguard Worker    val.offset = 0;
147*387f9dfdSAndroid Build Coastguard Worker    if (val.fp)
148*387f9dfdSAndroid Build Coastguard Worker        entryinfo.update(&id, &val);
149*387f9dfdSAndroid Build Coastguard Worker
150*387f9dfdSAndroid Build Coastguard Worker    return 0;
151*387f9dfdSAndroid Build Coastguard Worker}
152*387f9dfdSAndroid Build Coastguard Worker
153*387f9dfdSAndroid Build Coastguard Workerint trace_getattr_entry(struct pt_regs *ctx, struct vfsmount *mnt,
154*387f9dfdSAndroid Build Coastguard Worker                        struct dentry *dentry, struct kstat *stat)
155*387f9dfdSAndroid Build Coastguard Worker{
156*387f9dfdSAndroid Build Coastguard Worker    u64 id = bpf_get_current_pid_tgid();
157*387f9dfdSAndroid Build Coastguard Worker    u32 pid = id >> 32; // PID is higher part
158*387f9dfdSAndroid Build Coastguard Worker
159*387f9dfdSAndroid Build Coastguard Worker    if(FILTER_PID)
160*387f9dfdSAndroid Build Coastguard Worker        return 0;
161*387f9dfdSAndroid Build Coastguard Worker
162*387f9dfdSAndroid Build Coastguard Worker    struct val_t val = {};
163*387f9dfdSAndroid Build Coastguard Worker    val.ts = bpf_ktime_get_ns();
164*387f9dfdSAndroid Build Coastguard Worker    val.fp = NULL;
165*387f9dfdSAndroid Build Coastguard Worker    val.d = dentry;
166*387f9dfdSAndroid Build Coastguard Worker    val.offset = 0;
167*387f9dfdSAndroid Build Coastguard Worker    if (val.d)
168*387f9dfdSAndroid Build Coastguard Worker        entryinfo.update(&id, &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 Workerstatic int trace_exit(struct pt_regs *ctx, int type)
174*387f9dfdSAndroid Build Coastguard Worker{
175*387f9dfdSAndroid Build Coastguard Worker    struct val_t *valp;
176*387f9dfdSAndroid Build Coastguard Worker    u64 id = bpf_get_current_pid_tgid();
177*387f9dfdSAndroid Build Coastguard Worker    u32 pid = id >> 32; // PID is higher part
178*387f9dfdSAndroid Build Coastguard Worker
179*387f9dfdSAndroid Build Coastguard Worker    valp = entryinfo.lookup(&id);
180*387f9dfdSAndroid Build Coastguard Worker    if (valp == 0) {
181*387f9dfdSAndroid Build Coastguard Worker        // missed tracing issue or filtered
182*387f9dfdSAndroid Build Coastguard Worker        return 0;
183*387f9dfdSAndroid Build Coastguard Worker    }
184*387f9dfdSAndroid Build Coastguard Worker
185*387f9dfdSAndroid Build Coastguard Worker    // calculate delta
186*387f9dfdSAndroid Build Coastguard Worker    u64 ts = bpf_ktime_get_ns();
187*387f9dfdSAndroid Build Coastguard Worker    u64 delta_us = (ts - valp->ts) / 1000;
188*387f9dfdSAndroid Build Coastguard Worker    entryinfo.delete(&id);
189*387f9dfdSAndroid Build Coastguard Worker
190*387f9dfdSAndroid Build Coastguard Worker    if (FILTER_US)
191*387f9dfdSAndroid Build Coastguard Worker        return 0;
192*387f9dfdSAndroid Build Coastguard Worker
193*387f9dfdSAndroid Build Coastguard Worker    // populate output struct
194*387f9dfdSAndroid Build Coastguard Worker    u32 size = PT_REGS_RC(ctx);
195*387f9dfdSAndroid Build Coastguard Worker    struct data_t data = {};
196*387f9dfdSAndroid Build Coastguard Worker    data.type = type;
197*387f9dfdSAndroid Build Coastguard Worker    data.size = size;
198*387f9dfdSAndroid Build Coastguard Worker    data.delta_us = delta_us;
199*387f9dfdSAndroid Build Coastguard Worker    data.pid = pid;
200*387f9dfdSAndroid Build Coastguard Worker    data.ts_us = ts / 1000;
201*387f9dfdSAndroid Build Coastguard Worker    data.offset = valp->offset;
202*387f9dfdSAndroid Build Coastguard Worker    bpf_get_current_comm(&data.task, sizeof(data.task));
203*387f9dfdSAndroid Build Coastguard Worker
204*387f9dfdSAndroid Build Coastguard Worker    // workaround (rewriter should handle file to d_name in one step):
205*387f9dfdSAndroid Build Coastguard Worker    struct dentry *de = NULL;
206*387f9dfdSAndroid Build Coastguard Worker    struct qstr qs = {};
207*387f9dfdSAndroid Build Coastguard Worker    if(type == TRACE_GETATTR)
208*387f9dfdSAndroid Build Coastguard Worker    {
209*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&de,sizeof(de), &valp->d);
210*387f9dfdSAndroid Build Coastguard Worker    }
211*387f9dfdSAndroid Build Coastguard Worker    else
212*387f9dfdSAndroid Build Coastguard Worker    {
213*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&de, sizeof(de), &valp->fp->f_path.dentry);
214*387f9dfdSAndroid Build Coastguard Worker    }
215*387f9dfdSAndroid Build Coastguard Worker
216*387f9dfdSAndroid Build Coastguard Worker    bpf_probe_read_kernel(&qs, sizeof(qs), (void *)&de->d_name);
217*387f9dfdSAndroid Build Coastguard Worker    if (qs.len == 0)
218*387f9dfdSAndroid Build Coastguard Worker        return 0;
219*387f9dfdSAndroid Build Coastguard Worker
220*387f9dfdSAndroid Build Coastguard Worker    bpf_probe_read_kernel(&data.file, sizeof(data.file), (void *)qs.name);
221*387f9dfdSAndroid Build Coastguard Worker    // output
222*387f9dfdSAndroid Build Coastguard Worker    events.perf_submit(ctx, &data, sizeof(data));
223*387f9dfdSAndroid Build Coastguard Worker    return 0;
224*387f9dfdSAndroid Build Coastguard Worker}
225*387f9dfdSAndroid Build Coastguard Worker
226*387f9dfdSAndroid Build Coastguard Workerint trace_file_open_return(struct pt_regs *ctx)
227*387f9dfdSAndroid Build Coastguard Worker{
228*387f9dfdSAndroid Build Coastguard Worker    return trace_exit(ctx, TRACE_OPEN);
229*387f9dfdSAndroid Build Coastguard Worker}
230*387f9dfdSAndroid Build Coastguard Worker
231*387f9dfdSAndroid Build Coastguard Workerint trace_read_return(struct pt_regs *ctx)
232*387f9dfdSAndroid Build Coastguard Worker{
233*387f9dfdSAndroid Build Coastguard Worker    return trace_exit(ctx, TRACE_READ);
234*387f9dfdSAndroid Build Coastguard Worker}
235*387f9dfdSAndroid Build Coastguard Worker
236*387f9dfdSAndroid Build Coastguard Workerint trace_write_return(struct pt_regs *ctx)
237*387f9dfdSAndroid Build Coastguard Worker{
238*387f9dfdSAndroid Build Coastguard Worker    return trace_exit(ctx, TRACE_WRITE);
239*387f9dfdSAndroid Build Coastguard Worker}
240*387f9dfdSAndroid Build Coastguard Worker
241*387f9dfdSAndroid Build Coastguard Workerint trace_getattr_return(struct pt_regs *ctx)
242*387f9dfdSAndroid Build Coastguard Worker{
243*387f9dfdSAndroid Build Coastguard Worker    return trace_exit(ctx, TRACE_GETATTR);
244*387f9dfdSAndroid Build Coastguard Worker}
245*387f9dfdSAndroid Build Coastguard Worker
246*387f9dfdSAndroid Build Coastguard Workerstatic int trace_initiate_commit(struct nfs_commit_data *cd)
247*387f9dfdSAndroid Build Coastguard Worker{
248*387f9dfdSAndroid Build Coastguard Worker    u64 key = (u64)cd;
249*387f9dfdSAndroid Build Coastguard Worker    struct commit_t c = { 0 };
250*387f9dfdSAndroid Build Coastguard Worker
251*387f9dfdSAndroid Build Coastguard Worker    c.ts = bpf_ktime_get_ns();
252*387f9dfdSAndroid Build Coastguard Worker    bpf_probe_read_kernel(&c.offset, sizeof(cd->args.offset),
253*387f9dfdSAndroid Build Coastguard Worker        &cd->args.offset);
254*387f9dfdSAndroid Build Coastguard Worker    bpf_probe_read_kernel(&c.count, sizeof(cd->args.count), &cd->args.count);
255*387f9dfdSAndroid Build Coastguard Worker    commitinfo.update(&key, &c);
256*387f9dfdSAndroid Build Coastguard Worker    return 0;
257*387f9dfdSAndroid Build Coastguard Worker}
258*387f9dfdSAndroid Build Coastguard Worker
259*387f9dfdSAndroid Build Coastguard Worker"""
260*387f9dfdSAndroid Build Coastguard Worker
261*387f9dfdSAndroid Build Coastguard Workerbpf_text_raw_tp = """
262*387f9dfdSAndroid Build Coastguard WorkerRAW_TRACEPOINT_PROBE(nfs_initiate_commit)
263*387f9dfdSAndroid Build Coastguard Worker{
264*387f9dfdSAndroid Build Coastguard Worker    // TP_PROTO(const struct nfs_commit_data *data)
265*387f9dfdSAndroid Build Coastguard Worker    struct nfs_commit_data *cd = (struct nfs_commit_data *)ctx->args[0];
266*387f9dfdSAndroid Build Coastguard Worker    return trace_initiate_commit(cd);
267*387f9dfdSAndroid Build Coastguard Worker}
268*387f9dfdSAndroid Build Coastguard Worker
269*387f9dfdSAndroid Build Coastguard WorkerRAW_TRACEPOINT_PROBE(nfs_commit_done)
270*387f9dfdSAndroid Build Coastguard Worker{
271*387f9dfdSAndroid Build Coastguard Worker    // TP_PROTO(const struct rpc_task *task, const struct nfs_commit_data *data)
272*387f9dfdSAndroid Build Coastguard Worker    struct nfs_commit_data *cd = (struct nfs_commit_data *)ctx->args[1];
273*387f9dfdSAndroid Build Coastguard Worker    u64 key = (u64)cd;
274*387f9dfdSAndroid Build Coastguard Worker    struct commit_t *cp = commitinfo.lookup(&key);
275*387f9dfdSAndroid Build Coastguard Worker
276*387f9dfdSAndroid Build Coastguard Worker    if (cp) {
277*387f9dfdSAndroid Build Coastguard Worker        struct nfs_open_context *p;
278*387f9dfdSAndroid Build Coastguard Worker        struct dentry *de;
279*387f9dfdSAndroid Build Coastguard Worker        struct qstr qs;
280*387f9dfdSAndroid Build Coastguard Worker        u64 ts = bpf_ktime_get_ns();
281*387f9dfdSAndroid Build Coastguard Worker        u64 delta_us = (ts - cp->ts) / 1000;
282*387f9dfdSAndroid Build Coastguard Worker        u32 pid = bpf_get_current_pid_tgid() >> 32;
283*387f9dfdSAndroid Build Coastguard Worker
284*387f9dfdSAndroid Build Coastguard Worker        struct data_t data = {};
285*387f9dfdSAndroid Build Coastguard Worker        data.type = TRACE_COMMIT;
286*387f9dfdSAndroid Build Coastguard Worker        data.offset = cp->offset;
287*387f9dfdSAndroid Build Coastguard Worker        data.size = cp->count;
288*387f9dfdSAndroid Build Coastguard Worker        data.ts_us = ts/1000;
289*387f9dfdSAndroid Build Coastguard Worker        data.delta_us = delta_us;
290*387f9dfdSAndroid Build Coastguard Worker        data.pid = pid;
291*387f9dfdSAndroid Build Coastguard Worker
292*387f9dfdSAndroid Build Coastguard Worker        commitinfo.delete(&key);
293*387f9dfdSAndroid Build Coastguard Worker        bpf_get_current_comm(&data.task, sizeof(data.task));
294*387f9dfdSAndroid Build Coastguard Worker
295*387f9dfdSAndroid Build Coastguard Worker        if(FILTER_PID)
296*387f9dfdSAndroid Build Coastguard Worker            return 0;
297*387f9dfdSAndroid Build Coastguard Worker
298*387f9dfdSAndroid Build Coastguard Worker        if (FILTER_US)
299*387f9dfdSAndroid Build Coastguard Worker            return 0;
300*387f9dfdSAndroid Build Coastguard Worker
301*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&p, sizeof(p), &cd->context);
302*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&de, sizeof(de), &p->dentry);
303*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&qs, sizeof(qs), &de->d_name);
304*387f9dfdSAndroid Build Coastguard Worker        if (qs.len) {
305*387f9dfdSAndroid Build Coastguard Worker            bpf_probe_read_kernel(&data.file, sizeof(data.file),
306*387f9dfdSAndroid Build Coastguard Worker                (void *)qs.name);
307*387f9dfdSAndroid Build Coastguard Worker            events.perf_submit(ctx, &data, sizeof(data));
308*387f9dfdSAndroid Build Coastguard Worker        }
309*387f9dfdSAndroid Build Coastguard Worker    }
310*387f9dfdSAndroid Build Coastguard Worker    return 0;
311*387f9dfdSAndroid Build Coastguard Worker}
312*387f9dfdSAndroid Build Coastguard Worker"""
313*387f9dfdSAndroid Build Coastguard Worker
314*387f9dfdSAndroid Build Coastguard Workerbpf_text_kprobe = """
315*387f9dfdSAndroid Build Coastguard Workerint trace_nfs_initiate_commit(struct pt_regs *ctx, void *clnt, struct nfs_commit_data *cd)
316*387f9dfdSAndroid Build Coastguard Worker{
317*387f9dfdSAndroid Build Coastguard Worker    return trace_initiate_commit(cd);
318*387f9dfdSAndroid Build Coastguard Worker}
319*387f9dfdSAndroid Build Coastguard Worker
320*387f9dfdSAndroid Build Coastguard Workerint trace_nfs_commit_done(struct pt_regs *ctx, void *task, void *calldata)
321*387f9dfdSAndroid Build Coastguard Worker{
322*387f9dfdSAndroid Build Coastguard Worker    struct nfs_commit_data *cd = (struct nfs_commit_data *)calldata;
323*387f9dfdSAndroid Build Coastguard Worker    u64 key = (u64)cd;
324*387f9dfdSAndroid Build Coastguard Worker    struct commit_t *cp = commitinfo.lookup(&key);
325*387f9dfdSAndroid Build Coastguard Worker
326*387f9dfdSAndroid Build Coastguard Worker    if (cp) {
327*387f9dfdSAndroid Build Coastguard Worker        struct nfs_open_context *p;
328*387f9dfdSAndroid Build Coastguard Worker        struct dentry *de;
329*387f9dfdSAndroid Build Coastguard Worker        struct qstr qs;
330*387f9dfdSAndroid Build Coastguard Worker        u64 ts = bpf_ktime_get_ns();
331*387f9dfdSAndroid Build Coastguard Worker        u64 delta_us = (ts - cp->ts) / 1000;
332*387f9dfdSAndroid Build Coastguard Worker        u32 pid = bpf_get_current_pid_tgid() >> 32;
333*387f9dfdSAndroid Build Coastguard Worker
334*387f9dfdSAndroid Build Coastguard Worker        struct data_t data = {};
335*387f9dfdSAndroid Build Coastguard Worker        data.type = TRACE_COMMIT;
336*387f9dfdSAndroid Build Coastguard Worker        data.offset = cp->offset;
337*387f9dfdSAndroid Build Coastguard Worker        data.size = cp->count;
338*387f9dfdSAndroid Build Coastguard Worker        data.ts_us = ts/1000;
339*387f9dfdSAndroid Build Coastguard Worker        data.delta_us = delta_us;
340*387f9dfdSAndroid Build Coastguard Worker        data.pid = pid;
341*387f9dfdSAndroid Build Coastguard Worker
342*387f9dfdSAndroid Build Coastguard Worker        commitinfo.delete(&key);
343*387f9dfdSAndroid Build Coastguard Worker        bpf_get_current_comm(&data.task, sizeof(data.task));
344*387f9dfdSAndroid Build Coastguard Worker
345*387f9dfdSAndroid Build Coastguard Worker        if(FILTER_PID)
346*387f9dfdSAndroid Build Coastguard Worker            return 0;
347*387f9dfdSAndroid Build Coastguard Worker
348*387f9dfdSAndroid Build Coastguard Worker        if (FILTER_US)
349*387f9dfdSAndroid Build Coastguard Worker            return 0;
350*387f9dfdSAndroid Build Coastguard Worker
351*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&p, sizeof(p), &cd->context);
352*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&de, sizeof(de), &p->dentry);
353*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&qs, sizeof(qs), &de->d_name);
354*387f9dfdSAndroid Build Coastguard Worker        if (qs.len) {
355*387f9dfdSAndroid Build Coastguard Worker            bpf_probe_read_kernel(&data.file, sizeof(data.file),
356*387f9dfdSAndroid Build Coastguard Worker                (void *)qs.name);
357*387f9dfdSAndroid Build Coastguard Worker            events.perf_submit(ctx, &data, sizeof(data));
358*387f9dfdSAndroid Build Coastguard Worker        }
359*387f9dfdSAndroid Build Coastguard Worker    }
360*387f9dfdSAndroid Build Coastguard Worker    return 0;
361*387f9dfdSAndroid Build Coastguard Worker}
362*387f9dfdSAndroid Build Coastguard Worker"""
363*387f9dfdSAndroid Build Coastguard Workeris_support_raw_tp = BPF.support_raw_tracepoint()
364*387f9dfdSAndroid Build Coastguard Workerif is_support_raw_tp:
365*387f9dfdSAndroid Build Coastguard Worker    bpf_text += bpf_text_raw_tp
366*387f9dfdSAndroid Build Coastguard Workerelse:
367*387f9dfdSAndroid Build Coastguard Worker    bpf_text += bpf_text_kprobe
368*387f9dfdSAndroid Build Coastguard Worker
369*387f9dfdSAndroid Build Coastguard Workerif min_ms == 0:
370*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER_US', '0')
371*387f9dfdSAndroid Build Coastguard Workerelse:
372*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER_US',
373*387f9dfdSAndroid Build Coastguard Worker                                'delta_us <= %s' % str(min_ms * 1000))
374*387f9dfdSAndroid Build Coastguard Workerif args.pid:
375*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER_PID', 'pid != %s' % pid)
376*387f9dfdSAndroid Build Coastguard Workerelse:
377*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER_PID', '0')
378*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf:
379*387f9dfdSAndroid Build Coastguard Worker    print(bpf_text)
380*387f9dfdSAndroid Build Coastguard Worker    if args.ebpf:
381*387f9dfdSAndroid Build Coastguard Worker        exit()
382*387f9dfdSAndroid Build Coastguard Worker
383*387f9dfdSAndroid Build Coastguard Worker# process event
384*387f9dfdSAndroid Build Coastguard Workerdef print_event(cpu, data, size):
385*387f9dfdSAndroid Build Coastguard Worker    event = b["events"].event(data)
386*387f9dfdSAndroid Build Coastguard Worker
387*387f9dfdSAndroid Build Coastguard Worker    type = 'R'
388*387f9dfdSAndroid Build Coastguard Worker    if event.type == 1:
389*387f9dfdSAndroid Build Coastguard Worker        type = 'W'
390*387f9dfdSAndroid Build Coastguard Worker    elif event.type == 2:
391*387f9dfdSAndroid Build Coastguard Worker        type = 'O'
392*387f9dfdSAndroid Build Coastguard Worker    elif event.type == 3:
393*387f9dfdSAndroid Build Coastguard Worker        type = 'G'
394*387f9dfdSAndroid Build Coastguard Worker    elif event.type == 4:
395*387f9dfdSAndroid Build Coastguard Worker        type = 'C'
396*387f9dfdSAndroid Build Coastguard Worker
397*387f9dfdSAndroid Build Coastguard Worker    if(csv):
398*387f9dfdSAndroid Build Coastguard Worker        print("%d,%s,%d,%s,%d,%d,%d,%s" % (
399*387f9dfdSAndroid Build Coastguard Worker            event.ts_us, event.task, event.pid, type, event.size,
400*387f9dfdSAndroid Build Coastguard Worker            event.offset, event.delta_us, event.file))
401*387f9dfdSAndroid Build Coastguard Worker        return
402*387f9dfdSAndroid Build Coastguard Worker    print("%-8s %-14.14s %-6s %1s %-7s %-8d %7.2f %s" %
403*387f9dfdSAndroid Build Coastguard Worker          (strftime("%H:%M:%S"),
404*387f9dfdSAndroid Build Coastguard Worker           event.task.decode('utf-8', 'replace'),
405*387f9dfdSAndroid Build Coastguard Worker           event.pid,
406*387f9dfdSAndroid Build Coastguard Worker           type,
407*387f9dfdSAndroid Build Coastguard Worker           event.size,
408*387f9dfdSAndroid Build Coastguard Worker           event.offset / 1024,
409*387f9dfdSAndroid Build Coastguard Worker           float(event.delta_us) / 1000,
410*387f9dfdSAndroid Build Coastguard Worker           event.file.decode('utf-8', 'replace')))
411*387f9dfdSAndroid Build Coastguard Worker
412*387f9dfdSAndroid Build Coastguard Worker
413*387f9dfdSAndroid Build Coastguard Worker# Currently specifically works for NFSv4, the other kprobes are generic
414*387f9dfdSAndroid Build Coastguard Worker# so it should work with earlier NFS versions
415*387f9dfdSAndroid Build Coastguard Worker
416*387f9dfdSAndroid Build Coastguard Worker# The following warning is shown on kernels after linux-5.18 when using bcc.
417*387f9dfdSAndroid Build Coastguard Worker# Add compile option to silence it.
418*387f9dfdSAndroid Build Coastguard Worker#   In file included from /virtual/main.c:7:
419*387f9dfdSAndroid Build Coastguard Worker#   In file included from include/linux/nfs_fs.h:31:
420*387f9dfdSAndroid Build Coastguard Worker#   In file included from include/linux/sunrpc/auth.h:13:
421*387f9dfdSAndroid Build Coastguard Worker#   In file included from include/linux/sunrpc/sched.h:19:
422*387f9dfdSAndroid Build Coastguard Worker#   include/linux/sunrpc/xdr.h:751:10: warning: result of comparison of constant 4611686018427387903 with expression of type '__u32' (aka 'unsigned int') is always false [-Wtautological-constant-out-of-range-compare]
423*387f9dfdSAndroid Build Coastguard Worker#           if (len > SIZE_MAX / sizeof(*p))
424*387f9dfdSAndroid Build Coastguard Worker#               ~~~ ^ ~~~~~~~~~~~~~~~~~~~~~
425*387f9dfdSAndroid Build Coastguard Worker#   1 warning generated.
426*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text,
427*387f9dfdSAndroid Build Coastguard Worker    cflags=["-Wno-tautological-constant-out-of-range-compare"])
428*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="nfs_file_read", fn_name="trace_rw_entry")
429*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="nfs_file_write", fn_name="trace_rw_entry")
430*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="nfs_file_open", fn_name="trace_file_open_entry")
431*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="nfs_getattr", fn_name="trace_getattr_entry")
432*387f9dfdSAndroid Build Coastguard Worker
433*387f9dfdSAndroid Build Coastguard Workerb.attach_kretprobe(event="nfs_file_read", fn_name="trace_read_return")
434*387f9dfdSAndroid Build Coastguard Workerb.attach_kretprobe(event="nfs_file_write", fn_name="trace_write_return")
435*387f9dfdSAndroid Build Coastguard Workerb.attach_kretprobe(event="nfs_file_open", fn_name="trace_file_open_return")
436*387f9dfdSAndroid Build Coastguard Workerb.attach_kretprobe(event="nfs_getattr", fn_name="trace_getattr_return")
437*387f9dfdSAndroid Build Coastguard Worker
438*387f9dfdSAndroid Build Coastguard Workerif BPF.get_kprobe_functions(b'nfs4_file_open'):
439*387f9dfdSAndroid Build Coastguard Worker    b.attach_kprobe(event="nfs4_file_open", fn_name="trace_file_open_entry")
440*387f9dfdSAndroid Build Coastguard Worker    b.attach_kretprobe(event="nfs4_file_open", fn_name="trace_file_open_return")
441*387f9dfdSAndroid Build Coastguard Worker
442*387f9dfdSAndroid Build Coastguard Workerif not is_support_raw_tp:
443*387f9dfdSAndroid Build Coastguard Worker    b.attach_kprobe(event="nfs_initiate_commit",
444*387f9dfdSAndroid Build Coastguard Worker                    fn_name="trace_nfs_initiate_commit")
445*387f9dfdSAndroid Build Coastguard Worker    b.attach_kprobe(event="nfs_commit_done",
446*387f9dfdSAndroid Build Coastguard Worker                    fn_name="trace_nfs_commit_done")
447*387f9dfdSAndroid Build Coastguard Worker
448*387f9dfdSAndroid Build Coastguard Workerif(csv):
449*387f9dfdSAndroid Build Coastguard Worker    print("ENDTIME_us,TASK,PID,TYPE,BYTES,OFFSET_b,LATENCY_us,FILE")
450*387f9dfdSAndroid Build Coastguard Workerelse:
451*387f9dfdSAndroid Build Coastguard Worker    if min_ms == 0:
452*387f9dfdSAndroid Build Coastguard Worker        print("Tracing NFS operations... Ctrl-C to quit")
453*387f9dfdSAndroid Build Coastguard Worker    else:
454*387f9dfdSAndroid Build Coastguard Worker        print("""Tracing NFS operations that are slower than \
455*387f9dfdSAndroid Build Coastguard Worker%d ms... Ctrl-C to quit"""
456*387f9dfdSAndroid Build Coastguard Worker              % min_ms)
457*387f9dfdSAndroid Build Coastguard Worker    print("%-8s %-14s %-6s %1s %-7s %-8s %7s %s" % ("TIME",
458*387f9dfdSAndroid Build Coastguard Worker                                                    "COMM",
459*387f9dfdSAndroid Build Coastguard Worker                                                    "PID",
460*387f9dfdSAndroid Build Coastguard Worker                                                    "T",
461*387f9dfdSAndroid Build Coastguard Worker                                                    "BYTES",
462*387f9dfdSAndroid Build Coastguard Worker                                                    "OFF_KB",
463*387f9dfdSAndroid Build Coastguard Worker                                                    "LAT(ms)",
464*387f9dfdSAndroid Build Coastguard Worker                                                    "FILENAME"))
465*387f9dfdSAndroid Build Coastguard Worker
466*387f9dfdSAndroid Build Coastguard Workerb["events"].open_perf_buffer(print_event, page_cnt=64)
467*387f9dfdSAndroid Build Coastguard Workerwhile 1:
468*387f9dfdSAndroid Build Coastguard Worker    try:
469*387f9dfdSAndroid Build Coastguard Worker        b.perf_buffer_poll()
470*387f9dfdSAndroid Build Coastguard Worker    except KeyboardInterrupt:
471*387f9dfdSAndroid Build Coastguard Worker        exit()
472