-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathio_throttle.py
executable file
·124 lines (93 loc) · 2.71 KB
/
io_throttle.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#!/usr/bin/env python
#
# io_throttle Track provided event in the kernel and print user/kernel stack
#
# usage: io_throttle -e event_name
from __future__ import print_function
from time import sleep
from bcc import BPF
import argparse
import ctypes as ct
import signal
text = """
#include <linux/ptrace.h>
#define HASH_SIZE 2^14
#define QUERY_LEN 100
#define STACK_STORAGE_SIZE 1024
struct key_t {
int pid;
int result;
char name[TASK_COMM_LEN];
char query[QUERY_LEN];
};
struct backend {
int pid;
char query[QUERY_LEN];
};
BPF_PERF_OUTPUT(events);
BPF_HASH(queries, u32, struct backend, HASH_SIZE);
static inline __attribute__((always_inline)) void get_key(struct key_t* key) {
key->pid = bpf_get_current_pid_tgid();
struct backend *data = queries.lookup(&(key->pid));
bpf_get_current_comm(&(key->name), sizeof(key->name));
if (data != NULL)
bpf_probe_read(&(key->query), QUERY_LEN, &(data->query));
}
int probe_blk_throtl_bio(struct pt_regs *ctx)
{
struct key_t key = {};
get_key(&key);
key.result = (int)PT_REGS_RC(ctx);
if (key.result == 1)
events.perf_submit(ctx, &key, sizeof(key));
}
"""
def attach(event_name, bpf, args):
bpf.attach_kretprobe(
event="blk_throtl_bio",
fn_name="probe_blk_throtl_bio"
)
# signal handler
def signal_ignore(sig, frame):
print()
class Data(ct.Structure):
_fields_ = [("pid", ct.c_int),
("result", ct.c_int),
("name", ct.c_char * 16),
("query", ct.c_char * 100)]
def run(args):
print("Attaching...")
debug = 4
bpf = BPF(text=text, debug=debug)
attach(args.event, bpf, args)
exiting = False
def print_event(cpu, data, size):
event = ct.cast(data, ct.POINTER(Data)).contents
name = event.name.decode("ascii")
if not name.startswith("postgres"):
return
print("Event: pid {} name {} query {} result {}".format(
event.pid, event.name, event.query, event.result))
bpf["events"].open_perf_buffer(print_event)
print("Listening...")
while True:
try:
sleep(1)
bpf.perf_buffer_poll()
except KeyboardInterrupt:
exiting = True
# as cleanup can take many seconds, trap Ctrl-C:
signal.signal(signal.SIGINT, signal_ignore)
if exiting:
print("Detaching...")
break
def parse_args():
parser = argparse.ArgumentParser(
description="",
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument(
"-e", "--event", type=str,
help="Event to trace")
return parser.parse_args()
if __name__ == "__main__":
run(parse_args())