-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathio_spy.c
284 lines (239 loc) · 7.91 KB
/
io_spy.c
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
#include <argp.h>
#include <signal.h>
#include <time.h>
#include <sys/resource.h>
#include <sys/sysinfo.h>
#include <sys/select.h>
#include <errno.h>
#include <asm/unistd.h>
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include <linux/perf_event.h>
#include <assert.h>
#include "io_event.h"
#include "io_stats.skel.h"
#include "proc_data.h"
#define MAX_IO_RESULTS 256
static u32 zero = 0;
static u32 one = 1;
/*---------------------------IO信息---------------------------------*/
struct ring_buffer *rb_io_task_stats, *rb_io_process_stats, *rb_io_wait;
struct io_stats_bpf *io_skel = NULL;
struct bpf_link *link_io_wait = NULL;
DiskStatsContext* context = NULL;
DiskStats current[MAX_DEVICES];
static int handle_io_task_stats_event(void *ctx,void *data, size_t data_sz){
struct io_task_stats *event = (struct io_task_stats *)data;
printf(" PID: %u\n", event->info.pid);
printf(" Command: %s\n", event->info.comm);
printf(" read_count: %u\n", event->read_count);
printf(" write_count: %u\n", event->write_count);
return 0;
}
static int handle_io_process_stats_event(void *ctx,void *data, size_t data_sz){
struct io_process_stats *event = (struct io_process_stats *)data;
printf(" tgid: %u\n", event->tgid);
printf(" read_count: %u\n", event->read_count);
printf(" write_count: %u\n", event->write_count);
return 0;
}
static int handle_iowait_perf_event(void *ctx,void *data, size_t data_sz){
struct io_wait_perf_data *event = (struct io_wait_perf_data *)data;
for(int i=0;i<8;i++){
switch(i)
{
case 0:
printf("wait less than 1us: %u\n",event->count_list[i]);
continue;
case 1:
printf("wait less than 4us: %u\n",event->count_list[i]);
continue;
case 2:
printf("wait less than 16us: %u\n",event->count_list[i]);
continue;
case 3:
printf("wait less than 64us: %u\n",event->count_list[i]);
continue;
case 4:
printf("wait less than 256us: %u\n",event->count_list[i]);
continue;
case 5:
printf("wait less than 1ms: %u\n",event->count_list[i]);
continue;
case 6:
printf("wait less than 4ms: %u\n",event->count_list[i]);
continue;
case 7:
printf("wait large than 4ms: %u\n",event->count_list[i]);
continue;
default:
continue;
}
}
return 0;
}
static int create_perf_event(u32 period_ms) {
struct perf_event_attr attr = {
.type = PERF_TYPE_SOFTWARE, // 使用软件事件类型
.config = PERF_COUNT_SW_CPU_CLOCK, // 使用 CPU 时钟作为触发源
.size = sizeof(struct perf_event_attr),
.sample_period = period_ms * 1000000ULL, // 设置为毫秒级的间隔
.freq = 0, // 使用固定间隔,而非频率
.wakeup_events = 1, // 每次触发事件
};
// 对所有 CPU 和进程创建事件
int fd = syscall(__NR_perf_event_open, &attr, -1, 0, -1, 0);
if (fd < 0) {
perror("perf_event_open");
return -1;
}
return fd;
}
static struct bpf_link* attach_perf_event_to_program(struct bpf_program *prog, u32 period_ms) {
// 创建 perf event
int perf_fd = create_perf_event(period_ms);
if (perf_fd < 0) {
fprintf(stderr, "Failed to create perf_event\n");
return NULL;
}
// 将 perf event 附加到指定的 BPF 程序
struct bpf_link *link = bpf_program__attach_perf_event(prog, perf_fd);
if (!link) {
fprintf(stderr, "Failed to attach perf_event to BPF program: %s\n", strerror(errno));
close(perf_fd);
return NULL;
}
return link;
}
static int attach_io_skel(struct io_stats_bpf *skel){
int ret;
ret = io_stats_bpf__load(skel);
if(ret){
fprintf(stderr, "failed to load io_stats skel\n");
return ret;
}
ret = io_stats_bpf__attach(skel);
if(ret){
fprintf(stderr, "failed to attach io_stats bpf program(s)\n");
return -1;
}
link_io_wait = attach_perf_event_to_program(skel->progs.handle_io_wait_event,500);
if(!link_io_wait){
return -1;
}
skel->links.handle_io_wait_event = link_io_wait;
rb_io_task_stats = ring_buffer__new(bpf_map__fd(skel->maps.io_task_stats_buffer),handle_io_task_stats_event,NULL,NULL);
rb_io_process_stats = ring_buffer__new(bpf_map__fd(skel->maps.io_process_stats_buffer),handle_io_process_stats_event,NULL,NULL);
rb_io_wait = ring_buffer__new(bpf_map__fd(skel->maps.io_wait_buffer),handle_iowait_perf_event,NULL,NULL);
int threhold_fd = bpf_map__fd(skel->maps.io_threhold_map);
struct io_stats_threhold task = {
.read_count = 50,
.write_count = 50,
.time_window = (1000 * MSEC)
};
struct io_stats_threhold process = {
.read_count = 100,
.write_count = 100,
.time_window = (1000 * MSEC)
};
if(bpf_map_update_elem(threhold_fd,&zero,&task,BPF_ANY) != 0){
printf("io_threhold map update error\n");
return -1;
}
if(bpf_map_update_elem(threhold_fd,&one,&process,BPF_ANY) != 0){
printf("io_threhold map update error\n");
return -1;
}
return 0;
}
unsigned int io_parse_arguments(int argc, char *argv[]) {
unsigned int interval = 1; // 默认1秒
if (argc == 2) {
interval = atoi(argv[1]);
if (interval == 0) {
fprintf(stderr, "Invalid interval. Using default 1 second.\n");
interval = 1;
}
}
return interval;
}
int io_initialize_monitoring(unsigned int interval) {
// 初始化上下文
context = diskstats_init();
if (!context) {
fprintf(stderr, "Failed to initialize DiskStatsContext.\n");
return -1;
}
// 读取初始统计数据
int device_count_prev = diskstats_read(context, current, MAX_DEVICES);
if (device_count_prev < 0) {
fprintf(stderr, "Failed to read /proc/diskstats.\n");
diskstats_cleanup(context);
return -1;
}
context->device_count_prev = device_count_prev;
return 0;
}
static void io_resource_clean(){
if(rb_io_task_stats)
ring_buffer__free(rb_io_task_stats);
if(rb_io_process_stats)
ring_buffer__free(rb_io_process_stats);
if(rb_io_wait)
ring_buffer__free(rb_io_wait);
io_stats_bpf__destroy(io_skel);
}
static int io_ring_buffer_poll(){
int ret;
ret = ring_buffer__poll(rb_io_task_stats,200);
if(ret<0)
{
fprintf(stderr, "Error polling io task stat ring buffer: %d\n", ret);
return ret;
}
ret = ring_buffer__poll(rb_io_process_stats,200);
if(ret < 0)
{
fprintf(stderr, "Error polling io process stat ring buffer: %d\n", ret);
return ret;
}
ret = ring_buffer__poll(rb_io_wait,600);
if(ret<0)
{
fprintf(stderr, "Error polling io wait ring buffer: %d\n", ret);
return ret;
}
return 0;
}
int main(int argc, char *argv[]) {
int ret = 0;
io_skel = io_stats_bpf__open();
if(!io_skel){
fprintf(stderr, "failed to open io_stats skel\n");
ret = 1;
goto cleanup;
}
ret = attach_io_skel(io_skel);
if(ret != 0)
goto cleanup;
unsigned int interval = io_parse_arguments(argc, argv);
if (io_initialize_monitoring(interval) != 0) {
fprintf(stderr, "Initialization failed.\n");
ret = 1;
goto cleanup;
}
while (1) {
//sleep(interval);
usleep(USEC * 100);
ret = io_ring_buffer_poll();
if(ret != 0)
goto cleanup;
if (process_disk_stats(context, current, &context->device_count_prev, interval) != 0) {
goto cleanup;
}
}
cleanup:
io_resource_clean();
diskstats_cleanup(context);
return 0;
}