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# dcsnoop Trace directory entry cache (dcache) lookups. 5*387f9dfdSAndroid Build Coastguard Worker# For Linux, uses BCC, eBPF. Embedded C. 6*387f9dfdSAndroid Build Coastguard Worker# 7*387f9dfdSAndroid Build Coastguard Worker# USAGE: dcsnoop [-h] [-a] 8*387f9dfdSAndroid Build Coastguard Worker# 9*387f9dfdSAndroid Build Coastguard Worker# By default, this traces every failed dcache lookup, and shows the process 10*387f9dfdSAndroid Build Coastguard Worker# performing the lookup and the filename requested. A -a option can be used 11*387f9dfdSAndroid Build Coastguard Worker# to show all lookups, not just failed ones. 12*387f9dfdSAndroid Build Coastguard Worker# 13*387f9dfdSAndroid Build Coastguard Worker# This uses kernel dynamic tracing of the d_lookup() function, and will need 14*387f9dfdSAndroid Build Coastguard Worker# to be modified to match kernel changes. 15*387f9dfdSAndroid Build Coastguard Worker# 16*387f9dfdSAndroid Build Coastguard Worker# Also see dcstat(8), for per-second summaries. 17*387f9dfdSAndroid Build Coastguard Worker# 18*387f9dfdSAndroid Build Coastguard Worker# Copyright 2016 Netflix, Inc. 19*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License") 20*387f9dfdSAndroid Build Coastguard Worker# 21*387f9dfdSAndroid Build Coastguard Worker# 09-Feb-2016 Brendan Gregg Created this. 22*387f9dfdSAndroid Build Coastguard Worker 23*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 24*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF 25*387f9dfdSAndroid Build Coastguard Workerimport argparse 26*387f9dfdSAndroid Build Coastguard Workerimport re 27*387f9dfdSAndroid Build Coastguard Workerimport time 28*387f9dfdSAndroid Build Coastguard Worker 29*387f9dfdSAndroid Build Coastguard Worker# arguments 30*387f9dfdSAndroid Build Coastguard Workerexamples = """examples: 31*387f9dfdSAndroid Build Coastguard Worker ./dcsnoop # trace failed dcache lookups 32*387f9dfdSAndroid Build Coastguard Worker ./dcsnoop -a # trace all dcache lookups 33*387f9dfdSAndroid Build Coastguard Worker""" 34*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser( 35*387f9dfdSAndroid Build Coastguard Worker description="Trace directory entry cache (dcache) lookups", 36*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 37*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 38*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-a", "--all", action="store_true", 39*387f9dfdSAndroid Build Coastguard Worker help="trace all lookups (default is fails only)") 40*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true", 41*387f9dfdSAndroid Build Coastguard Worker help=argparse.SUPPRESS) 42*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 43*387f9dfdSAndroid Build Coastguard Worker 44*387f9dfdSAndroid Build Coastguard Worker# define BPF program 45*387f9dfdSAndroid Build Coastguard Workerbpf_text = """ 46*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h> 47*387f9dfdSAndroid Build Coastguard Worker#include <linux/fs.h> 48*387f9dfdSAndroid Build Coastguard Worker#include <linux/sched.h> 49*387f9dfdSAndroid Build Coastguard Worker 50*387f9dfdSAndroid Build Coastguard Worker#define MAX_FILE_LEN 64 51*387f9dfdSAndroid Build Coastguard Worker 52*387f9dfdSAndroid Build Coastguard Workerenum lookup_type { 53*387f9dfdSAndroid Build Coastguard Worker LOOKUP_MISS, 54*387f9dfdSAndroid Build Coastguard Worker LOOKUP_REFERENCE, 55*387f9dfdSAndroid Build Coastguard Worker}; 56*387f9dfdSAndroid Build Coastguard Worker 57*387f9dfdSAndroid Build Coastguard Workerstruct entry_t { 58*387f9dfdSAndroid Build Coastguard Worker char name[MAX_FILE_LEN]; 59*387f9dfdSAndroid Build Coastguard Worker}; 60*387f9dfdSAndroid Build Coastguard Worker 61*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(entrybypid, u32, struct entry_t); 62*387f9dfdSAndroid Build Coastguard Worker 63*387f9dfdSAndroid Build Coastguard Workerstruct data_t { 64*387f9dfdSAndroid Build Coastguard Worker u32 pid; 65*387f9dfdSAndroid Build Coastguard Worker enum lookup_type type; 66*387f9dfdSAndroid Build Coastguard Worker char comm[TASK_COMM_LEN]; 67*387f9dfdSAndroid Build Coastguard Worker char filename[MAX_FILE_LEN]; 68*387f9dfdSAndroid Build Coastguard Worker}; 69*387f9dfdSAndroid Build Coastguard Worker 70*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(events); 71*387f9dfdSAndroid Build Coastguard Worker 72*387f9dfdSAndroid Build Coastguard Worker/* from fs/namei.c: */ 73*387f9dfdSAndroid Build Coastguard Workerstruct nameidata { 74*387f9dfdSAndroid Build Coastguard Worker struct path path; 75*387f9dfdSAndroid Build Coastguard Worker struct qstr last; 76*387f9dfdSAndroid Build Coastguard Worker // [...] 77*387f9dfdSAndroid Build Coastguard Worker}; 78*387f9dfdSAndroid Build Coastguard Worker 79*387f9dfdSAndroid Build Coastguard Workerstatic inline 80*387f9dfdSAndroid Build Coastguard Workervoid submit_event(struct pt_regs *ctx, void *name, int type, u32 pid) 81*387f9dfdSAndroid Build Coastguard Worker{ 82*387f9dfdSAndroid Build Coastguard Worker struct data_t data = { 83*387f9dfdSAndroid Build Coastguard Worker .pid = pid, 84*387f9dfdSAndroid Build Coastguard Worker .type = type, 85*387f9dfdSAndroid Build Coastguard Worker }; 86*387f9dfdSAndroid Build Coastguard Worker bpf_get_current_comm(&data.comm, sizeof(data.comm)); 87*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&data.filename, sizeof(data.filename), name); 88*387f9dfdSAndroid Build Coastguard Worker events.perf_submit(ctx, &data, sizeof(data)); 89*387f9dfdSAndroid Build Coastguard Worker} 90*387f9dfdSAndroid Build Coastguard Worker 91*387f9dfdSAndroid Build Coastguard Workerint trace_fast(struct pt_regs *ctx, struct nameidata *nd, struct path *path) 92*387f9dfdSAndroid Build Coastguard Worker{ 93*387f9dfdSAndroid Build Coastguard Worker u32 pid = bpf_get_current_pid_tgid() >> 32; 94*387f9dfdSAndroid Build Coastguard Worker submit_event(ctx, (void *)nd->last.name, LOOKUP_REFERENCE, pid); 95*387f9dfdSAndroid Build Coastguard Worker return 1; 96*387f9dfdSAndroid Build Coastguard Worker} 97*387f9dfdSAndroid Build Coastguard Worker 98*387f9dfdSAndroid Build Coastguard Workerint kprobe__d_lookup(struct pt_regs *ctx, const struct dentry *parent, 99*387f9dfdSAndroid Build Coastguard Worker const struct qstr *name) 100*387f9dfdSAndroid Build Coastguard Worker{ 101*387f9dfdSAndroid Build Coastguard Worker u32 tid = bpf_get_current_pid_tgid(); 102*387f9dfdSAndroid Build Coastguard Worker struct entry_t entry = {}; 103*387f9dfdSAndroid Build Coastguard Worker const char *fname = name->name; 104*387f9dfdSAndroid Build Coastguard Worker if (fname) { 105*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&entry.name, sizeof(entry.name), (void *)fname); 106*387f9dfdSAndroid Build Coastguard Worker } 107*387f9dfdSAndroid Build Coastguard Worker entrybypid.update(&tid, &entry); 108*387f9dfdSAndroid Build Coastguard Worker return 0; 109*387f9dfdSAndroid Build Coastguard Worker} 110*387f9dfdSAndroid Build Coastguard Worker 111*387f9dfdSAndroid Build Coastguard Workerint kretprobe__d_lookup(struct pt_regs *ctx) 112*387f9dfdSAndroid Build Coastguard Worker{ 113*387f9dfdSAndroid Build Coastguard Worker u64 pid_tgid = bpf_get_current_pid_tgid(); 114*387f9dfdSAndroid Build Coastguard Worker u32 pid = pid_tgid >> 32; 115*387f9dfdSAndroid Build Coastguard Worker u32 tid = (u32)pid_tgid; 116*387f9dfdSAndroid Build Coastguard Worker struct entry_t *ep; 117*387f9dfdSAndroid Build Coastguard Worker 118*387f9dfdSAndroid Build Coastguard Worker ep = entrybypid.lookup(&tid); 119*387f9dfdSAndroid Build Coastguard Worker if (ep == 0) { 120*387f9dfdSAndroid Build Coastguard Worker return 0; // missed entry 121*387f9dfdSAndroid Build Coastguard Worker } 122*387f9dfdSAndroid Build Coastguard Worker if (PT_REGS_RC(ctx) != 0) { 123*387f9dfdSAndroid Build Coastguard Worker entrybypid.delete(&tid); 124*387f9dfdSAndroid Build Coastguard Worker return 0; // lookup didn't fail 125*387f9dfdSAndroid Build Coastguard Worker } 126*387f9dfdSAndroid Build Coastguard Worker 127*387f9dfdSAndroid Build Coastguard Worker submit_event(ctx, (void *)ep->name, LOOKUP_MISS, pid); 128*387f9dfdSAndroid Build Coastguard Worker entrybypid.delete(&tid); 129*387f9dfdSAndroid Build Coastguard Worker return 0; 130*387f9dfdSAndroid Build Coastguard Worker} 131*387f9dfdSAndroid Build Coastguard Worker""" 132*387f9dfdSAndroid Build Coastguard Worker 133*387f9dfdSAndroid Build Coastguard Workerif args.ebpf: 134*387f9dfdSAndroid Build Coastguard Worker print(bpf_text) 135*387f9dfdSAndroid Build Coastguard Worker exit() 136*387f9dfdSAndroid Build Coastguard Worker 137*387f9dfdSAndroid Build Coastguard Worker# initialize BPF 138*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text) 139*387f9dfdSAndroid Build Coastguard Workerif args.all: 140*387f9dfdSAndroid Build Coastguard Worker b.attach_kprobe(event_re="^lookup_fast$|^lookup_fast.constprop.*.\d$", fn_name="trace_fast") 141*387f9dfdSAndroid Build Coastguard Worker 142*387f9dfdSAndroid Build Coastguard Workermode_s = { 143*387f9dfdSAndroid Build Coastguard Worker 0: 'M', 144*387f9dfdSAndroid Build Coastguard Worker 1: 'R', 145*387f9dfdSAndroid Build Coastguard Worker} 146*387f9dfdSAndroid Build Coastguard Worker 147*387f9dfdSAndroid Build Coastguard Workerstart_ts = time.time() 148*387f9dfdSAndroid Build Coastguard Worker 149*387f9dfdSAndroid Build Coastguard Workerdef print_event(cpu, data, size): 150*387f9dfdSAndroid Build Coastguard Worker event = b["events"].event(data) 151*387f9dfdSAndroid Build Coastguard Worker print("%-11.6f %-7d %-16s %1s %s" % ( 152*387f9dfdSAndroid Build Coastguard Worker time.time() - start_ts, event.pid, 153*387f9dfdSAndroid Build Coastguard Worker event.comm.decode('utf-8', 'replace'), mode_s[event.type], 154*387f9dfdSAndroid Build Coastguard Worker event.filename.decode('utf-8', 'replace'))) 155*387f9dfdSAndroid Build Coastguard Worker 156*387f9dfdSAndroid Build Coastguard Worker# header 157*387f9dfdSAndroid Build Coastguard Workerprint("%-11s %-7s %-16s %1s %s" % ("TIME(s)", "PID", "COMM", "T", "FILE")) 158*387f9dfdSAndroid Build Coastguard Worker 159*387f9dfdSAndroid Build Coastguard Workerb["events"].open_perf_buffer(print_event, page_cnt=64) 160*387f9dfdSAndroid Build Coastguard Workerwhile 1: 161*387f9dfdSAndroid Build Coastguard Worker try: 162*387f9dfdSAndroid Build Coastguard Worker b.perf_buffer_poll() 163*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 164*387f9dfdSAndroid Build Coastguard Worker exit() 165