1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
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;
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.
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,
23 #include <lttv/traceset.h>
24 #include <lttv/iattribute.h>
25 #include <lttv/state.h>
26 #include <lttv/event.h>
27 #include <lttv/hook.h>
29 #include <babeltrace/babeltrace.h>
30 #include <babeltrace/context.h>
31 #include <babeltrace/ctf/iterator.h>
32 #include <babeltrace/ctf/events.h>
34 /* To traverse a tree recursively */
36 /* For the use of realpath*/
43 /* A trace is a sequence of events gathered in the same tracing session. The
44 events may be stored in several tracefiles in the same directory.
45 A trace set is defined when several traces are to be analyzed together,
46 possibly to study the interactions between events in the different traces.
50 LttvTraceset
*lttv_traceset_new(void)
53 struct bt_iter_pos begin_pos
;
55 ts
= g_new(LttvTraceset
, 1);
57 ts
->common_path
= NULL
;
58 ts
->traces
= g_ptr_array_new();
59 ts
->context
= bt_context_create();
60 ts
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
62 /*Initialize iterator to the beginning of the traces*/
63 begin_pos
.type
= BT_SEEK_BEGIN
;
64 ts
->iter
= bt_ctf_iter_create(ts
->context
, &begin_pos
, NULL
);
66 ts
->event_hooks
= lttv_hooks_new();
68 ts
->state_trace_handle_index
= g_ptr_array_new();
69 ts
->has_precomputed_states
= FALSE
;
71 ts
->time_span
.start_time
= ltt_time_zero
;
72 ts
->time_span
.end_time
= ltt_time_zero
;
73 lttv_traceset_get_time_span_real(ts
);
77 char * lttv_traceset_name(LttvTraceset
* s
)
83 LttvTrace
*lttv_trace_new(LttTrace
*t
)
87 new_trace
= g_new(LttvTrace
, 1);
88 new_trace
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
90 new_trace
->ref_count
= 0;
95 * get_absolute_pathname : Return the unique pathname in the system
97 * pathname is the relative path.
99 * abs_pathname is being set to the absolute path.
102 void get_absolute_pathname(const gchar
*pathname
, gchar
* abs_pathname
)
104 abs_pathname
[0] = '\0';
106 if (realpath(pathname
, abs_pathname
) != NULL
)
110 /* error, return the original path unmodified */
111 strcpy(abs_pathname
, pathname
);
120 * lttv_trace_create : Create a trace from a path
122 * ts is the traceset in which will be contained the trace
124 * path is the path where to find a trace. It is not recursive.
126 * This function is static since a trace should always be contained in a
129 * return the created trace or NULL on failure
131 static LttvTrace
*lttv_trace_create(LttvTraceset
*ts
, const char *path
)
133 int id
= bt_context_add_trace(lttv_traceset_get_context(ts
),
142 // Create the trace and save the trace handle id returned by babeltrace
143 LttvTrace
*new_trace
;
145 new_trace
= g_new(LttvTrace
, 1);
146 new_trace
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
148 new_trace
->ref_count
= 0;
149 new_trace
->short_name
[0] = '\0';
150 new_trace
->traceset
= ts
;
151 new_trace
->state
= g_new(LttvTraceState
,1);
152 lttv_trace_state_init(new_trace
->state
,new_trace
);
154 /* Add the state to the trace_handle to state index */
155 g_ptr_array_set_size(ts
->state_trace_handle_index
,id
+1);
156 g_ptr_array_index(ts
->state_trace_handle_index
,id
) = new_trace
->state
;
158 /* Find common path */
159 if (ts
->common_path
== NULL
) {
160 ts
->common_path
= strdup(path
);
162 /* TODO ybrosseau 2013-05-24: consider put that in a function */
165 ts
->common_path
!= '\0';
167 if (path
[i
] != ts
->common_path
[i
]) {
168 /* The common path has changed, redo the other traces */
169 for(j
= 0; j
< ts
->traces
->len
; j
++) {
170 LttvTrace
*t
= g_ptr_array_index(ts
->traces
, j
);
171 strncpy(t
->short_name
, t
->full_path
+i
, TRACE_NAME_SIZE
);
177 strncpy(new_trace
->short_name
, path
+i
, TRACE_NAME_SIZE
);
179 new_trace
->full_path
= strdup(path
);
185 * lttv_trace_create : Create and add a single trace to a traceset
187 * ts is the traceset in which will be contained the trace
189 * path is the path where to find a trace. It is not recursive.
191 * return a positive integer (>=0)on success or -1 on failure
193 static int lttv_traceset_create_trace(LttvTraceset
*ts
, const char *path
)
195 LttvTrace
*trace
= lttv_trace_create(ts
, path
);
199 lttv_traceset_add(ts
, trace
);
203 LttvTraceset
*lttv_traceset_copy(LttvTraceset
*s_orig
)
209 s
= g_new(LttvTraceset
, 1);
211 s
->common_path
= strdup(s_orig
->common_path
);
212 s
->traces
= g_ptr_array_new();
213 s
->state_trace_handle_index
= g_ptr_array_new();
214 for(i
=0;i
<s_orig
->traces
->len
;i
++)
216 trace
= g_ptr_array_index(s_orig
->traces
, i
);
219 /* WARNING: this is an alias, not a copy. */
220 g_ptr_array_add(s
->traces
, trace
);
222 g_ptr_array_set_size(s
->state_trace_handle_index
,trace
->id
+1);
223 g_ptr_array_index(s
->state_trace_handle_index
,trace
->id
) = trace
->state
;
226 s
->context
= s_orig
->context
;
227 bt_context_get(s
->context
);
228 s
->a
= LTTV_ATTRIBUTE(lttv_iattribute_deep_copy(LTTV_IATTRIBUTE(s_orig
->a
)));
233 LttvTraceset
*lttv_traceset_load(const gchar
*filename
)
235 LttvTraceset
*s
= g_new(LttvTraceset
,1);
238 s
->filename
= g_strdup(filename
);
239 tf
= fopen(filename
,"r");
241 g_critical("NOT IMPLEMENTED : load traceset data from a XML file");
247 gint
lttv_traceset_save(LttvTraceset
*s
)
251 tf
= fopen(s
->filename
, "w");
253 g_critical("NOT IMPLEMENTED : save traceset data in a XML file");
259 void lttv_traceset_destroy(LttvTraceset
*s
)
263 for(i
=0;i
<s
->traces
->len
;i
++) {
264 LttvTrace
*trace
= g_ptr_array_index(s
->traces
, i
);
265 lttv_trace_unref(trace
);
266 // todo mdenis 2012-03-27: uncomment when babeltrace gets fixed
267 //bt_context_remove_trace(lttv_traceset_get_context(s), trace->id);
268 if(lttv_trace_get_ref_number(trace
) == 0)
269 lttv_trace_destroy(trace
);
271 free(s
->common_path
);
272 g_ptr_array_free(s
->traces
, TRUE
);
273 bt_context_put(s
->context
);
274 g_object_unref(s
->a
);
278 struct bt_context
*lttv_traceset_get_context(LttvTraceset
*s
)
283 LttvTraceset
*lttv_trace_get_traceset(LttvTrace
*trace
)
285 return trace
->traceset
;
288 LttvHooks
*lttv_traceset_get_hooks(LttvTraceset
*s
)
290 return s
->event_hooks
;
293 void lttv_trace_destroy(LttvTrace
*t
)
296 g_object_unref(t
->a
);
300 void lttv_traceset_add(LttvTraceset
*s
, LttvTrace
*t
)
303 g_ptr_array_add(s
->traces
, t
);
306 int lttv_traceset_get_trace_index_from_event(LttvEvent
*event
)
308 LttvTraceset
*ts
= event
->state
->trace
->traceset
;
310 return lttv_traceset_get_trace_index_from_handle_id(ts
, bt_ctf_event_get_handle_id(event
->bt_event
));
313 int lttv_traceset_get_trace_index_from_handle_id(LttvTraceset
*ts
, int handle_id
)
317 /* TODO ybrosseau 2013-05-22: use a map to speedup the lookup */
319 for(i
= 0; i
< ts
->traces
->len
; i
++) {
320 LttvTrace
*t
= g_ptr_array_index(ts
->traces
, i
);
321 if (t
&& t
->id
== handle_id
) {
326 /* Handle id not found */
331 int lttv_traceset_add_path(LttvTraceset
*ts
, char *trace_path
)
335 gboolean metaFileFound
= FALSE
;
337 /* Open top level directory */
338 curdir
= opendir(trace_path
);
339 if (curdir
== NULL
) {
340 g_warning("Cannot open directory %s (%s)", trace_path
, strerror(errno
));
344 // Check if a metadata file exists in the current directory
345 int metafd
= openat(dirfd(curdir
), "metadata", O_RDONLY
);
351 g_warning("Unable to close metadata "
352 "file descriptor : %s.", trace_path
);
356 ret
= lttv_traceset_create_trace(ts
, trace_path
);
358 g_warning("Opening trace \"%s\" "
359 "for reading.", trace_path
);
362 metaFileFound
= TRUE
;
365 struct dirent curentry
;
366 struct dirent
*resultentry
;
367 while ((ret
= readdir_r(curdir
, &curentry
, &resultentry
)) == 0) {
368 if (resultentry
== NULL
) {
372 if (curentry
.d_name
[0] != '.') {
373 if (curentry
.d_type
== DT_DIR
) {
375 char curpath
[PATH_MAX
];
376 snprintf(curpath
, PATH_MAX
, "%s/%s", trace_path
, curentry
.d_name
);
377 ret
= lttv_traceset_add_path(ts
, curpath
);
379 metaFileFound
= TRUE
;
386 g_warning("Invalid readdir");
396 unsigned lttv_traceset_number(LttvTraceset
*s
)
398 return s
->traces
->len
;
402 LttvTrace
*lttv_traceset_get(LttvTraceset
*s
, unsigned i
)
404 g_assert(s
->traces
->len
> i
);
405 return ((LttvTrace
*)s
->traces
->pdata
[i
]);
409 void lttv_traceset_remove(LttvTraceset
*s
, unsigned i
)
412 g_assert(s
->traces
->len
> i
);
413 t
= (LttvTrace
*)s
->traces
->pdata
[i
];
415 bt_context_remove_trace(lttv_traceset_get_context(s
), t
->id
);
416 g_ptr_array_remove_index(s
->traces
, i
);
420 /* A set of attributes is attached to each trace set, trace and tracefile
421 to store user defined data as needed. */
423 LttvAttribute
*lttv_traceset_attribute(LttvTraceset
*s
)
429 LttvAttribute
*lttv_trace_attribute(LttvTrace
*t
)
435 gint
lttv_trace_get_id(LttvTrace
*t
)
440 guint
lttv_trace_get_ref_number(LttvTrace
* t
)
442 // todo mdenis: adapt to babeltrace
446 guint
lttv_trace_ref(LttvTrace
* t
)
453 guint
lttv_trace_unref(LttvTrace
* t
)
455 if(likely(t
->ref_count
> 0))
461 guint
lttv_trace_get_num_cpu(LttvTrace
*t
)
463 #warning "TODO - Set the right number of CPU"
467 LttvTracesetPosition
*lttv_traceset_create_current_position(const LttvTraceset
*traceset
)
469 LttvTracesetPosition
*traceset_pos
;
471 traceset_pos
= g_new(LttvTracesetPosition
, 1);
473 /* Check if the new passed */
474 if(traceset_pos
== NULL
) {
478 traceset_pos
->iter
= traceset
->iter
;
479 traceset_pos
->bt_pos
= bt_iter_get_pos(bt_ctf_get_iter(traceset
->iter
));
480 traceset_pos
->timestamp
= G_MAXUINT64
;
481 traceset_pos
->cpu_id
= INT_MAX
;
486 LttvTracesetPosition
*lttv_traceset_create_time_position(LttvTraceset
*traceset
,
489 LttvTracesetPosition
*traceset_pos
;
491 traceset_pos
= g_new(LttvTracesetPosition
, 1);
493 /* Check if the new passed */
494 if(traceset_pos
== NULL
) {
498 traceset_pos
->iter
= traceset
->iter
;
499 traceset_pos
->bt_pos
= bt_iter_create_time_pos(
500 bt_ctf_get_iter(traceset_pos
->iter
),
501 ltt_time_to_uint64(timestamp
));
502 traceset_pos
->timestamp
= G_MAXUINT64
;
503 traceset_pos
->cpu_id
= INT_MAX
;
507 void lttv_traceset_destroy_position(LttvTracesetPosition
*traceset_pos
)
509 bt_iter_free_pos(traceset_pos
->bt_pos
);
510 g_free(traceset_pos
);
513 void lttv_traceset_seek_to_position(const LttvTracesetPosition
*traceset_pos
)
515 bt_iter_set_pos(bt_ctf_get_iter(traceset_pos
->iter
), traceset_pos
->bt_pos
);
518 guint
lttv_traceset_get_cpuid_from_event(LttvEvent
*event
)
520 unsigned long timestamp
;
523 struct bt_ctf_event
*ctf_event
= event
->bt_event
;
524 timestamp
= bt_ctf_get_timestamp(ctf_event
);
525 if (timestamp
== -1ULL) {
528 const struct bt_definition
*scope
= bt_ctf_get_top_level_scope(ctf_event
, BT_STREAM_PACKET_CONTEXT
);
529 if (bt_ctf_field_get_error()) {
532 cpu_id
= bt_ctf_get_uint64(bt_ctf_get_field(ctf_event
, scope
, "cpu_id"));
533 if (bt_ctf_field_get_error()) {
540 guint64
lttv_traceset_get_timestamp_first_event(LttvTraceset
*ts
)
542 LttvTracesetPosition begin_position
;
543 struct bt_iter_pos pos
;
544 begin_position
.bt_pos
= &pos
;
545 begin_position
.timestamp
= G_MAXUINT64
;
546 begin_position
.cpu_id
= INT_MAX
;
548 /* Assign iterator to the beginning of the traces */
549 begin_position
.bt_pos
->type
= BT_SEEK_BEGIN
;
550 begin_position
.iter
= ts
->iter
;
552 return lttv_traceset_position_get_timestamp(&begin_position
);
555 guint64
lttv_traceset_get_timestamp_last_event(LttvTraceset
*ts
)
557 LttvTracesetPosition last_position
;
558 struct bt_iter_pos pos
;
559 last_position
.bt_pos
= &pos
;
560 last_position
.timestamp
= G_MAXUINT64
;
561 last_position
.cpu_id
= INT_MAX
;
563 /* Assign iterator to the last event of the traces */
564 last_position
.bt_pos
->type
= BT_SEEK_LAST
;
565 last_position
.iter
= ts
->iter
;
567 return lttv_traceset_position_get_timestamp(&last_position
);
571 * lttv_traceset_get_timestamp_begin : returns the minimum timestamp of
572 * all the traces in the traceset.
575 guint64
lttv_traceset_get_timestamp_begin(LttvTraceset
*traceset
)
577 struct bt_context
*bt_ctx
;
578 bt_ctx
= lttv_traceset_get_context(traceset
);
579 guint64 timestamp_min
, timestamp_cur
= 0;
582 LttvTrace
*currentTrace
;
583 trace_count
= traceset
->traces
->len
;
587 timestamp_min
= G_MAXUINT64
;
588 for(i
= 0; i
< trace_count
;i
++)
590 currentTrace
= g_ptr_array_index(traceset
->traces
,i
);
591 timestamp_cur
= bt_trace_handle_get_timestamp_begin(bt_ctx
,
594 if(timestamp_cur
< timestamp_min
)
595 timestamp_min
= timestamp_cur
;
598 return timestamp_min
;
602 * lttv_traceset_get_timestamp_end: returns the maximum timestamp of
603 * all the traces in the traceset.
606 guint64
lttv_traceset_get_timestamp_end(LttvTraceset
*traceset
)
608 struct bt_context
*bt_ctx
;
609 bt_ctx
= lttv_traceset_get_context(traceset
);
610 guint64 timestamp_max
, timestamp_cur
= 0;
613 LttvTrace
*currentTrace
;
614 trace_count
= traceset
->traces
->len
;
616 if(trace_count
== 0){
621 for(i
=0; i
< trace_count
;i
++)
623 currentTrace
= g_ptr_array_index(traceset
->traces
,i
);
624 timestamp_cur
= bt_trace_handle_get_timestamp_end(bt_ctx
,
627 if(timestamp_cur
> timestamp_max
){
628 timestamp_max
= timestamp_cur
;
632 return timestamp_max
;
635 * lttv_traceset_get_time_span_real : return a TimeInterval representing the
636 * minimum timestamp and the maximum timestamp of the traceset.
639 TimeInterval
lttv_traceset_get_time_span_real(LttvTraceset
*ts
)
643 if(ltt_time_compare(ts
->time_span
.start_time
,
644 ltt_time_zero
) == 0 && ts
->traces
->len
> 0){
645 ts
->time_span
.start_time
= ltt_time_from_uint64(
646 lttv_traceset_get_timestamp_first_event(ts
));
647 ts
->time_span
.end_time
= ltt_time_from_uint64(
648 lttv_traceset_get_timestamp_last_event(ts
));
650 return ts
->time_span
;
654 * lttv_traceset_get_time_span : return a TimeInterval representing the
655 * minimum timestamp and the maximum timestamp of the traceset.
658 TimeInterval
lttv_traceset_get_time_span(LttvTraceset
*ts
)
660 if(ltt_time_compare(ts
->time_span
.start_time
, ltt_time_zero
) == 0){
661 ts
->time_span
.start_time
=ltt_time_from_uint64(
662 lttv_traceset_get_timestamp_begin(ts
));
663 ts
->time_span
.end_time
= ltt_time_from_uint64(
664 lttv_traceset_get_timestamp_end(ts
));
666 return ts
->time_span
;
669 const char *lttv_traceset_get_name_from_event(LttvEvent
*event
)
671 return bt_ctf_event_name(event
->bt_event
);
674 int set_values_position(const LttvTracesetPosition
*pos
)
676 LttvTracesetPosition previous_pos
;
677 previous_pos
.iter
= pos
->iter
;
678 previous_pos
.bt_pos
= bt_iter_get_pos(bt_ctf_get_iter(pos
->iter
));
679 /* Seek to the new desired position */
680 lttv_traceset_seek_to_position(pos
);
682 struct bt_ctf_event
*event
= bt_ctf_iter_read_event(pos
->iter
);
685 ((LttvTracesetPosition
*)pos
)->timestamp
= bt_ctf_get_timestamp(event
);
687 LttvEvent lttv_event
;
688 lttv_event
.bt_event
= event
;
689 ((LttvTracesetPosition
*)pos
)->cpu_id
= lttv_traceset_get_cpuid_from_event(<tv_event
);
692 /* The event is null */
696 /* Reassign the previously saved position */
697 lttv_traceset_seek_to_position(&previous_pos
);
698 /*We must desallocate because the function bt_iter_get_pos() does a g_new */
699 bt_iter_free_pos(previous_pos
.bt_pos
);
700 if (pos
->timestamp
== G_MAXUINT64
) {
706 guint64
lttv_traceset_position_get_timestamp(const LttvTracesetPosition
*pos
)
708 if(pos
->timestamp
== G_MAXUINT64
){
709 if(set_values_position(pos
) == 0){
714 return pos
->timestamp
;
717 int lttv_traceset_position_get_cpuid(const LttvTracesetPosition
*pos
){
718 if(pos
->cpu_id
== INT_MAX
){
719 if(set_values_position(pos
) == 0){
726 LttTime
lttv_traceset_position_get_time(const LttvTracesetPosition
*pos
)
728 return ltt_time_from_uint64(lttv_traceset_position_get_timestamp(pos
));
732 /* 0 if equals, other is different */
733 int lttv_traceset_position_compare(const LttvTracesetPosition
*pos1
, const LttvTracesetPosition
*pos2
)
735 #warning " TODO :Rename for lttv_traceset_position_equals && Must return COMPARAISON OF THE 2 POSITION && verify if it is the best way to compare position"
736 if(pos1
== NULL
|| pos2
== NULL
){
741 #ifdef HAVE_BT_ITER_EQUALS_POS
742 if(pos1
->timestamp
== G_MAXUINT64
|| pos2
->timestamp
== G_MAXUINT64
) {
743 res
= bt_iter_equals_pos(pos1
->bt_pos
, pos2
->bt_pos
);
748 guint64 timeStampPos1
,timeStampPos2
;
749 guint cpuId1
, cpuId2
;
751 timeStampPos1
= lttv_traceset_position_get_timestamp(pos1
);
752 timeStampPos2
= lttv_traceset_position_get_timestamp(pos2
);
754 if (timeStampPos1
== timeStampPos2
) {
756 cpuId1
= lttv_traceset_position_get_cpuid(pos1
);
757 cpuId2
= lttv_traceset_position_get_cpuid(pos2
);
759 if(cpuId1
== cpuId2
){
770 int lttv_traceset_position_time_compare(const LttvTracesetPosition
*pos1
,
771 const LttvTracesetPosition
*pos2
)
773 guint64 timeStampPos1
,timeStampPos2
;
775 timeStampPos1
= lttv_traceset_position_get_timestamp(pos1
);
776 timeStampPos2
= lttv_traceset_position_get_timestamp(pos2
);
778 return timeStampPos1
- timeStampPos2
;
780 int lttv_traceset_position_compare_current(const LttvTraceset
*ts
,
781 const LttvTracesetPosition
*pos
)
784 LttvTracesetPosition
*curPos
= lttv_traceset_create_current_position(ts
);
786 result
= lttv_traceset_position_compare(curPos
,pos
);
788 lttv_traceset_destroy_position(curPos
);
793 LttTime
lttv_traceset_get_current_time(const LttvTraceset
*ts
)
795 LttvTracesetPosition
*curPos
= lttv_traceset_create_current_position(ts
);
796 guint64 currentTimestamp
= lttv_traceset_position_get_timestamp(curPos
);
797 lttv_traceset_destroy_position(curPos
);
799 return ltt_time_from_uint64(currentTimestamp
);