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 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 #include <babeltrace/babeltrace.h>
29 #include <babeltrace/format.h>
30 #include <babeltrace/context.h>
31 #include <babeltrace/ctf/types.h>
32 #include <babeltrace/ctf-text/types.h>
33 #include <babeltrace/trace-collection.h>
34 #include <babeltrace/ctf-ir/metadata.h> /* for clocks */
35 #include <babeltrace/clock-internal.h>
41 struct ctf_clock
*clock_match
;
42 struct trace_collection
*tc
;
45 static void check_clock_match(gpointer key
, gpointer value
, gpointer user_data
)
47 struct clock_match
*match
= user_data
;
48 struct ctf_clock
*clock_a
= value
, *clock_b
;
50 if (clock_a
->absolute
) {
52 * Absolute time references, such as NTP, are looked up
55 clock_b
= g_hash_table_lookup(match
->clocks
,
56 (gpointer
) (unsigned long) clock_a
->name
);
58 match
->clock_match
= clock_b
;
61 } else if (clock_a
->uuid
!= 0) {
63 * Lookup the the trace clocks into the collection
66 clock_b
= g_hash_table_lookup(match
->clocks
,
67 (gpointer
) (unsigned long) clock_a
->uuid
);
69 match
->clock_match
= clock_b
;
76 * Note: if using a frequency different from 1GHz for clock->offset, it
77 * is recommended to express the seconds in offset_s, otherwise there
78 * will be a loss of precision caused by the limited size of the double
82 uint64_t clock_offset_ns(struct ctf_clock
*clock
)
84 return clock
->offset_s
* 1000000000ULL
85 + clock_cycles_to_ns(clock
, clock
->offset
);
88 static void clock_add(gpointer key
, gpointer value
, gpointer user_data
)
90 struct clock_match
*clock_match
= user_data
;
91 GHashTable
*tc_clocks
= clock_match
->clocks
;
92 struct ctf_clock
*t_clock
= value
;
95 if (t_clock
->absolute
)
100 struct ctf_clock
*tc_clock
;
102 tc_clock
= g_hash_table_lookup(tc_clocks
,
103 (gpointer
) (unsigned long) v
);
106 * For now we only support CTF that has one
107 * single clock uuid or name (absolute ref) per
110 if (g_hash_table_size(tc_clocks
) > 0) {
111 fprintf(stderr
, "[error] Only CTF traces with a single clock description are supported by this babeltrace version.\n");
113 if (!clock_match
->tc
->offset_nr
) {
114 clock_match
->tc
->offset_first
= clock_offset_ns(t_clock
);
115 clock_match
->tc
->delta_offset_first_sum
= 0;
116 clock_match
->tc
->offset_nr
++;
117 clock_match
->tc
->single_clock_offset_avg
=
118 clock_match
->tc
->offset_first
;
120 g_hash_table_insert(tc_clocks
,
121 (gpointer
) (unsigned long) v
,
123 } else if (!t_clock
->absolute
) {
127 * For non-absolute clocks, check that the
128 * offsets match. If not, warn the user that we
129 * do an arbitrary choice.
131 diff_ns
= clock_offset_ns(tc_clock
) - clock_offset_ns(t_clock
);
132 printf_debug("Clock \"%s\" offset between traces has a delta of %" PRIu64
" ns.",
133 g_quark_to_string(tc_clock
->name
),
134 diff_ns
< 0 ? -diff_ns
: diff_ns
);
135 if (diff_ns
> 10000 || diff_ns
< -10000) {
136 fprintf(stderr
, "[warning] Clock \"%s\" offset differs between traces (delta %" PRIu64
" ns). Using average.\n",
137 g_quark_to_string(tc_clock
->name
),
138 diff_ns
< 0 ? -diff_ns
: diff_ns
);
140 /* Compute average */
141 clock_match
->tc
->delta_offset_first_sum
+=
142 clock_offset_ns(t_clock
) - clock_match
->tc
->offset_first
;
143 clock_match
->tc
->offset_nr
++;
144 clock_match
->tc
->single_clock_offset_avg
=
145 clock_match
->tc
->offset_first
146 + (clock_match
->tc
->delta_offset_first_sum
/ clock_match
->tc
->offset_nr
);
147 /* Time need to use offset average */
148 clock_match
->tc
->clock_use_offset_avg
= 1;
154 * Whenever we add a trace to the trace collection, check that we can
155 * correlate this trace with at least one other clock in the trace and
156 * convert the index from cycles to real time.
158 int bt_trace_collection_add(struct trace_collection
*tc
,
159 struct bt_trace_descriptor
*trace
)
167 if (tc
->array
->len
> 1) {
168 struct clock_match clock_match
= {
169 .clocks
= tc
->clocks
,
175 * With two or more traces, we need correlation info
178 g_hash_table_foreach(trace
->clocks
,
181 if (!clock_match
.clock_match
) {
182 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");
187 g_ptr_array_add(tc
->array
, trace
);
188 trace
->collection
= tc
;
191 struct clock_match clock_match
= {
192 .clocks
= tc
->clocks
,
198 * Add each clock from the trace clocks into the trace
201 g_hash_table_foreach(trace
->clocks
,
211 int bt_trace_collection_remove(struct trace_collection
*tc
,
212 struct bt_trace_descriptor
*td
)
217 if (g_ptr_array_remove(tc
->array
, td
)) {
225 void bt_init_trace_collection(struct trace_collection
*tc
)
228 tc
->array
= g_ptr_array_new();
229 tc
->clocks
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
230 tc
->single_clock_offset_avg
= 0;
231 tc
->offset_first
= 0;
232 tc
->delta_offset_first_sum
= 0;
237 * bt_finalize_trace_collection() closes the opened traces for read
238 * and free the memory allocated for trace collection
240 void bt_finalize_trace_collection(struct trace_collection
*tc
)
243 g_ptr_array_free(tc
->array
, TRUE
);
244 g_hash_table_destroy(tc
->clocks
);
This page took 0.034507 seconds and 4 git commands to generate.