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
->uuid
!= 0) {
44 * Lookup the the trace clocks into the collection
47 clock_b
= g_hash_table_lookup(match
->clocks
,
48 (gpointer
) (unsigned long) clock_a
->uuid
);
50 match
->clock_match
= clock_b
;
53 } else if (clock_a
->absolute
) {
55 * Absolute time references, such as NTP, are looked up
58 clock_b
= g_hash_table_lookup(match
->clocks
,
59 (gpointer
) (unsigned long) clock_a
->name
);
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).
101 if (g_hash_table_size(tc_clocks
) > 0) {
102 fprintf(stderr
, "[error] Only CTF traces with a single clock description are supported by this babeltrace version.\n");
104 if (!clock_match
->tc
->offset_nr
) {
105 clock_match
->tc
->offset_first
= clock_offset_ns(t_clock
);
106 clock_match
->tc
->delta_offset_first_sum
= 0;
107 clock_match
->tc
->offset_nr
++;
108 clock_match
->tc
->single_clock_offset_avg
=
109 clock_match
->tc
->offset_first
;
111 g_hash_table_insert(tc_clocks
,
112 (gpointer
) (unsigned long) v
,
118 * Check that the offsets match. If not, warn
119 * the user that we do an arbitrary choice.
121 diff_ns
= clock_offset_ns(tc_clock
) - clock_offset_ns(t_clock
);
122 printf_debug("Clock \"%s\" offset between traces has a delta of %" PRIu64
" ns.",
123 g_quark_to_string(tc_clock
->name
),
124 diff_ns
< 0 ? -diff_ns
: diff_ns
);
125 if (diff_ns
> 10000 || diff_ns
< -10000) {
126 fprintf(stderr
, "[warning] Clock \"%s\" offset differs between traces (delta %" PRIu64
" ns). Using average.\n",
127 g_quark_to_string(tc_clock
->name
),
128 diff_ns
< 0 ? -diff_ns
: diff_ns
);
130 /* Compute average */
131 clock_match
->tc
->delta_offset_first_sum
+=
132 clock_offset_ns(t_clock
) - clock_match
->tc
->offset_first
;
133 clock_match
->tc
->offset_nr
++;
134 clock_match
->tc
->single_clock_offset_avg
=
135 clock_match
->tc
->offset_first
136 + (clock_match
->tc
->delta_offset_first_sum
/ clock_match
->tc
->offset_nr
);
142 * Whenever we add a trace to the trace collection, check that we can
143 * correlate this trace with at least one other clock in the trace and
144 * convert the index from cycles to real time.
146 int trace_collection_add(struct trace_collection
*tc
,
147 struct trace_descriptor
*td
)
149 struct ctf_trace
*trace
;
154 trace
= container_of(td
, struct ctf_trace
, parent
);
155 g_ptr_array_add(tc
->array
, td
);
156 trace
->collection
= tc
;
158 if (tc
->array
->len
> 1) {
159 struct clock_match clock_match
= {
160 .clocks
= tc
->clocks
,
166 * With two or more traces, we need correlation info
169 g_hash_table_foreach(trace
->clocks
,
172 if (!clock_match
.clock_match
) {
173 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");
179 struct clock_match clock_match
= {
180 .clocks
= tc
->clocks
,
186 * Add each clock from the trace clocks into the trace
189 g_hash_table_foreach(trace
->clocks
,
199 int trace_collection_remove(struct trace_collection
*tc
,
200 struct trace_descriptor
*td
)
205 if (g_ptr_array_remove(tc
->array
, td
)) {
213 void init_trace_collection(struct trace_collection
*tc
)
216 tc
->array
= g_ptr_array_new();
217 tc
->clocks
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
218 tc
->single_clock_offset_avg
= 0;
219 tc
->offset_first
= 0;
220 tc
->delta_offset_first_sum
= 0;
225 * finalize_trace_collection() closes the opened traces for read
226 * and free the memory allocated for trace collection
228 void finalize_trace_collection(struct trace_collection
*tc
)
231 g_ptr_array_free(tc
->array
, TRUE
);
232 g_hash_table_destroy(tc
->clocks
);
This page took 0.033738 seconds and 5 git commands to generate.