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# fileslower Trace slow synchronous file reads and writes. 5*387f9dfdSAndroid Build Coastguard Worker# For Linux, uses BCC, eBPF. 6*387f9dfdSAndroid Build Coastguard Worker# 7*387f9dfdSAndroid Build Coastguard Worker# USAGE: fileslower [-h] [-p PID] [-a] [min_ms] 8*387f9dfdSAndroid Build Coastguard Worker# 9*387f9dfdSAndroid Build Coastguard Worker# This script uses kernel dynamic tracing of synchronous reads and writes 10*387f9dfdSAndroid Build Coastguard Worker# at the VFS interface, to identify slow file reads and writes for any file 11*387f9dfdSAndroid Build Coastguard Worker# system. 12*387f9dfdSAndroid Build Coastguard Worker# 13*387f9dfdSAndroid Build Coastguard Worker# This works by tracing __vfs_read() and __vfs_write(), and filtering for 14*387f9dfdSAndroid Build Coastguard Worker# synchronous I/O (the path to new_sync_read() and new_sync_write()), and 15*387f9dfdSAndroid Build Coastguard Worker# for I/O with filenames. This approach provides a view of just two file 16*387f9dfdSAndroid Build Coastguard Worker# system request types. There are typically many others: asynchronous I/O, 17*387f9dfdSAndroid Build Coastguard Worker# directory operations, file handle operations, etc, that this tool does not 18*387f9dfdSAndroid Build Coastguard Worker# instrument. 19*387f9dfdSAndroid Build Coastguard Worker# 20*387f9dfdSAndroid Build Coastguard Worker# WARNING: This traces VFS reads and writes, which can be extremely frequent, 21*387f9dfdSAndroid Build Coastguard Worker# and so the overhead of this tool can become severe depending on the 22*387f9dfdSAndroid Build Coastguard Worker# workload. 23*387f9dfdSAndroid Build Coastguard Worker# 24*387f9dfdSAndroid Build Coastguard Worker# By default, a minimum millisecond threshold of 10 is used. 25*387f9dfdSAndroid Build Coastguard Worker# 26*387f9dfdSAndroid Build Coastguard Worker# Copyright 2016 Netflix, Inc. 27*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License") 28*387f9dfdSAndroid Build Coastguard Worker# 29*387f9dfdSAndroid Build Coastguard Worker# 06-Feb-2016 Brendan Gregg Created this. 30*387f9dfdSAndroid Build Coastguard Worker 31*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 32*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF 33*387f9dfdSAndroid Build Coastguard Workerimport argparse 34*387f9dfdSAndroid Build Coastguard Workerimport time 35*387f9dfdSAndroid Build Coastguard Worker 36*387f9dfdSAndroid Build Coastguard Worker# arguments 37*387f9dfdSAndroid Build Coastguard Workerexamples = """examples: 38*387f9dfdSAndroid Build Coastguard Worker ./fileslower # trace sync file I/O slower than 10 ms (default) 39*387f9dfdSAndroid Build Coastguard Worker ./fileslower 1 # trace sync file I/O slower than 1 ms 40*387f9dfdSAndroid Build Coastguard Worker ./fileslower -p 185 # trace PID 185 only 41*387f9dfdSAndroid Build Coastguard Worker""" 42*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser( 43*387f9dfdSAndroid Build Coastguard Worker description="Trace slow synchronous file reads and writes", 44*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 45*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 46*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid", type=int, metavar="PID", dest="tgid", 47*387f9dfdSAndroid Build Coastguard Worker help="trace this PID only") 48*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-a", "--all-files", action="store_true", 49*387f9dfdSAndroid Build Coastguard Worker help="include non-regular file types (sockets, FIFOs, etc)") 50*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("min_ms", nargs="?", default='10', 51*387f9dfdSAndroid Build Coastguard Worker help="minimum I/O duration to trace, in ms (default 10)") 52*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true", 53*387f9dfdSAndroid Build Coastguard Worker help=argparse.SUPPRESS) 54*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 55*387f9dfdSAndroid Build Coastguard Workermin_ms = int(args.min_ms) 56*387f9dfdSAndroid Build Coastguard Workertgid = args.tgid 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 Workerenum trace_mode { 66*387f9dfdSAndroid Build Coastguard Worker MODE_READ, 67*387f9dfdSAndroid Build Coastguard Worker MODE_WRITE 68*387f9dfdSAndroid Build Coastguard Worker}; 69*387f9dfdSAndroid Build Coastguard Worker 70*387f9dfdSAndroid Build Coastguard Workerstruct val_t { 71*387f9dfdSAndroid Build Coastguard Worker u32 sz; 72*387f9dfdSAndroid Build Coastguard Worker u64 ts; 73*387f9dfdSAndroid Build Coastguard Worker u32 name_len; 74*387f9dfdSAndroid Build Coastguard Worker // de->d_name.name may point to de->d_iname so limit len accordingly 75*387f9dfdSAndroid Build Coastguard Worker char name[DNAME_INLINE_LEN]; 76*387f9dfdSAndroid Build Coastguard Worker char comm[TASK_COMM_LEN]; 77*387f9dfdSAndroid Build Coastguard Worker}; 78*387f9dfdSAndroid Build Coastguard Worker 79*387f9dfdSAndroid Build Coastguard Workerstruct data_t { 80*387f9dfdSAndroid Build Coastguard Worker enum trace_mode mode; 81*387f9dfdSAndroid Build Coastguard Worker u32 pid; 82*387f9dfdSAndroid Build Coastguard Worker u32 sz; 83*387f9dfdSAndroid Build Coastguard Worker u64 delta_us; 84*387f9dfdSAndroid Build Coastguard Worker u32 name_len; 85*387f9dfdSAndroid Build Coastguard Worker char name[DNAME_INLINE_LEN]; 86*387f9dfdSAndroid Build Coastguard Worker char comm[TASK_COMM_LEN]; 87*387f9dfdSAndroid Build Coastguard Worker}; 88*387f9dfdSAndroid Build Coastguard Worker 89*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(entryinfo, pid_t, struct val_t); 90*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(events); 91*387f9dfdSAndroid Build Coastguard Worker 92*387f9dfdSAndroid Build Coastguard Worker// store timestamp and size on entry 93*387f9dfdSAndroid Build Coastguard Workerstatic int trace_rw_entry(struct pt_regs *ctx, struct file *file, 94*387f9dfdSAndroid Build Coastguard Worker char __user *buf, size_t count) 95*387f9dfdSAndroid Build Coastguard Worker{ 96*387f9dfdSAndroid Build Coastguard Worker u32 tgid = bpf_get_current_pid_tgid() >> 32; 97*387f9dfdSAndroid Build Coastguard Worker if (TGID_FILTER) 98*387f9dfdSAndroid Build Coastguard Worker return 0; 99*387f9dfdSAndroid Build Coastguard Worker 100*387f9dfdSAndroid Build Coastguard Worker u32 pid = bpf_get_current_pid_tgid(); 101*387f9dfdSAndroid Build Coastguard Worker 102*387f9dfdSAndroid Build Coastguard Worker // skip I/O lacking a filename 103*387f9dfdSAndroid Build Coastguard Worker struct dentry *de = file->f_path.dentry; 104*387f9dfdSAndroid Build Coastguard Worker int mode = file->f_inode->i_mode; 105*387f9dfdSAndroid Build Coastguard Worker if (de->d_name.len == 0 || TYPE_FILTER) 106*387f9dfdSAndroid Build Coastguard Worker return 0; 107*387f9dfdSAndroid Build Coastguard Worker 108*387f9dfdSAndroid Build Coastguard Worker // store size and timestamp by pid 109*387f9dfdSAndroid Build Coastguard Worker struct val_t val = {}; 110*387f9dfdSAndroid Build Coastguard Worker val.sz = count; 111*387f9dfdSAndroid Build Coastguard Worker val.ts = bpf_ktime_get_ns(); 112*387f9dfdSAndroid Build Coastguard Worker 113*387f9dfdSAndroid Build Coastguard Worker struct qstr d_name = de->d_name; 114*387f9dfdSAndroid Build Coastguard Worker val.name_len = d_name.len; 115*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&val.name, sizeof(val.name), d_name.name); 116*387f9dfdSAndroid Build Coastguard Worker bpf_get_current_comm(&val.comm, sizeof(val.comm)); 117*387f9dfdSAndroid Build Coastguard Worker entryinfo.update(&pid, &val); 118*387f9dfdSAndroid Build Coastguard Worker 119*387f9dfdSAndroid Build Coastguard Worker return 0; 120*387f9dfdSAndroid Build Coastguard Worker} 121*387f9dfdSAndroid Build Coastguard Worker 122*387f9dfdSAndroid Build Coastguard Workerint trace_read_entry(struct pt_regs *ctx, struct file *file, 123*387f9dfdSAndroid Build Coastguard Worker char __user *buf, size_t count) 124*387f9dfdSAndroid Build Coastguard Worker{ 125*387f9dfdSAndroid Build Coastguard Worker // skip non-sync I/O; see kernel code for __vfs_read() 126*387f9dfdSAndroid Build Coastguard Worker if (!(file->f_op->read_iter)) 127*387f9dfdSAndroid Build Coastguard Worker return 0; 128*387f9dfdSAndroid Build Coastguard Worker return trace_rw_entry(ctx, file, buf, count); 129*387f9dfdSAndroid Build Coastguard Worker} 130*387f9dfdSAndroid Build Coastguard Worker 131*387f9dfdSAndroid Build Coastguard Workerint trace_write_entry(struct pt_regs *ctx, struct file *file, 132*387f9dfdSAndroid Build Coastguard Worker char __user *buf, size_t count) 133*387f9dfdSAndroid Build Coastguard Worker{ 134*387f9dfdSAndroid Build Coastguard Worker // skip non-sync I/O; see kernel code for __vfs_write() 135*387f9dfdSAndroid Build Coastguard Worker if (!(file->f_op->write_iter)) 136*387f9dfdSAndroid Build Coastguard Worker return 0; 137*387f9dfdSAndroid Build Coastguard Worker return trace_rw_entry(ctx, file, buf, count); 138*387f9dfdSAndroid Build Coastguard Worker} 139*387f9dfdSAndroid Build Coastguard Worker 140*387f9dfdSAndroid Build Coastguard Worker// output 141*387f9dfdSAndroid Build Coastguard Workerstatic int trace_rw_return(struct pt_regs *ctx, int type) 142*387f9dfdSAndroid Build Coastguard Worker{ 143*387f9dfdSAndroid Build Coastguard Worker struct val_t *valp; 144*387f9dfdSAndroid Build Coastguard Worker u32 pid = bpf_get_current_pid_tgid(); 145*387f9dfdSAndroid Build Coastguard Worker 146*387f9dfdSAndroid Build Coastguard Worker valp = entryinfo.lookup(&pid); 147*387f9dfdSAndroid Build Coastguard Worker if (valp == 0) { 148*387f9dfdSAndroid Build Coastguard Worker // missed tracing issue or filtered 149*387f9dfdSAndroid Build Coastguard Worker return 0; 150*387f9dfdSAndroid Build Coastguard Worker } 151*387f9dfdSAndroid Build Coastguard Worker u64 delta_us = (bpf_ktime_get_ns() - valp->ts) / 1000; 152*387f9dfdSAndroid Build Coastguard Worker entryinfo.delete(&pid); 153*387f9dfdSAndroid Build Coastguard Worker if (delta_us < MIN_US) 154*387f9dfdSAndroid Build Coastguard Worker return 0; 155*387f9dfdSAndroid Build Coastguard Worker 156*387f9dfdSAndroid Build Coastguard Worker struct data_t data = {}; 157*387f9dfdSAndroid Build Coastguard Worker data.mode = type; 158*387f9dfdSAndroid Build Coastguard Worker data.pid = pid; 159*387f9dfdSAndroid Build Coastguard Worker data.sz = valp->sz; 160*387f9dfdSAndroid Build Coastguard Worker data.delta_us = delta_us; 161*387f9dfdSAndroid Build Coastguard Worker data.name_len = valp->name_len; 162*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&data.name, sizeof(data.name), valp->name); 163*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&data.comm, sizeof(data.comm), valp->comm); 164*387f9dfdSAndroid Build Coastguard Worker events.perf_submit(ctx, &data, sizeof(data)); 165*387f9dfdSAndroid Build Coastguard Worker 166*387f9dfdSAndroid Build Coastguard Worker return 0; 167*387f9dfdSAndroid Build Coastguard Worker} 168*387f9dfdSAndroid Build Coastguard Worker 169*387f9dfdSAndroid Build Coastguard Workerint trace_read_return(struct pt_regs *ctx) 170*387f9dfdSAndroid Build Coastguard Worker{ 171*387f9dfdSAndroid Build Coastguard Worker return trace_rw_return(ctx, MODE_READ); 172*387f9dfdSAndroid Build Coastguard Worker} 173*387f9dfdSAndroid Build Coastguard Worker 174*387f9dfdSAndroid Build Coastguard Workerint trace_write_return(struct pt_regs *ctx) 175*387f9dfdSAndroid Build Coastguard Worker{ 176*387f9dfdSAndroid Build Coastguard Worker return trace_rw_return(ctx, MODE_WRITE); 177*387f9dfdSAndroid Build Coastguard Worker} 178*387f9dfdSAndroid Build Coastguard Worker 179*387f9dfdSAndroid Build Coastguard Worker""" 180*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('MIN_US', str(min_ms * 1000)) 181*387f9dfdSAndroid Build Coastguard Workerif args.tgid: 182*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('TGID_FILTER', 'tgid != %d' % tgid) 183*387f9dfdSAndroid Build Coastguard Workerelse: 184*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('TGID_FILTER', '0') 185*387f9dfdSAndroid Build Coastguard Workerif args.all_files: 186*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('TYPE_FILTER', '0') 187*387f9dfdSAndroid Build Coastguard Workerelse: 188*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('TYPE_FILTER', '!S_ISREG(mode)') 189*387f9dfdSAndroid Build Coastguard Worker 190*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf: 191*387f9dfdSAndroid Build Coastguard Worker print(bpf_text) 192*387f9dfdSAndroid Build Coastguard Worker if args.ebpf: 193*387f9dfdSAndroid Build Coastguard Worker exit() 194*387f9dfdSAndroid Build Coastguard Worker 195*387f9dfdSAndroid Build Coastguard Worker# initialize BPF 196*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text) 197*387f9dfdSAndroid Build Coastguard Worker 198*387f9dfdSAndroid Build Coastguard Worker# I'd rather trace these via new_sync_read/new_sync_write (which used to be 199*387f9dfdSAndroid Build Coastguard Worker# do_sync_read/do_sync_write), but those became static. So trace these from 200*387f9dfdSAndroid Build Coastguard Worker# the parent functions, at the cost of more overhead, instead. 201*387f9dfdSAndroid Build Coastguard Worker# Ultimately, we should be using [V]FS tracepoints. 202*387f9dfdSAndroid Build Coastguard Workertry: 203*387f9dfdSAndroid Build Coastguard Worker b.attach_kprobe(event="__vfs_read", fn_name="trace_read_entry") 204*387f9dfdSAndroid Build Coastguard Worker b.attach_kretprobe(event="__vfs_read", fn_name="trace_read_return") 205*387f9dfdSAndroid Build Coastguard Workerexcept Exception: 206*387f9dfdSAndroid Build Coastguard Worker print('Current kernel does not have __vfs_read, try vfs_read instead') 207*387f9dfdSAndroid Build Coastguard Worker b.attach_kprobe(event="vfs_read", fn_name="trace_read_entry") 208*387f9dfdSAndroid Build Coastguard Worker b.attach_kretprobe(event="vfs_read", fn_name="trace_read_return") 209*387f9dfdSAndroid Build Coastguard Workertry: 210*387f9dfdSAndroid Build Coastguard Worker b.attach_kprobe(event="__vfs_write", fn_name="trace_write_entry") 211*387f9dfdSAndroid Build Coastguard Worker b.attach_kretprobe(event="__vfs_write", fn_name="trace_write_return") 212*387f9dfdSAndroid Build Coastguard Workerexcept Exception: 213*387f9dfdSAndroid Build Coastguard Worker print('Current kernel does not have __vfs_write, try vfs_write instead') 214*387f9dfdSAndroid Build Coastguard Worker b.attach_kprobe(event="vfs_write", fn_name="trace_write_entry") 215*387f9dfdSAndroid Build Coastguard Worker b.attach_kretprobe(event="vfs_write", fn_name="trace_write_return") 216*387f9dfdSAndroid Build Coastguard Worker 217*387f9dfdSAndroid Build Coastguard Workermode_s = { 218*387f9dfdSAndroid Build Coastguard Worker 0: 'R', 219*387f9dfdSAndroid Build Coastguard Worker 1: 'W', 220*387f9dfdSAndroid Build Coastguard Worker} 221*387f9dfdSAndroid Build Coastguard Worker 222*387f9dfdSAndroid Build Coastguard Worker# header 223*387f9dfdSAndroid Build Coastguard Workerprint("Tracing sync read/writes slower than %d ms" % min_ms) 224*387f9dfdSAndroid Build Coastguard Workerprint("%-8s %-14s %-6s %1s %-7s %7s %s" % ("TIME(s)", "COMM", "TID", "D", 225*387f9dfdSAndroid Build Coastguard Worker "BYTES", "LAT(ms)", "FILENAME")) 226*387f9dfdSAndroid Build Coastguard Worker 227*387f9dfdSAndroid Build Coastguard Workerstart_ts = time.time() 228*387f9dfdSAndroid Build Coastguard WorkerDNAME_INLINE_LEN = 32 229*387f9dfdSAndroid Build Coastguard Workerdef print_event(cpu, data, size): 230*387f9dfdSAndroid Build Coastguard Worker event = b["events"].event(data) 231*387f9dfdSAndroid Build Coastguard Worker 232*387f9dfdSAndroid Build Coastguard Worker ms = float(event.delta_us) / 1000 233*387f9dfdSAndroid Build Coastguard Worker name = event.name.decode('utf-8', 'replace') 234*387f9dfdSAndroid Build Coastguard Worker if event.name_len > DNAME_INLINE_LEN: 235*387f9dfdSAndroid Build Coastguard Worker name = name[:-3] + "..." 236*387f9dfdSAndroid Build Coastguard Worker 237*387f9dfdSAndroid Build Coastguard Worker print("%-8.3f %-14.14s %-6s %1s %-7s %7.2f %s" % ( 238*387f9dfdSAndroid Build Coastguard Worker time.time() - start_ts, event.comm.decode('utf-8', 'replace'), 239*387f9dfdSAndroid Build Coastguard Worker event.pid, mode_s[event.mode], event.sz, ms, name)) 240*387f9dfdSAndroid Build Coastguard Worker 241*387f9dfdSAndroid Build Coastguard Workerb["events"].open_perf_buffer(print_event, page_cnt=64) 242*387f9dfdSAndroid Build Coastguard Workerwhile 1: 243*387f9dfdSAndroid Build Coastguard Worker try: 244*387f9dfdSAndroid Build Coastguard Worker b.perf_buffer_poll() 245*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 246*387f9dfdSAndroid Build Coastguard Worker exit() 247