cleanup: protected -> hidden: cleanup symbol table
[babeltrace.git] / lib / trace-collection.c
1 /*
2 * trace-collection.c
3 *
4 * Babeltrace Library
5 *
6 * Copyright 2012 EfficiOS Inc. and Linux Foundation
7 *
8 * Author: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
9 *
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:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 */
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
28 #include <inttypes.h>
29
30 struct clock_match {
31 GHashTable *clocks;
32 struct ctf_clock *clock_match;
33 struct trace_collection *tc;
34 };
35
36 static void check_clock_match(gpointer key, gpointer value, gpointer user_data)
37 {
38 struct clock_match *match = user_data;
39 struct ctf_clock *clock_a = value, *clock_b;
40
41 if (clock_a->uuid != 0) {
42 /*
43 * Lookup the the trace clocks into the collection
44 * clocks.
45 */
46 clock_b = g_hash_table_lookup(match->clocks,
47 (gpointer) (unsigned long) clock_a->uuid);
48 if (clock_b) {
49 match->clock_match = clock_b;
50 return;
51 }
52 } else if (clock_a->absolute) {
53 /*
54 * Absolute time references, such as NTP, are looked up
55 * by clock name.
56 */
57 clock_b = g_hash_table_lookup(match->clocks,
58 (gpointer) (unsigned long) clock_a->name);
59 if (clock_b) {
60 match->clock_match = clock_b;
61 return;
62 }
63 }
64 }
65
66 static void clock_add(gpointer key, gpointer value, gpointer user_data)
67 {
68 struct clock_match *clock_match = user_data;
69 GHashTable *tc_clocks = clock_match->clocks;
70 struct ctf_clock *t_clock = value;
71 GQuark v;
72
73 if (t_clock->absolute)
74 v = t_clock->name;
75 else
76 v = t_clock->uuid;
77 if (v) {
78 struct ctf_clock *tc_clock;
79
80 tc_clock = g_hash_table_lookup(tc_clocks,
81 (gpointer) (unsigned long) v);
82 if (!tc_clock) {
83 /*
84 * For now, we only support CTF that has one
85 * single clock uuid or name (absolute ref).
86 */
87 if (g_hash_table_size(tc_clocks) > 0) {
88 fprintf(stderr, "[error] Only CTF traces with a single clock description are supported by this babeltrace version.\n");
89 }
90 if (!clock_match->tc->offset_nr) {
91 clock_match->tc->offset_first =
92 (t_clock->offset_s * 1000000000ULL) + t_clock->offset;
93 clock_match->tc->delta_offset_first_sum = 0;
94 clock_match->tc->offset_nr++;
95 clock_match->tc->single_clock_offset_avg =
96 clock_match->tc->offset_first;
97 }
98 g_hash_table_insert(tc_clocks,
99 (gpointer) (unsigned long) v,
100 value);
101 } else {
102 int64_t diff_ns;
103
104 /*
105 * Check that the offsets match. If not, warn
106 * the user that we do an arbitrary choice.
107 */
108 diff_ns = tc_clock->offset_s;
109 diff_ns -= t_clock->offset_s;
110 diff_ns *= 1000000000ULL;
111 diff_ns += tc_clock->offset;
112 diff_ns -= t_clock->offset;
113 printf_debug("Clock \"%s\" offset between traces has a delta of %" PRIu64 " ns.",
114 g_quark_to_string(tc_clock->name),
115 diff_ns < 0 ? -diff_ns : diff_ns);
116 if (diff_ns > 10000) {
117 fprintf(stderr, "[warning] Clock \"%s\" offset differs between traces (delta %" PRIu64 " ns). Using average.\n",
118 g_quark_to_string(tc_clock->name),
119 diff_ns < 0 ? -diff_ns : diff_ns);
120 }
121 /* Compute average */
122 clock_match->tc->delta_offset_first_sum +=
123 (t_clock->offset_s * 1000000000ULL) + t_clock->offset
124 - clock_match->tc->offset_first;
125 clock_match->tc->offset_nr++;
126 clock_match->tc->single_clock_offset_avg =
127 clock_match->tc->offset_first
128 + (clock_match->tc->delta_offset_first_sum / clock_match->tc->offset_nr);
129 }
130 }
131 }
132
133 /*
134 * Whenever we add a trace to the trace collection, check that we can
135 * correlate this trace with at least one other clock in the trace and
136 * convert the index from cycles to real time.
137 */
138 int trace_collection_add(struct trace_collection *tc,
139 struct trace_descriptor *td)
140 {
141 struct ctf_trace *trace = container_of(td, struct ctf_trace, parent);
142
143 g_ptr_array_add(tc->array, td);
144 trace->collection = tc;
145
146 if (tc->array->len > 1) {
147 struct clock_match clock_match = {
148 .clocks = tc->clocks,
149 .clock_match = NULL,
150 .tc = NULL,
151 };
152
153 /*
154 * With two or more traces, we need correlation info
155 * avalable.
156 */
157 g_hash_table_foreach(trace->clocks,
158 check_clock_match,
159 &clock_match);
160 if (!clock_match.clock_match) {
161 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");
162 goto error;
163 }
164 }
165
166 {
167 struct clock_match clock_match = {
168 .clocks = tc->clocks,
169 .clock_match = NULL,
170 .tc = tc,
171 };
172
173 /*
174 * Add each clock from the trace clocks into the trace
175 * collection clocks.
176 */
177 g_hash_table_foreach(trace->clocks,
178 clock_add,
179 &clock_match);
180 }
181
182 return 0;
183 error:
184 return -EPERM;
185 }
186
187 int trace_collection_remove(struct trace_collection *tc,
188 struct trace_descriptor *td)
189 {
190 if (g_ptr_array_remove(tc->array, td)) {
191 return 0;
192 } else {
193 return -1;
194 }
195
196 }
197
198 void init_trace_collection(struct trace_collection *tc)
199 {
200 tc->array = g_ptr_array_new();
201 tc->clocks = g_hash_table_new(g_direct_hash, g_direct_equal);
202 tc->single_clock_offset_avg = 0;
203 tc->offset_first = 0;
204 tc->delta_offset_first_sum = 0;
205 tc->offset_nr = 0;
206 }
207
208 /*
209 * finalize_trace_collection() closes the opened traces for read
210 * and free the memory allocated for trace collection
211 */
212 void finalize_trace_collection(struct trace_collection *tc)
213 {
214 g_ptr_array_free(tc->array, TRUE);
215 g_hash_table_destroy(tc->clocks);
216 }
This page took 0.050606 seconds and 4 git commands to generate.