blob: 075be087d37da273b9d054785d06a7862e57e2c6 [file] [log] [blame]
Brendan Greggdc642c52016-02-09 00:32:51 -08001#!/usr/bin/python
2# @lint-avoid-python-3-compatibility-imports
3#
4# filelife Trace the lifespan of short-lived files.
5# For Linux, uses BCC, eBPF. Embedded C.
6#
7# This traces the creation and deletion of files, providing information
8# on who deleted the file, the file age, and the file name. The intent is to
9# provide information on short-lived files, for debugging or performance
10# analysis.
11#
12# USAGE: filelife [-h] [-p PID]
13#
14# Copyright 2016 Netflix, Inc.
15# Licensed under the Apache License, Version 2.0 (the "License")
16#
17# 08-Feb-2015 Brendan Gregg Created this.
18
19from __future__ import print_function
20from bcc import BPF
21import argparse
22from time import strftime
23
24# arguments
25examples = """examples:
26 ./filelife # trace all stat() syscalls
27 ./filelife -p 181 # only trace PID 181
28"""
29parser = argparse.ArgumentParser(
30 description="Trace stat() syscalls",
31 formatter_class=argparse.RawDescriptionHelpFormatter,
32 epilog=examples)
33parser.add_argument("-p", "--pid",
34 help="trace this PID only")
35args = parser.parse_args()
36debug = 0
37
38# define BPF program
39bpf_text = """
40#include <uapi/linux/ptrace.h>
41#include <linux/fs.h>
42
43BPF_HASH(birth, struct dentry *);
44
45// trace file creation time
46int trace_create(struct pt_regs *ctx, struct inode *dir, struct dentry *dentry)
47{
48 u32 pid = bpf_get_current_pid_tgid();
49 FILTER
50
51 u64 ts = bpf_ktime_get_ns();
52 birth.update(&dentry, &ts);
53
54 return 0;
55};
56
57// trace file deletion and output details
58int trace_unlink(struct pt_regs *ctx, struct inode *dir, struct dentry *dentry)
59{
60 u32 pid = bpf_get_current_pid_tgid();
61 FILTER
62
63 u64 *tsp, delta;
64 tsp = birth.lookup(&dentry);
65 if (tsp == 0) {
66 return 0; // missed create
67 }
68 delta = (bpf_ktime_get_ns() - *tsp) / 1000000;
69 birth.delete(&dentry);
70
71 if (dentry->d_iname[0] == 0)
72 return 0;
73
74 bpf_trace_printk("%d %s\\n", delta, dentry->d_iname);
75
76 return 0;
77}
78"""
79if args.pid:
80 bpf_text = bpf_text.replace('FILTER',
81 'if (pid != %s) { return 0; }' % args.pid)
82else:
83 bpf_text = bpf_text.replace('FILTER', '')
84if debug:
85 print(bpf_text)
86
87# initialize BPF
88b = BPF(text=bpf_text)
89b.attach_kprobe(event="vfs_create", fn_name="trace_create")
90b.attach_kprobe(event="vfs_unlink", fn_name="trace_unlink")
91
92# header
93print("%-8s %-6s %-16s %-7s %s" % ("TIME", "PID", "COMM", "AGE(s)", "FILE"))
94
95start_ts = 0
96
97# format output
98while 1:
99 (task, pid, cpu, flags, ts, msg) = b.trace_fields()
Brendan Greggee31f612016-02-10 22:32:03 -0800100 (delta, filename) = msg.split(" ", 1)
Brendan Greggdc642c52016-02-09 00:32:51 -0800101
102 # print columns
103 print("%-8s %-6d %-16s %-7.2f %s" % (strftime("%H:%M:%S"), pid, task,
104 float(delta) / 1000, filename))