Decouple component class from plugin subsystem, remove component factory
[babeltrace.git] / plugins / trimmer / iterator.c
1 /*
2 * iterator.c
3 *
4 * Babeltrace Trace Trimmer Iterator
5 *
6 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 *
8 * Author: Jérémie Galarneau <jeremie.galarneau@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 * 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
26 * SOFTWARE.
27 */
28
29 #include "trimmer.h"
30 #include "iterator.h"
31 #include <babeltrace/component/notification/iterator.h>
32 #include <babeltrace/component/notification/notification.h>
33 #include <babeltrace/component/notification/event.h>
34 #include <babeltrace/component/notification/stream.h>
35 #include <babeltrace/component/notification/packet.h>
36 #include <babeltrace/component/filter.h>
37 #include <babeltrace/ctf-ir/event.h>
38 #include <babeltrace/ctf-ir/stream.h>
39 #include <babeltrace/ctf-ir/stream-class.h>
40 #include <babeltrace/ctf-ir/clock-class.h>
41 #include <babeltrace/ctf-ir/packet.h>
42 #include <babeltrace/ctf-ir/trace.h>
43 #include <babeltrace/ctf-ir/fields.h>
44 #include <assert.h>
45
46 static
47 void trimmer_iterator_destroy(struct bt_notification_iterator *it)
48 {
49 struct trimmer_iterator *it_data;
50
51 it_data = bt_notification_iterator_get_private_data(it);
52 assert(it_data);
53
54 if (it_data->input_iterator_group) {
55 g_ptr_array_free(it_data->input_iterator_group, TRUE);
56 }
57 bt_put(it_data->current_notification);
58 g_free(it_data);
59 }
60
61 BT_HIDDEN
62 enum bt_component_status trimmer_iterator_init(struct bt_component *component,
63 struct bt_notification_iterator *iterator)
64 {
65 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
66 enum bt_notification_iterator_status it_ret;
67 struct trimmer_iterator *it_data = g_new0(struct trimmer_iterator, 1);
68
69 if (!it_data) {
70 ret = BT_COMPONENT_STATUS_NOMEM;
71 goto end;
72 }
73
74 /* FIXME init trimmer_iterator */
75 it_ret = bt_notification_iterator_set_private_data(iterator, it_data);
76 if (it_ret) {
77 goto end;
78 }
79
80 it_ret = bt_notification_iterator_set_destroy_cb(iterator,
81 trimmer_iterator_destroy);
82 if (it_ret) {
83 ret = BT_COMPONENT_STATUS_ERROR;
84 goto end;
85 }
86
87 it_ret = bt_notification_iterator_set_next_cb(iterator,
88 trimmer_iterator_next);
89 if (it_ret) {
90 ret = BT_COMPONENT_STATUS_ERROR;
91 goto end;
92 }
93
94 it_ret = bt_notification_iterator_set_get_cb(iterator,
95 trimmer_iterator_get);
96 if (it_ret) {
97 ret = BT_COMPONENT_STATUS_ERROR;
98 goto end;
99 }
100
101 it_ret = bt_notification_iterator_set_seek_time_cb(iterator,
102 trimmer_iterator_seek_time);
103 if (it_ret) {
104 ret = BT_COMPONENT_STATUS_ERROR;
105 goto end;
106 }
107 end:
108 return ret;
109 }
110
111 BT_HIDDEN
112 struct bt_notification *trimmer_iterator_get(
113 struct bt_notification_iterator *iterator)
114 {
115 struct trimmer_iterator *trim_it;
116
117 trim_it = bt_notification_iterator_get_private_data(iterator);
118 assert(trim_it);
119
120 if (!trim_it->current_notification) {
121 enum bt_notification_iterator_status it_ret;
122
123 it_ret = trimmer_iterator_next(iterator);
124 if (it_ret) {
125 goto end;
126 }
127 }
128 end:
129 return bt_get(trim_it->current_notification);
130 }
131
132 static
133 int update_lazy_bound(struct trimmer_bound *bound, const char *name,
134 int64_t ts, bool *lazy_update)
135 {
136 struct tm tm;
137 int64_t value;
138 time_t timeval;
139
140 *lazy_update = false;
141
142 if (!bound->lazy) {
143 return 0;
144 }
145 tm.tm_isdst = -1;
146 timeval = ts / NSEC_PER_SEC;
147
148 if (bound->lazy_values.gmt) {
149 /* Get day, month, year. */
150 if (!gmtime_r(&timeval, &tm)) {
151 printf_error("Failure in gmtime_r()");
152 goto error;
153 }
154 tm.tm_sec = bound->lazy_values.ss;
155 tm.tm_min = bound->lazy_values.mm;
156 tm.tm_hour = bound->lazy_values.hh;
157 timeval = timegm(&tm);
158 if (timeval < 0) {
159 printf_error("Failure in timegm(), incorrectly formatted %s timestamp",
160 name);
161 goto error;
162 }
163 } else {
164 /* Get day, month, year. */
165 if (!localtime_r(&timeval, &tm)) {
166 printf_error("Failure in localtime_r()");
167 goto error;
168 }
169 tm.tm_sec = bound->lazy_values.ss;
170 tm.tm_min = bound->lazy_values.mm;
171 tm.tm_hour = bound->lazy_values.hh;
172 timeval = mktime(&tm);
173 if (timeval < 0) {
174 printf_error("Failure in mktime(), incorrectly formatted %s timestamp",
175 name);
176 goto error;
177 }
178 }
179 value = (int64_t) timeval;
180 value *= NSEC_PER_SEC;
181 value += bound->lazy_values.ns;
182 bound->value = value;
183 bound->set = true;
184 bound->lazy = false;
185 *lazy_update = true;
186 return 0;
187
188 error:
189 return -1;
190 }
191
192 static
193 enum bt_notification_iterator_status
194 evaluate_event_notification(struct bt_notification *notification,
195 struct trimmer_bound *begin, struct trimmer_bound *end,
196 bool *_event_in_range)
197 {
198 int64_t ts;
199 int clock_ret;
200 struct bt_ctf_event *event = NULL;
201 bool in_range = true;
202 struct bt_ctf_clock_class *clock_class = NULL;
203 struct bt_ctf_trace *trace = NULL;
204 struct bt_ctf_stream *stream = NULL;
205 struct bt_ctf_stream_class *stream_class = NULL;
206 struct bt_ctf_clock_value *clock_value = NULL;
207 enum bt_notification_iterator_status ret =
208 BT_NOTIFICATION_ITERATOR_STATUS_OK;
209 bool lazy_update = false;
210
211 event = bt_notification_event_get_event(notification);
212 assert(event);
213
214 stream = bt_ctf_event_get_stream(event);
215 assert(stream);
216
217 stream_class = bt_ctf_stream_get_class(stream);
218 assert(stream_class);
219
220 trace = bt_ctf_stream_class_get_trace(stream_class);
221 assert(trace);
222
223 /* FIXME multi-clock? */
224 clock_class = bt_ctf_trace_get_clock_class(trace, 0);
225 if (!clock_class) {
226 goto end;
227 }
228
229 clock_value = bt_ctf_event_get_clock_value(event, clock_class);
230 if (!clock_value) {
231 printf_error("Failed to retrieve clock value");
232 ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
233 goto end;
234 }
235
236 clock_ret = bt_ctf_clock_value_get_value_ns_from_epoch(
237 clock_value, &ts);
238 if (clock_ret) {
239 printf_error("Failed to retrieve clock value timestamp");
240 ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
241 goto end;
242 }
243 if (update_lazy_bound(begin, "begin", ts, &lazy_update)) {
244 ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
245 goto end;
246 }
247 if (update_lazy_bound(end, "end", ts, &lazy_update)) {
248 ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
249 goto end;
250 }
251 if (lazy_update && begin->set && end->set) {
252 if (begin->value > end->value) {
253 printf_error("Unexpected: time range begin value is above end value");
254 ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
255 goto end;
256 }
257 }
258 if (begin->set && ts < begin->value) {
259 in_range = false;
260 }
261 if (end->set && ts > end->value) {
262 in_range = false;
263 }
264 end:
265 bt_put(event);
266 bt_put(clock_class);
267 bt_put(trace);
268 bt_put(stream);
269 bt_put(stream_class);
270 bt_put(clock_value);
271 *_event_in_range = in_range;
272 return ret;
273 }
274
275 static
276 int ns_from_integer_field(struct bt_ctf_field *integer, int64_t *ns)
277 {
278 int ret = 0;
279 int is_signed;
280 uint64_t raw_clock_value;
281 struct bt_ctf_field_type *integer_type = NULL;
282 struct bt_ctf_clock_class *clock_class = NULL;
283 struct bt_ctf_clock_value *clock_value = NULL;
284
285 integer_type = bt_ctf_field_get_type(integer);
286 assert(integer_type);
287 clock_class = bt_ctf_field_type_integer_get_mapped_clock_class(
288 integer_type);
289 if (!clock_class) {
290 ret = -1;
291 goto end;
292 }
293
294 is_signed = bt_ctf_field_type_integer_get_signed(integer_type);
295 if (!is_signed) {
296 ret = bt_ctf_field_unsigned_integer_get_value(integer,
297 &raw_clock_value);
298 if (ret) {
299 goto end;
300 }
301 } else {
302 /* Signed clock values are unsupported. */
303 goto end;
304 }
305
306 clock_value = bt_ctf_clock_value_create(clock_class, raw_clock_value);
307 if (!clock_value) {
308 goto end;
309 }
310
311 ret = bt_ctf_clock_value_get_value_ns_from_epoch(clock_value, ns);
312 end:
313 bt_put(integer_type);
314 bt_put(clock_class);
315 bt_put(clock_value);
316 return ret;
317 }
318
319 static
320 enum bt_notification_iterator_status evaluate_packet_notification(
321 struct bt_notification *notification,
322 struct trimmer_bound *begin, struct trimmer_bound *end,
323 bool *_packet_in_range)
324 {
325 enum bt_notification_iterator_status ret =
326 BT_NOTIFICATION_ITERATOR_STATUS_OK;
327 int64_t begin_ns, pkt_begin_ns, end_ns, pkt_end_ns;
328 bool in_range = true;
329 struct bt_ctf_packet *packet = NULL;
330 struct bt_ctf_field *packet_context = NULL,
331 *timestamp_begin = NULL,
332 *timestamp_end = NULL;
333
334 switch (bt_notification_get_type(notification)) {
335 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
336 packet = bt_notification_packet_begin_get_packet(notification);
337 break;
338 case BT_NOTIFICATION_TYPE_PACKET_END:
339 packet = bt_notification_packet_end_get_packet(notification);
340 break;
341 default:
342 break;
343 }
344 assert(packet);
345
346 packet_context = bt_ctf_packet_get_context(packet);
347 if (!packet_context) {
348 goto end;
349 }
350
351 if (!bt_ctf_field_is_structure(packet_context)) {
352 goto end;
353 }
354
355 timestamp_begin = bt_ctf_field_structure_get_field(
356 packet_context, "timestamp_begin");
357 if (!timestamp_begin || !bt_ctf_field_is_integer(timestamp_begin)) {
358 goto end;
359 }
360 timestamp_end = bt_ctf_field_structure_get_field(
361 packet_context, "timestamp_end");
362 if (!timestamp_end || !bt_ctf_field_is_integer(timestamp_end)) {
363 goto end;
364 }
365
366 if (ns_from_integer_field(timestamp_begin, &pkt_begin_ns)) {
367 goto end;
368 }
369 if (ns_from_integer_field(timestamp_end, &pkt_end_ns)) {
370 goto end;
371 }
372
373 begin_ns = begin->set ? begin->value : INT64_MIN;
374 end_ns = end->set ? end->value : INT64_MAX;
375
376 /*
377 * Accept if there is any overlap between the selected region and the
378 * packet.
379 */
380 in_range = (pkt_end_ns >= begin_ns) && (pkt_begin_ns <= end_ns);
381 end:
382 *_packet_in_range = in_range;
383 bt_put(packet);
384 bt_put(packet_context);
385 bt_put(timestamp_begin);
386 bt_put(timestamp_end);
387 return ret;
388 }
389
390 /* Return true if the notification should be forwarded. */
391 static
392 enum bt_notification_iterator_status evaluate_notification(
393 struct bt_notification *notification,
394 struct trimmer_bound *begin, struct trimmer_bound *end,
395 bool *in_range)
396 {
397 enum bt_notification_type type;
398 enum bt_notification_iterator_status ret =
399 BT_NOTIFICATION_ITERATOR_STATUS_OK;
400
401 *in_range = true;
402 type = bt_notification_get_type(notification);
403 switch (type) {
404 case BT_NOTIFICATION_TYPE_EVENT:
405 ret = evaluate_event_notification(notification, begin,
406 end, in_range);
407 break;
408 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
409 case BT_NOTIFICATION_TYPE_PACKET_END:
410 ret = evaluate_packet_notification(notification, begin,
411 end, in_range);
412 break;
413 default:
414 /* Accept all other notifications. */
415 break;
416 }
417 return ret;
418 }
419
420 BT_HIDDEN
421 enum bt_notification_iterator_status trimmer_iterator_next(
422 struct bt_notification_iterator *iterator)
423 {
424 struct trimmer_iterator *trim_it = NULL;
425 struct bt_component *component = NULL;
426 struct trimmer *trimmer = NULL;
427 struct bt_notification_iterator *source_it = NULL;
428 enum bt_notification_iterator_status ret =
429 BT_NOTIFICATION_ITERATOR_STATUS_OK;
430 enum bt_component_status component_ret;
431 bool notification_in_range = false;
432
433 trim_it = bt_notification_iterator_get_private_data(iterator);
434 assert(trim_it);
435
436 component = bt_notification_iterator_get_component(iterator);
437 assert(component);
438 trimmer = bt_component_get_private_data(component);
439 assert(trimmer);
440
441 /* FIXME, should handle input iterator groups. */
442 component_ret = bt_component_filter_get_input_iterator(component, 0,
443 &source_it);
444 assert((component_ret == BT_COMPONENT_STATUS_OK) && source_it);
445
446 while (!notification_in_range) {
447 struct bt_notification *notification;
448
449 ret = bt_notification_iterator_next(source_it);
450 if (ret != BT_NOTIFICATION_ITERATOR_STATUS_OK) {
451 goto end;
452 }
453
454 notification = bt_notification_iterator_get_notification(
455 source_it);
456 if (!notification) {
457 ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
458 goto end;
459 }
460
461 ret = evaluate_notification(notification,
462 &trimmer->begin, &trimmer->end,
463 &notification_in_range);
464 if (notification_in_range) {
465 BT_MOVE(trim_it->current_notification, notification);
466 } else {
467 bt_put(notification);
468 }
469
470 if (ret != BT_NOTIFICATION_ITERATOR_STATUS_OK) {
471 break;
472 }
473 }
474 end:
475 bt_put(source_it);
476 bt_put(component);
477 return ret;
478 }
479
480 BT_HIDDEN
481 enum bt_notification_iterator_status trimmer_iterator_seek_time(
482 struct bt_notification_iterator *iterator, int64_t time)
483 {
484 enum bt_notification_iterator_status ret;
485
486 ret = BT_NOTIFICATION_ITERATOR_STATUS_OK;
487 end:
488 return ret;
489 }
This page took 0.041599 seconds and 4 git commands to generate.