Commit | Line | Data |
---|---|---|
9c312311 | 1 | /* This file is part of the Linux Trace Toolkit viewer |
2 | * Copyright (C) 2003-2004 Michel Dagenais | |
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 | |
14 | * along with this program; if not, write to the Free Software | |
15 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, | |
16 | * MA 02111-1307, USA. | |
17 | */ | |
18 | ||
4e4d11b3 | 19 | #ifdef HAVE_CONFIG_H |
20 | #include <config.h> | |
21 | #endif | |
dc877563 | 22 | |
23 | #include <lttv/traceset.h> | |
3e67c985 | 24 | #include <lttv/iattribute.h> |
7a4bdb54 YB |
25 | #include <lttv/state.h> |
26 | #include <lttv/hook.h> | |
f7afe191 | 27 | #include <stdio.h> |
451aaf27 | 28 | #include <babeltrace/babeltrace.h> |
cbb811b3 | 29 | #include <babeltrace/context.h> |
451aaf27 | 30 | #include <babeltrace/ctf/iterator.h> |
7a4bdb54 | 31 | #include <babeltrace/ctf/events.h> |
3685e022 | 32 | |
33 | /* To traverse a tree recursively */ | |
34 | #include <fcntl.h> | |
35 | #include <fts.h> | |
451aaf27 FD |
36 | /* For the use of realpath*/ |
37 | #include <limits.h> | |
38 | #include <stdlib.h> | |
39 | /* For strcpy*/ | |
40 | #include <string.h> | |
3685e022 | 41 | |
dc877563 | 42 | /* A trace is a sequence of events gathered in the same tracing session. The |
43 | events may be stored in several tracefiles in the same directory. | |
44 | A trace set is defined when several traces are to be analyzed together, | |
45 | possibly to study the interactions between events in the different traces. | |
46 | */ | |
47 | ||
dc877563 | 48 | |
7a4bdb54 | 49 | LttvTraceset *lttv_traceset_new(void) |
dc877563 | 50 | { |
90e19f82 | 51 | LttvTraceset *s; |
7a4bdb54 | 52 | struct bt_iter_pos begin_pos; |
dc877563 | 53 | |
90e19f82 AM |
54 | s = g_new(LttvTraceset, 1); |
55 | s->filename = NULL; | |
56 | s->traces = g_ptr_array_new(); | |
cbb811b3 | 57 | s->context = bt_context_create(); |
90e19f82 | 58 | s->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL); |
7a4bdb54 YB |
59 | //TODO remove this when we have really mecanism |
60 | //s->tmpState = g_new(LttvTraceState *, 1); | |
61 | //lttv_trace_state_init(s->tmpState,0); | |
7a4bdb54 | 62 | |
7a4bdb54 YB |
63 | s->iter = 0; |
64 | s->event_hooks = lttv_hooks_new(); | |
451aaf27 | 65 | |
115c78c2 | 66 | s->state_trace_handle_index = g_ptr_array_new(); |
7a4bdb54 | 67 | |
90e19f82 | 68 | return s; |
dc877563 | 69 | } |
70 | ||
49bf71b5 | 71 | char * lttv_traceset_name(LttvTraceset * s) |
72 | { | |
90e19f82 | 73 | return s->filename; |
49bf71b5 | 74 | } |
75 | ||
2bc1bcfb | 76 | #ifdef BABEL_CLEANUP |
77 | LttvTrace *lttv_trace_new(LttTrace *t) | |
308711e5 | 78 | { |
90e19f82 | 79 | LttvTrace *new_trace; |
308711e5 | 80 | |
90e19f82 AM |
81 | new_trace = g_new(LttvTrace, 1); |
82 | new_trace->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL); | |
2bc1bcfb | 83 | new_trace->id = t; |
90e19f82 AM |
84 | new_trace->ref_count = 0; |
85 | return new_trace; | |
308711e5 | 86 | } |
2bc1bcfb | 87 | #endif |
451aaf27 FD |
88 | /* |
89 | * get_absolute_pathname : Return the unique pathname in the system | |
90 | * | |
91 | * pathname is the relative path. | |
92 | * | |
93 | * abs_pathname is being set to the absolute path. | |
94 | * | |
95 | */ | |
96 | void get_absolute_pathname(const gchar *pathname, gchar * abs_pathname) | |
97 | { | |
98 | abs_pathname[0] = '\0'; | |
99 | ||
100 | if (realpath(pathname, abs_pathname) != NULL) | |
101 | return; | |
102 | else | |
103 | { | |
104 | /* error, return the original path unmodified */ | |
105 | strcpy(abs_pathname, pathname); | |
106 | return; | |
107 | } | |
108 | return; | |
109 | } | |
110 | ||
111 | ||
308711e5 | 112 | |
2bc1bcfb | 113 | /* |
114 | * lttv_trace_create : Create a trace from a path | |
115 | * | |
116 | * ts is the traceset in which will be contained the trace | |
117 | * | |
118 | * path is the path where to find a trace. It is not recursive. | |
119 | * | |
120 | * This function is static since a trace should always be contained in a | |
121 | * traceset. | |
122 | * | |
123 | * return the created trace or NULL on failure | |
124 | */ | |
125 | static LttvTrace *lttv_trace_create(LttvTraceset *ts, const char *path) | |
126 | { | |
127 | int id = bt_context_add_trace(lttv_traceset_get_context(ts), | |
128 | path, | |
129 | "ctf", | |
130 | NULL, | |
131 | NULL, | |
132 | NULL); | |
133 | if (id < 0) { | |
134 | return NULL; | |
135 | } | |
136 | // Create the trace and save the trace handle id returned by babeltrace | |
137 | LttvTrace *new_trace; | |
138 | ||
139 | new_trace = g_new(LttvTrace, 1); | |
140 | new_trace->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL); | |
141 | new_trace->id = id; | |
142 | new_trace->ref_count = 0; | |
7a4bdb54 YB |
143 | new_trace->traceset = ts; |
144 | new_trace->state = g_new(LttvTraceState,1); | |
145 | lttv_trace_state_init(new_trace->state,new_trace); | |
115c78c2 YB |
146 | |
147 | /* Add the state to the trace_handle to state index */ | |
148 | g_ptr_array_set_size(ts->state_trace_handle_index,id+1); | |
149 | g_ptr_array_index(ts->state_trace_handle_index,id) = new_trace->state; | |
150 | ||
2bc1bcfb | 151 | return new_trace; |
152 | } | |
153 | ||
154 | /* | |
155 | * lttv_trace_create : Create and add a single trace to a traceset | |
156 | * | |
157 | * ts is the traceset in which will be contained the trace | |
158 | * | |
159 | * path is the path where to find a trace. It is not recursive. | |
160 | * | |
161 | * return a positive integer (>=0)on success or -1 on failure | |
162 | */ | |
163 | static int lttv_traceset_create_trace(LttvTraceset *ts, const char *path) | |
164 | { | |
165 | LttvTrace *trace = lttv_trace_create(ts, path); | |
166 | if (trace == NULL) { | |
167 | return -1; | |
168 | } | |
169 | lttv_traceset_add(ts, trace); | |
170 | return 0; | |
171 | } | |
308711e5 | 172 | |
f7afe191 | 173 | LttvTraceset *lttv_traceset_copy(LttvTraceset *s_orig) |
174 | { | |
90e19f82 AM |
175 | guint i; |
176 | LttvTraceset *s; | |
177 | LttvTrace * trace; | |
f7afe191 | 178 | |
90e19f82 AM |
179 | s = g_new(LttvTraceset, 1); |
180 | s->filename = NULL; | |
181 | s->traces = g_ptr_array_new(); | |
115c78c2 | 182 | s->state_trace_handle_index = g_ptr_array_new(); |
90e19f82 AM |
183 | for(i=0;i<s_orig->traces->len;i++) |
184 | { | |
185 | trace = g_ptr_array_index(s_orig->traces, i); | |
186 | trace->ref_count++; | |
2176f952 | 187 | |
7a4bdb54 | 188 | /* WARNING: this is an alias, not a copy. */ |
90e19f82 | 189 | g_ptr_array_add(s->traces, trace); |
115c78c2 YB |
190 | |
191 | g_ptr_array_set_size(s->state_trace_handle_index,trace->id+1); | |
192 | g_ptr_array_index(s->state_trace_handle_index,trace->id) = trace->state; | |
193 | ||
90e19f82 | 194 | } |
cbb811b3 YB |
195 | s->context = s_orig->context; |
196 | bt_context_get(s->context); | |
90e19f82 AM |
197 | s->a = LTTV_ATTRIBUTE(lttv_iattribute_deep_copy(LTTV_IATTRIBUTE(s_orig->a))); |
198 | return s; | |
f7afe191 | 199 | } |
dc877563 | 200 | |
f7afe191 | 201 | |
202 | LttvTraceset *lttv_traceset_load(const gchar *filename) | |
203 | { | |
90e19f82 AM |
204 | LttvTraceset *s = g_new(LttvTraceset,1); |
205 | FILE *tf; | |
f7afe191 | 206 | |
90e19f82 AM |
207 | s->filename = g_strdup(filename); |
208 | tf = fopen(filename,"r"); | |
209 | ||
210 | g_critical("NOT IMPLEMENTED : load traceset data from a XML file"); | |
211 | ||
212 | fclose(tf); | |
213 | return s; | |
f7afe191 | 214 | } |
215 | ||
216 | gint lttv_traceset_save(LttvTraceset *s) | |
217 | { | |
90e19f82 | 218 | FILE *tf; |
f7afe191 | 219 | |
90e19f82 | 220 | tf = fopen(s->filename, "w"); |
f7afe191 | 221 | |
90e19f82 AM |
222 | g_critical("NOT IMPLEMENTED : save traceset data in a XML file"); |
223 | ||
224 | fclose(tf); | |
225 | return 0; | |
f7afe191 | 226 | } |
308711e5 | 227 | |
ba576a78 | 228 | void lttv_traceset_destroy(LttvTraceset *s) |
dc877563 | 229 | { |
90e19f82 | 230 | guint i; |
5e2c04a2 | 231 | |
90e19f82 AM |
232 | for(i=0;i<s->traces->len;i++) { |
233 | LttvTrace *trace = g_ptr_array_index(s->traces, i); | |
234 | lttv_trace_unref(trace); | |
2bc1bcfb | 235 | // todo mdenis 2012-03-27: uncomment when babeltrace gets fixed |
236 | //bt_context_remove_trace(lttv_traceset_get_context(s), trace->id); | |
90e19f82 AM |
237 | if(lttv_trace_get_ref_number(trace) == 0) |
238 | lttv_trace_destroy(trace); | |
239 | } | |
240 | g_ptr_array_free(s->traces, TRUE); | |
cbb811b3 | 241 | bt_context_put(s->context); |
90e19f82 AM |
242 | g_object_unref(s->a); |
243 | g_free(s); | |
dc877563 | 244 | } |
245 | ||
922581a4 YB |
246 | struct bt_context *lttv_traceset_get_context(LttvTraceset *s) |
247 | { | |
248 | return s->context; | |
249 | } | |
250 | ||
7a4bdb54 YB |
251 | LttvTraceset *lttv_trace_get_traceset(LttvTrace *trace) |
252 | { | |
253 | return trace->traceset; | |
254 | } | |
255 | ||
256 | LttvHooks *lttv_traceset_get_hooks(LttvTraceset *s) | |
257 | { | |
258 | return s->event_hooks; | |
259 | } | |
260 | ||
308711e5 | 261 | void lttv_trace_destroy(LttvTrace *t) |
262 | { | |
90e19f82 AM |
263 | g_object_unref(t->a); |
264 | g_free(t); | |
308711e5 | 265 | } |
266 | ||
308711e5 | 267 | void lttv_traceset_add(LttvTraceset *s, LttvTrace *t) |
dc877563 | 268 | { |
90e19f82 AM |
269 | t->ref_count++; |
270 | g_ptr_array_add(s->traces, t); | |
dc877563 | 271 | } |
272 | ||
3685e022 | 273 | int lttv_traceset_add_path(LttvTraceset *ts, char *trace_path) |
2bc1bcfb | 274 | { |
451aaf27 | 275 | |
3685e022 | 276 | FTS *tree; |
277 | FTSENT *node; | |
278 | char * const paths[2] = { trace_path, NULL }; | |
279 | int ret = -1; | |
861fbe5f FD |
280 | |
281 | gboolean metaFileFound = FALSE; | |
451aaf27 | 282 | |
3685e022 | 283 | tree = fts_open(paths, FTS_NOCHDIR | FTS_LOGICAL, 0); |
284 | if (tree == NULL) { | |
285 | g_warning("Cannot traverse \"%s\" for reading.\n", | |
286 | trace_path); | |
287 | return ret; | |
288 | } | |
289 | ||
290 | int dirfd, metafd; | |
291 | while ((node = fts_read(tree))) { | |
292 | ||
293 | if (!(node->fts_info & FTS_D)) | |
294 | continue; | |
295 | ||
296 | dirfd = open(node->fts_accpath, 0); | |
297 | if (dirfd < 0) { | |
298 | g_warning("Unable to open trace " | |
299 | "directory file descriptor : %s.", node->fts_accpath); | |
300 | ret = dirfd; | |
301 | goto error; | |
302 | } | |
303 | ||
304 | // Check if a metadata file exists in the current directory | |
305 | metafd = openat(dirfd, "metadata", O_RDONLY); | |
306 | if (metafd < 0) { | |
307 | ret = close(dirfd); | |
308 | if (ret < 0) { | |
309 | g_warning("Unable to open metadata " | |
310 | "file descriptor : %s.", node->fts_accpath); | |
311 | goto error; | |
312 | } | |
313 | } else { | |
314 | ret = close(metafd); | |
315 | if (ret < 0) { | |
316 | g_warning("Unable to close metadata " | |
317 | "file descriptor : %s.", node->fts_accpath); | |
318 | goto error; | |
319 | } | |
320 | ret = close(dirfd); | |
321 | if (ret < 0) { | |
322 | g_warning("Unable to close trace " | |
323 | "directory file descriptor : %s.", node->fts_accpath); | |
324 | goto error; | |
325 | } | |
326 | ||
327 | ret = lttv_traceset_create_trace(ts, node->fts_accpath); | |
328 | if (ret < 0) { | |
329 | g_warning("Opening trace \"%s\" from %s " | |
330 | "for reading.", node->fts_accpath, trace_path); | |
331 | goto error; | |
332 | } | |
861fbe5f | 333 | metaFileFound = TRUE; |
3685e022 | 334 | } |
335 | } | |
336 | ||
337 | error: | |
338 | ret = fts_close(tree); | |
339 | if (ret < 0) { | |
340 | g_warning("Unable to close tree " | |
341 | "file descriptor : %s.", trace_path); | |
342 | } | |
861fbe5f FD |
343 | if(metaFileFound) |
344 | return ret; | |
345 | else | |
346 | return -1; | |
2bc1bcfb | 347 | } |
dc877563 | 348 | |
861fbe5f | 349 | |
dc877563 | 350 | unsigned lttv_traceset_number(LttvTraceset *s) |
351 | { | |
90e19f82 | 352 | return s->traces->len; |
dc877563 | 353 | } |
354 | ||
355 | ||
308711e5 | 356 | LttvTrace *lttv_traceset_get(LttvTraceset *s, unsigned i) |
dc877563 | 357 | { |
90e19f82 AM |
358 | g_assert(s->traces->len > i); |
359 | return ((LttvTrace *)s->traces->pdata[i]); | |
dc877563 | 360 | } |
361 | ||
362 | ||
ba576a78 | 363 | void lttv_traceset_remove(LttvTraceset *s, unsigned i) |
dc877563 | 364 | { |
90e19f82 AM |
365 | LttvTrace * t; |
366 | g_assert(s->traces->len > i); | |
367 | t = (LttvTrace *)s->traces->pdata[i]; | |
368 | t->ref_count--; | |
2bc1bcfb | 369 | bt_context_remove_trace(lttv_traceset_get_context(s), t->id); |
90e19f82 | 370 | g_ptr_array_remove_index(s->traces, i); |
dc877563 | 371 | } |
372 | ||
373 | ||
374 | /* A set of attributes is attached to each trace set, trace and tracefile | |
90e19f82 | 375 | to store user defined data as needed. */ |
dc877563 | 376 | |
377 | LttvAttribute *lttv_traceset_attribute(LttvTraceset *s) | |
378 | { | |
90e19f82 | 379 | return s->a; |
dc877563 | 380 | } |
381 | ||
382 | ||
308711e5 | 383 | LttvAttribute *lttv_trace_attribute(LttvTrace *t) |
384 | { | |
90e19f82 | 385 | return t->a; |
308711e5 | 386 | } |
387 | ||
2bc1bcfb | 388 | |
389 | gint lttv_trace_get_id(LttvTrace *t) | |
390 | { | |
391 | return t->id; | |
392 | } | |
308711e5 | 393 | |
2176f952 | 394 | guint lttv_trace_get_ref_number(LttvTrace * t) |
395 | { | |
2bc1bcfb | 396 | // todo mdenis: adapt to babeltrace |
90e19f82 | 397 | return t->ref_count; |
2176f952 | 398 | } |
a43d67ba | 399 | |
400 | guint lttv_trace_ref(LttvTrace * t) | |
401 | { | |
90e19f82 AM |
402 | t->ref_count++; |
403 | ||
404 | return t->ref_count; | |
a43d67ba | 405 | } |
406 | ||
407 | guint lttv_trace_unref(LttvTrace * t) | |
408 | { | |
90e19f82 AM |
409 | if(likely(t->ref_count > 0)) |
410 | t->ref_count--; | |
a43d67ba | 411 | |
90e19f82 | 412 | return t->ref_count; |
a43d67ba | 413 | } |
414 | ||
7a4bdb54 YB |
415 | guint lttv_trace_get_num_cpu(LttvTrace *t) |
416 | { | |
417 | #warning "TODO - Set the right number of CPU" | |
418 | return 24; | |
419 | } | |
420 | ||
421 | LttvTracesetPosition *lttv_traceset_create_position(LttvTraceset *traceset) | |
422 | { | |
3d1e7ee5 YB |
423 | LttvTracesetPosition *traceset_pos; |
424 | ||
425 | traceset_pos = g_new(LttvTracesetPosition, 1); | |
426 | ||
427 | /* Check in the new passed */ | |
428 | if(traceset_pos == NULL) { | |
429 | return NULL; | |
430 | } | |
431 | ||
432 | traceset_pos->iter = traceset->iter; | |
433 | traceset_pos->bt_pos = bt_iter_get_pos(bt_ctf_get_iter(traceset->iter)); | |
434 | ||
435 | return traceset_pos; | |
7a4bdb54 YB |
436 | } |
437 | ||
438 | void lttv_traceset_destroy_position(LttvTracesetPosition *traceset_pos) | |
439 | { | |
3d1e7ee5 YB |
440 | bt_iter_free_pos(traceset_pos->bt_pos); |
441 | g_free(traceset_pos); | |
7a4bdb54 YB |
442 | } |
443 | ||
444 | void lttv_traceset_seek_to_position(LttvTracesetPosition *traceset_pos) | |
445 | { | |
3d1e7ee5 | 446 | bt_iter_set_pos(traceset_pos->iter, traceset_pos->bt_pos); |
7a4bdb54 YB |
447 | } |
448 | ||
449 | guint lttv_traceset_get_cpuid_from_event(LttvEvent *event) | |
450 | { | |
451 | struct definition *scope; | |
452 | unsigned long timestamp; | |
453 | unsigned int cpu_id; | |
454 | ||
455 | struct bt_ctf_event *ctf_event = event->bt_event; | |
456 | timestamp = bt_ctf_get_timestamp(ctf_event); | |
457 | if (timestamp == -1ULL) { | |
458 | return 0; | |
459 | } | |
460 | scope = bt_ctf_get_top_level_scope(ctf_event, BT_STREAM_PACKET_CONTEXT); | |
461 | if (bt_ctf_field_get_error()) { | |
462 | return 0; | |
463 | } | |
464 | cpu_id = bt_ctf_get_uint64(bt_ctf_get_field(ctf_event, scope, "cpu_id")); | |
465 | if (bt_ctf_field_get_error()) { | |
466 | return 0; | |
467 | } else { | |
468 | return cpu_id; | |
469 | } | |
470 | } | |
451aaf27 FD |
471 | /* |
472 | * lttv_traceset_get_timestamp_begin : returns the minimum timestamp of | |
473 | * all the traces in the traceset. | |
474 | * | |
475 | */ | |
476 | ||
477 | guint64 lttv_traceset_get_timestamp_begin(LttvTraceset *traceset) | |
478 | { | |
479 | struct bt_context *bt_ctx; | |
480 | bt_ctx = lttv_traceset_get_context(traceset); | |
481 | guint64 timestamp_min = G_MAXUINT64, timestamp_cur = 0; | |
482 | int i; | |
483 | int trace_count; | |
484 | LttvTrace *currentTrace; | |
485 | trace_count = traceset->traces->len; | |
486 | if(trace_count == 0) | |
487 | timestamp_min = 0; | |
488 | else{ | |
489 | timestamp_min = G_MAXUINT64; | |
490 | ||
491 | for(i = 0; i < trace_count;i++) | |
492 | { | |
493 | currentTrace = g_ptr_array_index(traceset->traces,i); | |
494 | timestamp_cur = bt_trace_handle_get_timestamp_begin(bt_ctx, currentTrace->id); | |
495 | if(timestamp_cur < timestamp_min) | |
496 | timestamp_min = timestamp_cur; | |
497 | } | |
498 | } | |
499 | return timestamp_min; | |
500 | } | |
501 | ||
502 | /* | |
503 | * lttv_traceset_get_timestamp_end: returns the maximum timestamp of | |
504 | * all the traces in the traceset. | |
505 | * | |
506 | */ | |
507 | guint64 lttv_traceset_get_timestamp_end(LttvTraceset *traceset) | |
508 | { | |
509 | struct bt_context *bt_ctx; | |
510 | bt_ctx = lttv_traceset_get_context(traceset); | |
511 | guint64 timestamp_max, timestamp_cur = 0; | |
512 | int i; | |
513 | int trace_count; | |
514 | LttvTrace *currentTrace; | |
515 | trace_count = traceset->traces->len; | |
516 | ||
517 | if(trace_count == 0) | |
518 | timestamp_max = 1; | |
519 | else | |
520 | { | |
521 | timestamp_max = 0; | |
522 | for(i =0; i < trace_count;i++) | |
523 | { | |
524 | currentTrace = g_ptr_array_index(traceset->traces,i); | |
525 | timestamp_cur = bt_trace_handle_get_timestamp_end(bt_ctx, currentTrace->id); | |
526 | if(timestamp_cur > timestamp_max) | |
527 | timestamp_max = timestamp_cur; | |
528 | } | |
529 | } | |
530 | return timestamp_max; | |
531 | ||
532 | } | |
7a4bdb54 YB |
533 | |
534 | const char *lttv_traceset_get_name_from_event(LttvEvent *event) | |
535 | { | |
536 | return bt_ctf_event_name(event->bt_event); | |
537 | } |