blob: 74a3914aa944e867efbfb54a8e187623dccf890a [file] [log] [blame]
Alexey Ivanovcc01a9c2019-01-16 09:50:46 -08001#!/usr/bin/python
Brendan Gregg2757f0e2016-02-10 01:38:32 -08002# @lint-avoid-python-3-compatibility-imports
3#
4# dcsnoop Trace directory entry cache (dcache) lookups.
5# For Linux, uses BCC, eBPF. Embedded C.
6#
7# USAGE: dcsnoop [-h] [-a]
8#
9# By default, this traces every failed dcache lookup, and shows the process
10# performing the lookup and the filename requested. A -a option can be used
11# to show all lookups, not just failed ones.
12#
13# This uses kernel dynamic tracing of the d_lookup() function, and will need
14# to be modified to match kernel changes.
15#
16# Also see dcstat(8), for per-second summaries.
17#
18# Copyright 2016 Netflix, Inc.
19# Licensed under the Apache License, Version 2.0 (the "License")
20#
21# 09-Feb-2016 Brendan Gregg Created this.
22
23from __future__ import print_function
24from bcc import BPF
25import argparse
26import re
Mark Drayton44b4b5f2016-07-13 18:15:05 +010027import time
Brendan Gregg2757f0e2016-02-10 01:38:32 -080028
29# arguments
30examples = """examples:
31 ./dcsnoop # trace failed dcache lookups
32 ./dcsnoop -a # trace all dcache lookups
33"""
34parser = argparse.ArgumentParser(
35 description="Trace directory entry cache (dcache) lookups",
36 formatter_class=argparse.RawDescriptionHelpFormatter,
37 epilog=examples)
38parser.add_argument("-a", "--all", action="store_true",
39 help="trace all lookups (default is fails only)")
Nathan Scottcf0792f2018-02-02 16:56:50 +110040parser.add_argument("--ebpf", action="store_true",
41 help=argparse.SUPPRESS)
Brendan Gregg2757f0e2016-02-10 01:38:32 -080042args = parser.parse_args()
43
44# define BPF program
45bpf_text = """
46#include <uapi/linux/ptrace.h>
47#include <linux/fs.h>
48#include <linux/sched.h>
49
50#define MAX_FILE_LEN 64
51
Mark Drayton44b4b5f2016-07-13 18:15:05 +010052enum lookup_type {
53 LOOKUP_MISS,
54 LOOKUP_REFERENCE,
55};
56
Brendan Gregg2757f0e2016-02-10 01:38:32 -080057struct entry_t {
58 char name[MAX_FILE_LEN];
59};
60
61BPF_HASH(entrybypid, u32, struct entry_t);
62
Mark Drayton44b4b5f2016-07-13 18:15:05 +010063struct data_t {
64 u32 pid;
65 enum lookup_type type;
66 char comm[TASK_COMM_LEN];
67 char filename[MAX_FILE_LEN];
68};
69
70BPF_PERF_OUTPUT(events);
71
Brendan Gregg2757f0e2016-02-10 01:38:32 -080072/* from fs/namei.c: */
73struct nameidata {
74 struct path path;
75 struct qstr last;
76 // [...]
77};
78
Mark Drayton44b4b5f2016-07-13 18:15:05 +010079static inline
80void submit_event(struct pt_regs *ctx, void *name, int type, u32 pid)
81{
82 struct data_t data = {
83 .pid = pid,
84 .type = type,
85 };
86 bpf_get_current_comm(&data.comm, sizeof(data.comm));
Sumanth Korikkar7f6066d2020-05-20 10:49:56 -050087 bpf_probe_read_kernel(&data.filename, sizeof(data.filename), name);
Mark Drayton44b4b5f2016-07-13 18:15:05 +010088 events.perf_submit(ctx, &data, sizeof(data));
89}
90
Brendan Gregg2757f0e2016-02-10 01:38:32 -080091int trace_fast(struct pt_regs *ctx, struct nameidata *nd, struct path *path)
92{
Hengqi Chenf0a0dc72021-05-20 22:49:25 +080093 u32 pid = bpf_get_current_pid_tgid() >> 32;
Mark Drayton44b4b5f2016-07-13 18:15:05 +010094 submit_event(ctx, (void *)nd->last.name, LOOKUP_REFERENCE, pid);
Brendan Gregg2757f0e2016-02-10 01:38:32 -080095 return 1;
96}
97
98int kprobe__d_lookup(struct pt_regs *ctx, const struct dentry *parent,
99 const struct qstr *name)
100{
Hengqi Chenf0a0dc72021-05-20 22:49:25 +0800101 u32 tid = bpf_get_current_pid_tgid();
Brendan Gregg2757f0e2016-02-10 01:38:32 -0800102 struct entry_t entry = {};
Brendan Greggd18657e2016-02-10 16:38:18 -0800103 const char *fname = name->name;
104 if (fname) {
Sumanth Korikkar7f6066d2020-05-20 10:49:56 -0500105 bpf_probe_read_kernel(&entry.name, sizeof(entry.name), (void *)fname);
Brendan Gregg2757f0e2016-02-10 01:38:32 -0800106 }
Hengqi Chenf0a0dc72021-05-20 22:49:25 +0800107 entrybypid.update(&tid, &entry);
Brendan Gregg2757f0e2016-02-10 01:38:32 -0800108 return 0;
109}
110
111int kretprobe__d_lookup(struct pt_regs *ctx)
112{
Hengqi Chenf0a0dc72021-05-20 22:49:25 +0800113 u64 pid_tgid = bpf_get_current_pid_tgid();
114 u32 pid = pid_tgid >> 32;
115 u32 tid = (u32)pid_tgid;
Brendan Gregg2757f0e2016-02-10 01:38:32 -0800116 struct entry_t *ep;
Hengqi Chenf0a0dc72021-05-20 22:49:25 +0800117
118 ep = entrybypid.lookup(&tid);
119 if (ep == 0) {
120 return 0; // missed entry
Brendan Gregg2757f0e2016-02-10 01:38:32 -0800121 }
Hengqi Chenf0a0dc72021-05-20 22:49:25 +0800122 if (PT_REGS_RC(ctx) != 0) {
123 entrybypid.delete(&tid);
124 return 0; // lookup didn't fail
125 }
126
Mark Drayton44b4b5f2016-07-13 18:15:05 +0100127 submit_event(ctx, (void *)ep->name, LOOKUP_MISS, pid);
Hengqi Chenf0a0dc72021-05-20 22:49:25 +0800128 entrybypid.delete(&tid);
Brendan Gregg2757f0e2016-02-10 01:38:32 -0800129 return 0;
130}
131"""
132
Nathan Scottcf0792f2018-02-02 16:56:50 +1100133if args.ebpf:
134 print(bpf_text)
135 exit()
136
Brendan Gregg2757f0e2016-02-10 01:38:32 -0800137# initialize BPF
138b = BPF(text=bpf_text)
139if args.all:
Jerome Marchandcdfddc42021-03-20 14:33:59 +0100140 b.attach_kprobe(event_re="^lookup_fast$|^lookup_fast.constprop.*.\d$", fn_name="trace_fast")
Brendan Gregg2757f0e2016-02-10 01:38:32 -0800141
Mark Drayton44b4b5f2016-07-13 18:15:05 +0100142mode_s = {
143 0: 'M',
144 1: 'R',
145}
146
147start_ts = time.time()
148
149def print_event(cpu, data, size):
Xiaozhou Liu6c79c682019-02-15 03:41:22 +0800150 event = b["events"].event(data)
xingfeng251003e49482022-03-17 13:07:16 +0800151 print("%-11.6f %-7d %-16s %1s %s" % (
jeromemarchandb96ebcd2018-10-10 01:58:15 +0200152 time.time() - start_ts, event.pid,
153 event.comm.decode('utf-8', 'replace'), mode_s[event.type],
154 event.filename.decode('utf-8', 'replace')))
Mark Drayton44b4b5f2016-07-13 18:15:05 +0100155
Brendan Gregg2757f0e2016-02-10 01:38:32 -0800156# header
xingfeng251003e49482022-03-17 13:07:16 +0800157print("%-11s %-7s %-16s %1s %s" % ("TIME(s)", "PID", "COMM", "T", "FILE"))
Brendan Gregg2757f0e2016-02-10 01:38:32 -0800158
Mark Drayton5f5687e2017-02-20 18:13:03 +0000159b["events"].open_perf_buffer(print_event, page_cnt=64)
Brendan Gregg2757f0e2016-02-10 01:38:32 -0800160while 1:
Jerome Marchand51671272018-12-19 01:57:24 +0100161 try:
162 b.perf_buffer_poll()
163 except KeyboardInterrupt:
164 exit()