Skip to content

Commit 4c70499

Browse files
committed
IOSpeed Tool
1 parent ecdbafb commit 4c70499

File tree

1 file changed

+114
-0
lines changed

1 file changed

+114
-0
lines changed

iospeed.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#!/usr/bin/python
2+
3+
'''
4+
Author: Saleem Ahmad
5+
usage: sudo python iospeed -p <pid>
6+
'''
7+
from __future__ import print_function
8+
from bcc import BPF
9+
from bcc.utils import printb
10+
from time import sleep
11+
from optparse import OptionParser
12+
13+
parser = OptionParser()
14+
parser.add_option('-p', '--pid', dest='pid', help='pid to trace', type='int')
15+
16+
(option, args) = parser.parse_args()
17+
18+
# load BPF program
19+
text='''
20+
#include <uapi/linux/ptrace.h>
21+
22+
struct IOData {
23+
u64 bytes;
24+
u64 type;
25+
u64 time;
26+
};
27+
28+
BPF_HASH(data, u32, struct IOData);
29+
BPF_PERF_OUTPUT(output);
30+
31+
void write_probe(struct pt_regs* ctx, int fd, const void* buf, size_t len) {
32+
u32 pid = (bpf_get_current_pid_tgid() >> 32);
33+
if (pid != TRACE_PID) return;
34+
35+
u64 ts = bpf_ktime_get_ns();
36+
u32 key = 1;
37+
struct IOData* val = data.lookup(&key);
38+
int count = PT_REGS_RC(ctx);
39+
if (count < 0) {
40+
count = 0;
41+
}
42+
43+
if (val) {
44+
val->bytes += count;
45+
if (ts - val->time > 1000000000L) {
46+
output.perf_submit(ctx, val, sizeof(struct IOData));
47+
val->bytes = 0;
48+
val->time = ts;
49+
}
50+
} else {
51+
struct IOData zero;
52+
zero.time = ts;
53+
zero.type = key;
54+
zero.bytes = 0;
55+
data.insert(&key, &zero);
56+
}
57+
}
58+
59+
void read_probe(struct pt_regs* ctx, int fd, const void* buf, size_t len) {
60+
u32 pid = (bpf_get_current_pid_tgid() >> 32);
61+
if (pid != TRACE_PID) return;
62+
63+
u64 ts = bpf_ktime_get_ns();
64+
u32 key = 0;
65+
struct IOData* val = data.lookup(&key);
66+
int count = PT_REGS_RC(ctx);
67+
if (count < 0) {
68+
count = 0;
69+
}
70+
71+
if (val) {
72+
val->bytes += count;
73+
if (ts - val->time > 1000000000L) {
74+
output.perf_submit(ctx, val, sizeof(struct IOData));
75+
val->bytes = 0;
76+
val->time = ts;
77+
}
78+
} else {
79+
struct IOData zero;
80+
zero.time = ts;
81+
zero.type = key;
82+
zero.bytes = 0;
83+
data.insert(&key, &zero);
84+
}
85+
}
86+
'''.replace('TRACE_PID', str(option.pid))
87+
88+
#print(text)
89+
90+
b = BPF(text=text)
91+
92+
print('IOSpeed Running, PID: %d' % option.pid)
93+
w_name = b.get_syscall_fnname('write')
94+
r_name = b.get_syscall_fnname('read')
95+
print('Tracing: %s' % ','.join([w_name, r_name]))
96+
97+
b.attach_kretprobe(event=w_name, fn_name="write_probe")
98+
b.attach_kretprobe(event=r_name, fn_name="read_probe")
99+
100+
MB_DIVIDER = 1024.0 * 1024.0
101+
102+
def print_data(cpu, data, size):
103+
e = b['output'].event(data)
104+
t = 'RD'
105+
if e.type == 1:
106+
t = 'WR'
107+
print("%ld,%s,%0.4f MB/sec" % (e.time, t, e.bytes / MB_DIVIDER))
108+
109+
b['output'].open_perf_buffer(print_data)
110+
while True:
111+
try:
112+
b.perf_buffer_poll()
113+
except KeyboardInterrupt:
114+
exit()

0 commit comments

Comments
 (0)