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