Skip to content

Commit 5666f17

Browse files
committed
Add bpf_fs_operation_distribution.py
1 parent 5b813f2 commit 5666f17

File tree

1 file changed

+94
-0
lines changed

1 file changed

+94
-0
lines changed

bpf/bpf_fs_operation_distribution.py

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#!/usr/bin/python
2+
from __future__ import print_function
3+
from bcc import BPF
4+
import argparse
5+
import time
6+
import datetime
7+
import sys
8+
import ctypes
9+
10+
11+
BPF_PROGRAM = '''
12+
#include <uapi/linux/ptrace.h>
13+
#include <uapi/linux/limits.h>
14+
#include <linux/sched.h>
15+
16+
BPF_HASH(start_at, u32, u64);
17+
BPF_HISTOGRAM(dist, u32);
18+
19+
int trace_entry(struct pt_regs *ctx, const char __user *filename) {
20+
u64 pid_tgid = bpf_get_current_pid_tgid();
21+
u32 tid = (u32)pid_tgid;
22+
u32 pid = pid_tgid >> 32;
23+
24+
%FILTER_PID%
25+
26+
u64 ts = bpf_ktime_get_ns();
27+
start_at.update(&tid, &ts);
28+
return 0;
29+
}
30+
31+
int trace_return(struct pt_regs *ctx) {
32+
u32 tid = (u32)bpf_get_current_pid_tgid();
33+
34+
u64 *p = start_at.lookup(&tid);
35+
if (!p)
36+
return 0;
37+
u64 ts_start = *p;
38+
u64 ts_end = bpf_ktime_get_ns();
39+
u64 delta = ts_end - ts_start;
40+
41+
u32 key = bpf_log2l(delta);
42+
dist.increment(key);
43+
44+
start_at.delete(&tid);
45+
return 0;
46+
}
47+
'''
48+
49+
50+
TARGET_EVENTS = {
51+
'open': ["ext4_file_open"],
52+
'read': ["generic_file_read_iter"],
53+
'write': ["ext4_file_write_iter"],
54+
'stat': ["sys_stat", "sys_statfs", "sys_newstat"],
55+
'unlink': ["vfs_unlink"],
56+
'sync': ["sys_sync"],
57+
}
58+
59+
60+
def main():
61+
parser = argparse.ArgumentParser()
62+
parser.add_argument('-p', '--pid', metavar='PID', help='trace only this PID.')
63+
parser.add_argument('--interval', metavar='SEC', type=float, default=5.0, help='interval in seconds.')
64+
parser.add_argument('target', choices=['open', 'read', 'write', 'stat', 'unlink', 'sync'])
65+
args = parser.parse_args()
66+
67+
interval_sec = args.interval
68+
target = args.target
69+
70+
if args.pid is None:
71+
bpf_program = BPF_PROGRAM.replace('%FILTER_PID%', '')
72+
else:
73+
pid = int(args.pid)
74+
bpf_program = BPF_PROGRAM.replace('%FILTER_PID%', 'if (pid != {}) return 0;'.format(pid))
75+
76+
bpf = BPF(text=bpf_program)
77+
for event in TARGET_EVENTS[args.target]:
78+
bpf.attach_kprobe(event=event, fn_name="trace_entry")
79+
bpf.attach_kretprobe(event=event, fn_name="trace_return")
80+
81+
while True:
82+
time.sleep(interval_sec)
83+
ts = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
84+
sys.stdout.write("ts:" + ts + "\ttarget:" + target)
85+
table = bpf['dist']
86+
for k, v in sorted(table.items(), key=lambda x: x[0].value):
87+
sys.stdout.write("\t" + str(2 ** k.value) + ":" + str(v.value))
88+
sys.stdout.write("\n")
89+
sys.stdout.flush()
90+
table.clear()
91+
92+
93+
if __name__ == '__main__':
94+
main()

0 commit comments

Comments
 (0)