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