6 * Copyright 2012 EfficiOS Inc. and Linux Foundation
8 * Author: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
20 #include <babeltrace/babeltrace.h>
21 #include <babeltrace/format.h>
22 #include <babeltrace/context.h>
23 #include <babeltrace/ctf/types.h>
24 #include <babeltrace/ctf-text/types.h>
25 #include <babeltrace/trace-collection.h>
26 #include <babeltrace/ctf-ir/metadata.h> /* for clocks */
27 #include <babeltrace/clock-internal.h>
33 struct ctf_clock
*clock_match
;
34 struct trace_collection
*tc
;
37 static void check_clock_match(gpointer key
, gpointer value
, gpointer user_data
)
39 struct clock_match
*match
= user_data
;
40 struct ctf_clock
*clock_a
= value
, *clock_b
;
42 if (clock_a
->absolute
) {
44 * Absolute time references, such as NTP, are looked up
47 clock_b
= g_hash_table_lookup(match
->clocks
,
48 (gpointer
) (unsigned long) clock_a
->name
);
50 match
->clock_match
= clock_b
;
53 } else if (clock_a
->uuid
!= 0) {
55 * Lookup the the trace clocks into the collection
58 clock_b
= g_hash_table_lookup(match
->clocks
,
59 (gpointer
) (unsigned long) clock_a
->uuid
);
61 match
->clock_match
= clock_b
;
68 * Note: if using a frequency different from 1GHz for clock->offset, it
69 * is recommended to express the seconds in offset_s, otherwise there
70 * will be a loss of precision caused by the limited size of the double
74 uint64_t clock_offset_ns(struct ctf_clock
*clock
)
76 return clock
->offset_s
* 1000000000ULL
77 + clock_cycles_to_ns(clock
, clock
->offset
);
80 static void clock_add(gpointer key
, gpointer value
, gpointer user_data
)
82 struct clock_match
*clock_match
= user_data
;
83 GHashTable
*tc_clocks
= clock_match
->clocks
;
84 struct ctf_clock
*t_clock
= value
;
87 if (t_clock
->absolute
)
92 struct ctf_clock
*tc_clock
;
94 tc_clock
= g_hash_table_lookup(tc_clocks
,
95 (gpointer
) (unsigned long) v
);
98 * For now we only support CTF that has one
99 * single clock uuid or name (absolute ref) per
102 if (g_hash_table_size(tc_clocks
) > 0) {
103 fprintf(stderr
, "[error] Only CTF traces with a single clock description are supported by this babeltrace version.\n");
105 if (!clock_match
->tc
->offset_nr
) {
106 clock_match
->tc
->offset_first
= clock_offset_ns(t_clock
);
107 clock_match
->tc
->delta_offset_first_sum
= 0;
108 clock_match
->tc
->offset_nr
++;
109 clock_match
->tc
->single_clock_offset_avg
=
110 clock_match
->tc
->offset_first
;
112 g_hash_table_insert(tc_clocks
,
113 (gpointer
) (unsigned long) v
,
115 } else if (!t_clock
->absolute
) {
119 * For non-absolute clocks, check that the
120 * offsets match. If not, warn the user that we
121 * do an arbitrary choice.
123 diff_ns
= clock_offset_ns(tc_clock
) - clock_offset_ns(t_clock
);
124 printf_debug("Clock \"%s\" offset between traces has a delta of %" PRIu64
" ns.",
125 g_quark_to_string(tc_clock
->name
),
126 diff_ns
< 0 ? -diff_ns
: diff_ns
);
127 if (diff_ns
> 10000 || diff_ns
< -10000) {
128 fprintf(stderr
, "[warning] Clock \"%s\" offset differs between traces (delta %" PRIu64
" ns). Using average.\n",
129 g_quark_to_string(tc_clock
->name
),
130 diff_ns
< 0 ? -diff_ns
: diff_ns
);
132 /* Compute average */
133 clock_match
->tc
->delta_offset_first_sum
+=
134 clock_offset_ns(t_clock
) - clock_match
->tc
->offset_first
;
135 clock_match
->tc
->offset_nr
++;
136 clock_match
->tc
->single_clock_offset_avg
=
137 clock_match
->tc
->offset_first
138 + (clock_match
->tc
->delta_offset_first_sum
/ clock_match
->tc
->offset_nr
);
139 /* Time need to use offset average */
140 clock_match
->tc
->clock_use_offset_avg
= 1;
146 * Whenever we add a trace to the trace collection, check that we can
147 * correlate this trace with at least one other clock in the trace and
148 * convert the index from cycles to real time.
150 int trace_collection_add(struct trace_collection
*tc
,
151 struct trace_descriptor
*td
)
153 struct ctf_trace
*trace
;
158 trace
= container_of(td
, struct ctf_trace
, parent
);
159 g_ptr_array_add(tc
->array
, td
);
160 trace
->collection
= tc
;
162 if (tc
->array
->len
> 1) {
163 struct clock_match clock_match
= {
164 .clocks
= tc
->clocks
,
170 * With two or more traces, we need correlation info
173 g_hash_table_foreach(trace
->clocks
,
176 if (!clock_match
.clock_match
) {
177 fprintf(stderr
, "[error] No clocks can be correlated and multiple traces are added to the collection. If you are certain those traces can be correlated, try using \"--clock-force-correlate\".\n");
183 struct clock_match clock_match
= {
184 .clocks
= tc
->clocks
,
190 * Add each clock from the trace clocks into the trace
193 g_hash_table_foreach(trace
->clocks
,
203 int trace_collection_remove(struct trace_collection
*tc
,
204 struct trace_descriptor
*td
)
209 if (g_ptr_array_remove(tc
->array
, td
)) {
217 void init_trace_collection(struct trace_collection
*tc
)
220 tc
->array
= g_ptr_array_new();
221 tc
->clocks
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
222 tc
->single_clock_offset_avg
= 0;
223 tc
->offset_first
= 0;
224 tc
->delta_offset_first_sum
= 0;
229 * finalize_trace_collection() closes the opened traces for read
230 * and free the memory allocated for trace collection
232 void finalize_trace_collection(struct trace_collection
*tc
)
235 g_ptr_array_free(tc
->array
, TRUE
);
236 g_hash_table_destroy(tc
->clocks
);
This page took 0.039426 seconds and 4 git commands to generate.