Fix : only one iterator per context
[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.
136 */
137 int trace_collection_add(struct trace_collection *tc,
138 struct trace_descriptor *td)
139 {
140 struct ctf_trace *trace = container_of(td, struct ctf_trace, parent);
141
142 g_ptr_array_add(tc->array, td);
143 trace->collection = tc;
144
145 if (tc->array->len > 1) {
146 struct clock_match clock_match = {
147 .clocks = tc->clocks,
148 .clock_match = NULL,
149 .tc = NULL,
150 };
151
152 /*
153 * With two or more traces, we need correlation info
154 * avalable.
155 */
156 g_hash_table_foreach(trace->clocks,
157 check_clock_match,
158 &clock_match);
159 if (!clock_match.clock_match) {
160 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");
161 goto error;
162 }
163 }
164
165 {
166 struct clock_match clock_match = {
167 .clocks = tc->clocks,
168 .clock_match = NULL,
169 .tc = tc,
170 };
171
172 /*
173 * Add each clock from the trace clocks into the trace
174 * collection clocks.
175 */
176 g_hash_table_foreach(trace->clocks,
177 clock_add,
178 &clock_match);
179 }
180 return 0;
181 error:
182 return -EPERM;
183 }
184
185 int trace_collection_remove(struct trace_collection *tc,
186 struct trace_descriptor *td)
187 {
188 if (g_ptr_array_remove(tc->array, td)) {
189 return 0;
190 } else {
191 return -1;
192 }
193
194 }
195
196 void init_trace_collection(struct trace_collection *tc)
197 {
198 tc->array = g_ptr_array_new();
199 tc->clocks = g_hash_table_new(g_direct_hash, g_direct_equal);
200 tc->single_clock_offset_avg = 0;
201 tc->offset_first = 0;
202 tc->delta_offset_first_sum = 0;
203 tc->offset_nr = 0;
204 }
205
206 /*
207 * finalize_trace_collection() closes the opened traces for read
208 * and free the memory allocated for trace collection
209 */
210 void finalize_trace_collection(struct trace_collection *tc)
211 {
212 g_ptr_array_free(tc->array, TRUE);
213 g_hash_table_destroy(tc->clocks);
214 }
This page took 0.03695 seconds and 4 git commands to generate.