• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/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()
100    (delta, filename) = msg.split(" ", 1)
101
102    # print columns
103    print("%-8s %-6d %-16s %-7.2f %s" % (strftime("%H:%M:%S"), pid, task,
104        float(delta) / 1000, filename))
105