add_proc now takes hostname param
[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 char *hostname)
194 {
195 struct processtop *tmp;
196 struct files *tmpfile;
197 int err = 0;
198
199 tmp = get_proc(ctx, tid, comm, timestamp, hostname);
200
201 if (!tmp) {
202 err = -1;
203 goto end;
204 }
205 if (tmp->syscall_info != NULL) {
206 if (tmp->syscall_info->type == __NR_read
207 && ret > 0) {
208 tmp->totalfileread += ret;
209 tmp->fileread += ret;
210 tmpfile = get_file(tmp, tmp->syscall_info->fd);
211 if (tmpfile)
212 tmpfile->read += ret;
213 } else if (tmp->syscall_info->type == __NR_write
214 && ret > 0) {
215 tmp->totalfilewrite += ret;
216 tmp->filewrite += ret;
217 tmpfile = get_file(tmp, tmp->syscall_info->fd);
218 if (tmpfile)
219 tmpfile->write += ret;
220 } else if (tmp->syscall_info->type == __NR_open
221 && ret > 0) {
222 tmpfile = tmp->files_history->file;
223 add_file(tmp, tmpfile, ret);
224 tmpfile->fd = ret;
225 } else {
226 err = -1;
227 }
228 g_free(tmp->syscall_info);
229 tmp->syscall_info = NULL;
230 }
231
232 end:
233 return err;
234 }
235
236 struct syscalls *create_syscall_info(unsigned int type, uint64_t cpu_id,
237 unsigned int tid, int fd)
238 {
239 struct syscalls *syscall_info;
240
241 syscall_info = g_new0(struct syscalls, 1);
242 syscall_info->type = type;
243 syscall_info->cpu_id = cpu_id;
244 syscall_info->tid = tid;
245 syscall_info->fd = fd;
246
247 return syscall_info;
248 }
249
250 struct file_history *create_file(struct file_history *history, char *file_name)
251 {
252 struct files *new_file;
253 struct file_history *new_history;
254
255 new_file = g_new0(struct files, 1);
256 new_history = g_new0(struct file_history, 1);
257 new_file->name = strdup(file_name);
258 new_file->read = 0;
259 new_file->write = 0;
260 new_file->flag = -1;
261 new_history->file = new_file;
262 new_history->next = history;
263
264 return new_history;
265 }
266
267 enum bt_cb_ret handle_exit_syscall(struct bt_ctf_event *call_data,
268 void *private_data)
269 {
270 const struct bt_definition *scope;
271 unsigned long timestamp;
272 char *comm;
273 uint64_t ret, tid;
274 uint64_t cpu_id;
275 char *hostname;
276
277 timestamp = bt_ctf_get_timestamp(call_data);
278 if (timestamp == -1ULL)
279 goto error;
280
281 comm = get_context_comm(call_data);
282 tid = get_context_tid(call_data);
283
284 scope = bt_ctf_get_top_level_scope(call_data,
285 BT_EVENT_FIELDS);
286 ret = bt_ctf_get_int64(bt_ctf_get_field(call_data,
287 scope, "_ret"));
288 if (bt_ctf_field_get_error()) {
289 fprintf(stderr, "Missing ret context info\n");
290 goto error;
291 }
292
293 cpu_id = get_cpu_id(call_data);
294 hostname = get_context_hostname(call_data);
295
296 /*
297 * if we encounter an exit_syscall and
298 * it is not for a syscall read or write
299 * we just abort the execution of this callback
300 */
301 if ((update_iostream_ret(&lttngtop, tid, comm, timestamp, cpu_id,
302 ret, hostname)) < 0)
303 return BT_CB_ERROR_CONTINUE;
304
305 return BT_CB_OK;
306
307 error:
308 return BT_CB_ERROR_STOP;
309 }
310
311
312 enum bt_cb_ret handle_sys_write(struct bt_ctf_event *call_data,
313 void *private_data)
314 {
315 const struct bt_definition *scope;
316 struct processtop *tmp;
317 unsigned long timestamp;
318 uint64_t cpu_id;
319 int64_t tid;
320 char *procname, *hostname;
321 int fd;
322
323 timestamp = bt_ctf_get_timestamp(call_data);
324 if (timestamp == -1ULL)
325 goto error;
326
327 tid = get_context_tid(call_data);
328 cpu_id = get_cpu_id(call_data);
329
330 procname = get_context_comm(call_data);
331 hostname = get_context_hostname(call_data);
332
333 scope = bt_ctf_get_top_level_scope(call_data,
334 BT_EVENT_FIELDS);
335 fd = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
336 scope, "_fd"));
337 if (bt_ctf_field_get_error()) {
338 fprintf(stderr, "Missing fd context info\n");
339 goto error;
340 }
341
342 tmp = get_proc(&lttngtop, tid, procname, timestamp, hostname);
343 if (!tmp)
344 goto end;
345
346 tmp->syscall_info = create_syscall_info(__NR_write, cpu_id, tid, fd);
347
348 insert_file(tmp, fd);
349
350 end:
351 return BT_CB_OK;
352
353 error:
354 return BT_CB_ERROR_STOP;
355 }
356
357 enum bt_cb_ret handle_sys_read(struct bt_ctf_event *call_data,
358 void *private_data)
359 {
360 struct processtop *tmp;
361 const struct bt_definition *scope;
362 unsigned long timestamp;
363 uint64_t cpu_id;
364 int64_t tid;
365 char *procname;
366 int fd;
367 char *hostname;
368
369 timestamp = bt_ctf_get_timestamp(call_data);
370 if (timestamp == -1ULL)
371 goto error;
372
373 tid = get_context_tid(call_data);
374 cpu_id = get_cpu_id(call_data);
375
376 procname = get_context_comm(call_data);
377 hostname = get_context_hostname(call_data);
378
379 scope = bt_ctf_get_top_level_scope(call_data,
380 BT_EVENT_FIELDS);
381 fd = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
382 scope, "_fd"));
383 if (bt_ctf_field_get_error()) {
384 fprintf(stderr, "Missing fd context info\n");
385 goto error;
386 }
387
388 tmp = get_proc(&lttngtop, tid, procname, timestamp, hostname);
389 if (!tmp)
390 goto end;
391
392 tmp->syscall_info = create_syscall_info(__NR_read, cpu_id, tid, fd);
393
394 insert_file(tmp, fd);
395
396 end:
397 return BT_CB_OK;
398
399 error:
400 return BT_CB_ERROR_STOP;
401 }
402
403
404 enum bt_cb_ret handle_sys_open(struct bt_ctf_event *call_data,
405 void *private_data)
406 {
407
408 struct processtop *tmp;
409 const struct bt_definition *scope;
410 unsigned long timestamp;
411 uint64_t cpu_id;
412 int64_t tid;
413 char *procname, *hostname;
414 char *file;
415
416 timestamp = bt_ctf_get_timestamp(call_data);
417 if (timestamp == -1ULL)
418 goto error;
419
420 tid = get_context_tid(call_data);
421 cpu_id = get_cpu_id(call_data);
422
423 procname = get_context_comm(call_data);
424 hostname = get_context_hostname(call_data);
425
426 scope = bt_ctf_get_top_level_scope(call_data,
427 BT_EVENT_FIELDS);
428 file = bt_ctf_get_string(bt_ctf_get_field(call_data,
429 scope, "_filename"));
430 if (bt_ctf_field_get_error()) {
431 fprintf(stderr, "Missing file name context info\n");
432 goto error;
433 }
434
435 tmp = get_proc(&lttngtop, tid, procname, timestamp, hostname);
436 if (!tmp)
437 goto end;
438
439 tmp->syscall_info = create_syscall_info(__NR_open, cpu_id, tid, -1);
440
441 tmp->files_history = create_file(tmp->files_history, file);
442
443 end:
444 return BT_CB_OK;
445
446 error:
447 return BT_CB_ERROR_STOP;
448 }
449
450
451 enum bt_cb_ret handle_sys_close(struct bt_ctf_event *call_data,
452 void *private_data)
453 {
454 const struct bt_definition *scope;
455 struct processtop *tmp;
456 unsigned long timestamp;
457 int64_t tid;
458 char *procname;
459 int fd;
460 char *hostname;
461
462 timestamp = bt_ctf_get_timestamp(call_data);
463 if (timestamp == -1ULL)
464 goto error;
465
466 tid = get_context_tid(call_data);
467
468 procname = get_context_comm(call_data);
469 hostname = get_context_hostname(call_data);
470
471 scope = bt_ctf_get_top_level_scope(call_data,
472 BT_EVENT_FIELDS);
473 fd = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
474 scope, "_fd"));
475 if (bt_ctf_field_get_error()) {
476 fprintf(stderr, "Missing fd context info\n");
477 goto error;
478 }
479
480 tmp = get_proc(&lttngtop, tid, procname, timestamp, hostname);
481 if (!tmp)
482 goto end;
483
484 close_file(tmp, fd);
485
486 end:
487 return BT_CB_OK;
488
489 error:
490 return BT_CB_ERROR_STOP;
491 }
492
493 enum bt_cb_ret handle_statedump_file_descriptor(struct bt_ctf_event *call_data,
494 void *private_data)
495 {
496 const struct bt_definition *scope;
497 struct processtop *parent;
498 struct files *file;
499 unsigned long timestamp;
500 int64_t pid;
501 char *file_name, *hostname;
502 int fd;
503
504 timestamp = bt_ctf_get_timestamp(call_data);
505 if (timestamp == -1ULL)
506 goto error;
507
508 scope = bt_ctf_get_top_level_scope(call_data,
509 BT_EVENT_FIELDS);
510 pid = bt_ctf_get_int64(bt_ctf_get_field(call_data,
511 scope, "_pid"));
512 if (bt_ctf_field_get_error()) {
513 fprintf(stderr, "Missing tid context info\n");
514 goto error;
515 }
516
517 scope = bt_ctf_get_top_level_scope(call_data,
518 BT_EVENT_FIELDS);
519 fd = bt_ctf_get_int64(bt_ctf_get_field(call_data,
520 scope, "_fd"));
521 if (bt_ctf_field_get_error()) {
522 fprintf(stderr, "Missing fd context info\n");
523 goto error;
524 }
525
526 scope = bt_ctf_get_top_level_scope(call_data,
527 BT_EVENT_FIELDS);
528 file_name = bt_ctf_get_string(bt_ctf_get_field(call_data,
529 scope, "_filename"));
530 if (bt_ctf_field_get_error()) {
531 fprintf(stderr, "Missing file name context info\n");
532 goto error;
533 }
534 hostname = get_context_hostname(call_data);
535
536 parent = get_proc_pid(&lttngtop, pid, pid, timestamp, hostname);
537 if (!parent)
538 goto end;
539
540 parent->files_history = create_file(parent->files_history, file_name);
541 file = parent->files_history->file;
542 edit_file(parent, file, fd);
543
544 end:
545 return BT_CB_OK;
546
547 error:
548 return BT_CB_ERROR_STOP;
549 }
This page took 0.039398 seconds and 4 git commands to generate.