33b901938b9356e65690694c297f403483edd84b
[lttngtop.git] / src / iostreamtop.c
1 /*
2 * Copyright (C) 2011 Mathieu Bain <mathieu.bain@polymtl.ca>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <string.h>
23 #include <babeltrace/babeltrace.h>
24
25 #include "lttngtoptypes.h"
26 #include "common.h"
27 #include "iostreamtop.h"
28
29 void add_file(struct processtop *proc, struct files *file, int fd)
30 {
31 struct files *tmp_file;
32 struct processtop *parent;
33 int size;
34
35 size = proc->process_files_table->len;
36 parent = proc->threadparent;
37 if (parent)
38 insert_file(parent, fd);
39 if (size <= fd) {
40 g_ptr_array_set_size(proc->process_files_table, fd);
41 g_ptr_array_add(proc->process_files_table, file);
42 } else {
43 tmp_file = g_ptr_array_index(proc->process_files_table, fd);
44 if (tmp_file == NULL)
45 g_ptr_array_index(proc->process_files_table, fd) = file;
46 else {
47 if (strcmp(tmp_file->name, file->name) != 0) {
48 size = proc->process_files_table->len;
49 g_ptr_array_set_size(proc->process_files_table,
50 size+1);
51 g_ptr_array_index(proc->process_files_table,
52 size) = tmp_file;
53 g_ptr_array_index(proc->process_files_table,
54 fd) = file;
55 } else
56 tmp_file->flag = __NR_open;
57 }
58 }
59 /*
60 * The file may have be created in the parent
61 */
62 if (file->flag == -1) {
63 file->fd = fd;
64 file->flag = __NR_open;
65 lttngtop.nbfiles++;
66 lttngtop.nbnewfiles++;
67 }
68 }
69
70 /*
71 * Edit the file
72 * Called by handled_statedump_filename
73 */
74 void edit_file(struct processtop *proc, struct files *file, int fd)
75 {
76 int size = proc->process_files_table->len;
77 struct files *tmpfile;
78
79 if (fd >= size) {
80 add_file(proc, file, fd);
81 } else {
82 tmpfile = g_ptr_array_index(proc->process_files_table, fd);
83 if (tmpfile) {
84 tmpfile->name = strdup(file->name);
85 free(file);
86 } else
87 add_file(proc, file, fd);
88 }
89 }
90
91 void insert_file(struct processtop *proc, int fd)
92 {
93 struct files *tmp;
94 struct files *tmp_parent;
95 struct processtop *parent;
96
97 if (fd < 0)
98 return;
99 if (fd >= proc->process_files_table->len) {
100 tmp = g_new0(struct files, 1);
101 tmp->name = "Unknown";
102 tmp->read = 0;
103 tmp->write = 0;
104 tmp->fd = fd;
105 tmp->flag = -1;
106 add_file(proc, tmp, fd);
107 } else {
108 tmp = g_ptr_array_index(proc->process_files_table, fd);
109 if (tmp == NULL) {
110 tmp = g_new0(struct files, 1);
111 tmp->name = "Unknown";
112 tmp->read = 0;
113 tmp->write = 0;
114 tmp->fd = fd;
115 tmp->flag = -1;
116 add_file(proc, tmp, fd);
117 } else {
118 parent = proc->threadparent;
119 if (parent) {
120 tmp_parent = g_ptr_array_index(
121 parent->process_files_table, fd);
122 if (tmp_parent &&
123 (strcmp(tmp->name, tmp_parent->name)) != 0)
124 tmp->name = strdup(tmp_parent->name);
125 }
126 }
127 }
128 }
129
130 void close_file(struct processtop *proc, int fd)
131 {
132 struct files *file;
133
134 file = get_file(proc, fd);
135 if (file != NULL) {
136 file->flag = __NR_close;
137 lttngtop.nbfiles--;
138 }
139 lttngtop.nbclosedfiles++;
140 }
141
142 struct files *get_file(struct processtop *proc, int fd)
143 {
144 int len;
145 struct files *tmp = NULL;
146
147 len = proc->process_files_table->len;
148
149 /*
150 * It is possible that a file was open before taking the trace
151 * and its fd could be greater than all of the others fd
152 * used by the process
153 */
154 if (fd < len && fd >= 0)
155 tmp = g_ptr_array_index(proc->process_files_table, fd);
156
157 return tmp;
158 }
159
160 void show_table(GPtrArray *tab)
161 {
162 int i;
163 struct files *file;
164
165 for (i = 0 ; i < tab->len; i++) {
166 file = g_ptr_array_index(tab, i);
167 if (file == NULL)
168 fprintf(stderr, "NULL, ");
169 else
170 fprintf(stderr, "%s, ", file->name);
171 }
172 fprintf(stderr, "]\n\n");
173 }
174
175 void show_history(struct file_history *history)
176 {
177 struct file_history *tmp = history;
178
179 while (tmp != NULL) {
180 fprintf(stderr, "fd = %d, name = %s\n", tmp->file->fd,
181 tmp->file->name);
182 tmp = tmp->next;
183 }
184
185 }
186
187 int update_iostream_ret(struct lttngtop *ctx, int tid, char *comm,
188 unsigned long timestamp, uint64_t cpu_id, int ret)
189 {
190 struct processtop *tmp;
191 struct files *tmpfile;
192 int err = 0;
193
194 tmp = get_proc(ctx, tid, comm, timestamp);
195
196 if (tmp->syscall_info != NULL) {
197 if (tmp->syscall_info->type == __NR_read
198 && ret > 0) {
199 tmp->totalfileread += ret;
200 tmp->fileread += ret;
201 tmpfile = get_file(tmp, tmp->syscall_info->fd);
202 if (tmpfile)
203 tmpfile->read += ret;
204 } else if (tmp->syscall_info->type == __NR_write
205 && ret > 0) {
206 tmp->totalfilewrite += ret;
207 tmp->filewrite += ret;
208 tmpfile = get_file(tmp, tmp->syscall_info->fd);
209 if (tmpfile)
210 tmpfile->write += ret;
211 } else if (tmp->syscall_info->type == __NR_open
212 && ret > 0) {
213 tmpfile = tmp->files_history->file;
214 add_file(tmp, tmpfile, ret);
215 tmpfile->fd = ret;
216 } else {
217 err = -1;
218 }
219 g_free(tmp->syscall_info);
220 tmp->syscall_info = NULL;
221 }
222 return err;
223 }
224
225 struct syscalls *create_syscall_info(unsigned int type, uint64_t cpu_id,
226 unsigned int tid, int fd)
227 {
228 struct syscalls *syscall_info;
229
230 syscall_info = g_new0(struct syscalls, 1);
231 syscall_info->type = type;
232 syscall_info->cpu_id = cpu_id;
233 syscall_info->tid = tid;
234 syscall_info->fd = fd;
235
236 return syscall_info;
237 }
238
239 struct file_history *create_file(struct file_history *history, char *file_name)
240 {
241 struct files *new_file;
242 struct file_history *new_history;
243
244 new_file = g_new0(struct files, 1);
245 new_history = g_new0(struct file_history, 1);
246 new_file->name = strdup(file_name);
247 new_file->read = 0;
248 new_file->write = 0;
249 new_file->flag = -1;
250 new_history->file = new_file;
251 new_history->next = history;
252
253 return new_history;
254 }
255
256 enum bt_cb_ret handle_exit_syscall(struct bt_ctf_event *call_data,
257 void *private_data)
258 {
259 const struct definition *scope;
260 unsigned long timestamp;
261 char *comm;
262 uint64_t ret, tid;
263 uint64_t cpu_id;
264
265 timestamp = bt_ctf_get_timestamp(call_data);
266 if (timestamp == -1ULL)
267 goto error;
268
269 comm = get_context_comm(call_data);
270 tid = get_context_tid(call_data);
271
272 scope = bt_ctf_get_top_level_scope(call_data,
273 BT_EVENT_FIELDS);
274 ret = bt_ctf_get_int64(bt_ctf_get_field(call_data,
275 scope, "_ret"));
276 if (bt_ctf_field_get_error()) {
277 fprintf(stderr, "Missing ret context info\n");
278 goto error;
279 }
280
281 cpu_id = get_cpu_id(call_data);
282
283 /*
284 * if we encounter an exit_syscall and
285 * it is not for a syscall read or write
286 * we just abort the execution of this callback
287 */
288 if ((update_iostream_ret(&lttngtop, tid, comm, timestamp, cpu_id, ret)) < 0)
289 return BT_CB_ERROR_CONTINUE;
290
291 return BT_CB_OK;
292
293 error:
294 return BT_CB_ERROR_STOP;
295 }
296
297
298 enum bt_cb_ret handle_sys_write(struct bt_ctf_event *call_data,
299 void *private_data)
300 {
301 const struct definition *scope;
302 struct processtop *tmp;
303 unsigned long timestamp;
304 uint64_t cpu_id;
305 int64_t tid;
306 char *procname;
307 int fd;
308
309 timestamp = bt_ctf_get_timestamp(call_data);
310 if (timestamp == -1ULL)
311 goto error;
312
313 tid = get_context_tid(call_data);
314 cpu_id = get_cpu_id(call_data);
315
316 procname = get_context_comm(call_data);
317
318 scope = bt_ctf_get_top_level_scope(call_data,
319 BT_EVENT_FIELDS);
320 fd = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
321 scope, "_fd"));
322 if (bt_ctf_field_get_error()) {
323 fprintf(stderr, "Missing fd context info\n");
324 goto error;
325 }
326
327 tmp = get_proc(&lttngtop, tid, procname, timestamp);
328 tmp->syscall_info = create_syscall_info(__NR_write, cpu_id, tid, fd);
329
330 insert_file(tmp, fd);
331
332 return BT_CB_OK;
333
334 error:
335 return BT_CB_ERROR_STOP;
336 }
337
338 enum bt_cb_ret handle_sys_read(struct bt_ctf_event *call_data,
339 void *private_data)
340 {
341 struct processtop *tmp;
342 const struct definition *scope;
343 unsigned long timestamp;
344 uint64_t cpu_id;
345 int64_t tid;
346 char *procname;
347 int fd;
348
349 timestamp = bt_ctf_get_timestamp(call_data);
350 if (timestamp == -1ULL)
351 goto error;
352
353 tid = get_context_tid(call_data);
354 cpu_id = get_cpu_id(call_data);
355
356 procname = get_context_comm(call_data);
357
358 scope = bt_ctf_get_top_level_scope(call_data,
359 BT_EVENT_FIELDS);
360 fd = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
361 scope, "_fd"));
362 if (bt_ctf_field_get_error()) {
363 fprintf(stderr, "Missing fd context info\n");
364 goto error;
365 }
366
367 tmp = get_proc(&lttngtop, tid, procname, timestamp);
368 tmp->syscall_info = create_syscall_info(__NR_read, cpu_id, tid, fd);
369
370 insert_file(tmp, fd);
371
372 return BT_CB_OK;
373
374 error:
375 return BT_CB_ERROR_STOP;
376 }
377
378
379 enum bt_cb_ret handle_sys_open(struct bt_ctf_event *call_data,
380 void *private_data)
381 {
382
383 struct processtop *tmp;
384 const struct definition *scope;
385 unsigned long timestamp;
386 uint64_t cpu_id;
387 int64_t tid;
388 char *procname;
389 char *file;
390
391 timestamp = bt_ctf_get_timestamp(call_data);
392 if (timestamp == -1ULL)
393 goto error;
394
395 tid = get_context_tid(call_data);
396 cpu_id = get_cpu_id(call_data);
397
398 procname = get_context_comm(call_data);
399
400 scope = bt_ctf_get_top_level_scope(call_data,
401 BT_EVENT_FIELDS);
402 file = bt_ctf_get_string(bt_ctf_get_field(call_data,
403 scope, "_filename"));
404 if (bt_ctf_field_get_error()) {
405 fprintf(stderr, "Missing file name context info\n");
406 goto error;
407 }
408
409 tmp = get_proc(&lttngtop, tid, procname, timestamp);
410 tmp->syscall_info = create_syscall_info(__NR_open, cpu_id, tid, -1);
411
412 tmp->files_history = create_file(tmp->files_history, file);
413
414 return BT_CB_OK;
415
416 error:
417 return BT_CB_ERROR_STOP;
418 }
419
420
421 enum bt_cb_ret handle_sys_close(struct bt_ctf_event *call_data,
422 void *private_data)
423 {
424 const struct definition *scope;
425 struct processtop *tmp;
426 unsigned long timestamp;
427 int64_t tid;
428 char *procname;
429 int fd;
430
431 timestamp = bt_ctf_get_timestamp(call_data);
432 if (timestamp == -1ULL)
433 goto error;
434
435 tid = get_context_tid(call_data);
436
437 procname = get_context_comm(call_data);
438
439 scope = bt_ctf_get_top_level_scope(call_data,
440 BT_EVENT_FIELDS);
441 fd = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
442 scope, "_fd"));
443 if (bt_ctf_field_get_error()) {
444 fprintf(stderr, "Missing fd context info\n");
445 goto error;
446 }
447
448 tmp = get_proc(&lttngtop, tid, procname, timestamp);
449
450 close_file(tmp, fd);
451
452 return BT_CB_OK;
453
454 error:
455 return BT_CB_ERROR_STOP;
456 }
457
458 enum bt_cb_ret handle_statedump_file_descriptor(struct bt_ctf_event *call_data,
459 void *private_data)
460 {
461 const struct definition *scope;
462 struct processtop *parent;
463 struct files *file;
464 unsigned long timestamp;
465 int64_t pid;
466 char *file_name;
467 int fd;
468
469 timestamp = bt_ctf_get_timestamp(call_data);
470 if (timestamp == -1ULL)
471 goto error;
472
473 scope = bt_ctf_get_top_level_scope(call_data,
474 BT_EVENT_FIELDS);
475 pid = bt_ctf_get_int64(bt_ctf_get_field(call_data,
476 scope, "_pid"));
477 if (bt_ctf_field_get_error()) {
478 fprintf(stderr, "Missing tid context info\n");
479 goto error;
480 }
481
482 scope = bt_ctf_get_top_level_scope(call_data,
483 BT_EVENT_FIELDS);
484 fd = bt_ctf_get_int64(bt_ctf_get_field(call_data,
485 scope, "_fd"));
486 if (bt_ctf_field_get_error()) {
487 fprintf(stderr, "Missing fd context info\n");
488 goto error;
489 }
490
491 scope = bt_ctf_get_top_level_scope(call_data,
492 BT_EVENT_FIELDS);
493 file_name = bt_ctf_get_string(bt_ctf_get_field(call_data,
494 scope, "_filename"));
495 if (bt_ctf_field_get_error()) {
496 fprintf(stderr, "Missing file name context info\n");
497 goto error;
498 }
499
500 parent = get_proc_pid(&lttngtop, pid, pid, timestamp);
501 parent->files_history = create_file(parent->files_history, file_name);
502 file = parent->files_history->file;
503 edit_file(parent, file, fd);
504
505 return BT_CB_OK;
506
507 error:
508 return BT_CB_ERROR_STOP;
509 }
This page took 0.038745 seconds and 3 git commands to generate.