Stop trimmer iteration when end bound is reached
[babeltrace.git] / plugins / trimmer / iterator.c
CommitLineData
cab3f160
JG
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/plugin/notification/iterator.h>
44d3cbf0
JG
32#include <babeltrace/plugin/notification/notification.h>
33#include <babeltrace/plugin/notification/event.h>
34#include <babeltrace/plugin/notification/stream.h>
35#include <babeltrace/plugin/notification/packet.h>
36#include <babeltrace/plugin/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.h>
41#include <babeltrace/ctf-ir/packet.h>
42#include <babeltrace/ctf-ir/trace.h>
72208f03 43#include <babeltrace/ctf-ir/fields.h>
44d3cbf0
JG
44#include <assert.h>
45
46static
47void 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);
44d3cbf0
JG
58 g_free(it_data);
59}
cab3f160
JG
60
61BT_HIDDEN
62enum bt_component_status trimmer_iterator_init(struct bt_component *component,
63 struct bt_notification_iterator *iterator)
64{
44d3cbf0 65 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
cab3f160 66 enum bt_notification_iterator_status it_ret;
44d3cbf0
JG
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 }
cab3f160
JG
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 }
107end:
108 return ret;
109}
110
111BT_HIDDEN
112struct bt_notification *trimmer_iterator_get(
113 struct bt_notification_iterator *iterator)
114{
44d3cbf0
JG
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 }
128end:
129 return bt_get(trim_it->current_notification);
130}
131
528debdf
MD
132static
133int update_lazy_bound(struct trimmer_bound *bound, const char *name,
55595636 134 int64_t ts, bool *lazy_update)
528debdf
MD
135{
136 struct tm tm;
137 int64_t value;
138 time_t timeval;
139
55595636
MD
140 *lazy_update = false;
141
528debdf
MD
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)) {
55595636 151 printf_error("Failure in gmtime_r()");
528debdf
MD
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) {
55595636
MD
159 printf_error("Failure in timegm(), incorrectly formatted %s timestamp",
160 name);
528debdf
MD
161 goto error;
162 }
163 } else {
164 /* Get day, month, year. */
165 if (!localtime_r(&timeval, &tm)) {
55595636 166 printf_error("Failure in localtime_r()");
528debdf
MD
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) {
55595636 174 printf_error("Failure in mktime(), incorrectly formatted %s timestamp",
528debdf
MD
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;
55595636 185 *lazy_update = true;
528debdf
MD
186 return 0;
187
188error:
528debdf
MD
189 return -1;
190}
191
44d3cbf0 192static
55595636
MD
193enum bt_notification_iterator_status
194evaluate_event_notification(struct bt_notification *notification,
195 struct trimmer_bound *begin, struct trimmer_bound *end,
196 bool *_event_in_range)
44d3cbf0 197{
72208f03
JG
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 *clock = NULL;
203 struct bt_ctf_trace *trace = NULL;
44d3cbf0 204 struct bt_ctf_stream *stream = NULL;
72208f03
JG
205 struct bt_ctf_stream_class *stream_class = NULL;
206 struct bt_ctf_clock_value *clock_value = NULL;
55595636
MD
207 enum bt_notification_iterator_status ret =
208 BT_NOTIFICATION_ITERATOR_STATUS_OK;
209 bool lazy_update = false;
44d3cbf0 210
72208f03
JG
211 event = bt_notification_event_get_event(notification);
212 assert(event);
44d3cbf0 213
72208f03
JG
214 stream = bt_ctf_event_get_stream(event);
215 assert(stream);
44d3cbf0 216
72208f03
JG
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 = bt_ctf_trace_get_clock(trace, 0);
225 if (!clock) {
226 goto end;
44d3cbf0 227 }
44d3cbf0 228
72208f03
JG
229 clock_value = bt_ctf_event_get_clock_value(event, clock);
230 if (!clock_value) {
55595636
MD
231 printf_error("Failed to retrieve clock value");
232 ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
72208f03 233 goto end;
44d3cbf0 234 }
72208f03
JG
235
236 clock_ret = bt_ctf_clock_value_get_value_ns_from_epoch(
237 clock_value, &ts);
238 if (clock_ret) {
55595636
MD
239 printf_error("Failed to retrieve clock value timestamp");
240 ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
44d3cbf0
JG
241 goto end;
242 }
55595636
MD
243 if (update_lazy_bound(begin, "begin", ts, &lazy_update)) {
244 ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
528debdf
MD
245 goto end;
246 }
55595636
MD
247 if (update_lazy_bound(end, "end", ts, &lazy_update)) {
248 ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
528debdf
MD
249 goto end;
250 }
55595636
MD
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 }
72208f03
JG
258 if (begin->set && ts < begin->value) {
259 in_range = false;
260 }
261 if (end->set && ts > end->value) {
262 in_range = false;
c2535354 263 ret = BT_NOTIFICATION_ITERATOR_STATUS_END;
72208f03 264 }
44d3cbf0 265end:
72208f03
JG
266 bt_put(event);
267 bt_put(clock);
268 bt_put(trace);
269 bt_put(stream);
270 bt_put(stream_class);
271 bt_put(clock_value);
55595636
MD
272 *_event_in_range = in_range;
273 return ret;
44d3cbf0
JG
274}
275
44d3cbf0 276static
72208f03 277int ns_from_integer_field(struct bt_ctf_field *integer, int64_t *ns)
44d3cbf0 278{
72208f03
JG
279 int ret = 0;
280 int is_signed;
281 uint64_t raw_clock_value;
282 struct bt_ctf_field_type *integer_type = NULL;
44d3cbf0 283 struct bt_ctf_clock *clock = NULL;
44d3cbf0
JG
284 struct bt_ctf_clock_value *clock_value = NULL;
285
72208f03
JG
286 integer_type = bt_ctf_field_get_type(integer);
287 assert(integer_type);
288 clock = bt_ctf_field_type_integer_get_mapped_clock(integer_type);
289 if (!clock) {
290 ret = -1;
44d3cbf0
JG
291 goto end;
292 }
293
72208f03
JG
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) {
44d3cbf0
JG
299 goto end;
300 }
72208f03
JG
301 } else {
302 /* Signed clock values are unsupported. */
303 goto end;
304 }
44d3cbf0 305
72208f03
JG
306 clock_value = bt_ctf_clock_value_create(clock, raw_clock_value);
307 if (!clock_value) {
308 goto end;
309 }
44d3cbf0 310
72208f03
JG
311 ret = bt_ctf_clock_value_get_value_ns_from_epoch(clock_value, ns);
312end:
313 bt_put(integer_type);
314 bt_put(clock);
315 bt_put(clock_value);
316 return ret;
317}
44d3cbf0 318
72208f03 319static
55595636
MD
320enum 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)
72208f03 324{
55595636
MD
325 enum bt_notification_iterator_status ret =
326 BT_NOTIFICATION_ITERATOR_STATUS_OK;
72208f03
JG
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);
44d3cbf0 337 break;
72208f03
JG
338 case BT_NOTIFICATION_TYPE_PACKET_END:
339 packet = bt_notification_packet_end_get_packet(notification);
340 break;
341 default:
55595636 342 break;
44d3cbf0 343 }
72208f03
JG
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
55595636 366 if (ns_from_integer_field(timestamp_begin, &pkt_begin_ns)) {
72208f03
JG
367 goto end;
368 }
55595636 369 if (ns_from_integer_field(timestamp_end, &pkt_end_ns)) {
72208f03
JG
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);
c2535354
JG
381 if (pkt_begin_ns > end_ns) {
382 ret = BT_NOTIFICATION_ITERATOR_STATUS_END;
383 }
72208f03 384end:
55595636 385 *_packet_in_range = in_range;
72208f03
JG
386 bt_put(packet);
387 bt_put(packet_context);
388 bt_put(timestamp_begin);
389 bt_put(timestamp_end);
55595636 390 return ret;
72208f03
JG
391}
392
393/* Return true if the notification should be forwarded. */
394static
55595636
MD
395enum bt_notification_iterator_status evaluate_notification(
396 struct bt_notification *notification,
397 struct trimmer_bound *begin, struct trimmer_bound *end,
398 bool *in_range)
72208f03 399{
72208f03 400 enum bt_notification_type type;
55595636
MD
401 enum bt_notification_iterator_status ret =
402 BT_NOTIFICATION_ITERATOR_STATUS_OK;
72208f03
JG
403
404 type = bt_notification_get_type(notification);
405 switch (type) {
406 case BT_NOTIFICATION_TYPE_EVENT:
55595636
MD
407 ret = evaluate_event_notification(notification, begin,
408 end, in_range);
72208f03
JG
409 break;
410 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
411 case BT_NOTIFICATION_TYPE_PACKET_END:
55595636
MD
412 ret = evaluate_packet_notification(notification, begin,
413 end, in_range);
72208f03 414 break;
44d3cbf0 415 default:
72208f03 416 /* Accept all other notifications. */
44d3cbf0
JG
417 break;
418 }
55595636 419 return ret;
cab3f160
JG
420}
421
422BT_HIDDEN
423enum bt_notification_iterator_status trimmer_iterator_next(
424 struct bt_notification_iterator *iterator)
425{
44d3cbf0
JG
426 struct trimmer_iterator *trim_it = NULL;
427 struct bt_component *component = NULL;
428 struct trimmer *trimmer = NULL;
429 struct bt_notification_iterator *source_it = NULL;
430 enum bt_notification_iterator_status ret =
55595636 431 BT_NOTIFICATION_ITERATOR_STATUS_OK;
44d3cbf0 432 enum bt_component_status component_ret;
72208f03 433 bool notification_in_range = false;
cab3f160 434
44d3cbf0
JG
435 trim_it = bt_notification_iterator_get_private_data(iterator);
436 assert(trim_it);
437
438 component = bt_notification_iterator_get_component(iterator);
439 assert(component);
440 trimmer = bt_component_get_private_data(component);
441 assert(trimmer);
442
443 /* FIXME, should handle input iterator groups. */
444 component_ret = bt_component_filter_get_input_iterator(component, 0,
445 &source_it);
446 assert((component_ret == BT_COMPONENT_STATUS_OK) && source_it);
447
72208f03 448 while (!notification_in_range) {
44d3cbf0
JG
449 struct bt_notification *notification;
450
451 ret = bt_notification_iterator_next(source_it);
452 if (ret != BT_NOTIFICATION_ITERATOR_STATUS_OK) {
453 goto end;
454 }
455
456 notification = bt_notification_iterator_get_notification(
457 source_it);
458 if (!notification) {
459 ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
460 goto end;
461 }
462
55595636
MD
463 ret = evaluate_notification(notification,
464 &trimmer->begin, &trimmer->end,
465 &notification_in_range);
72208f03 466 if (notification_in_range) {
44d3cbf0
JG
467 BT_MOVE(trim_it->current_notification, notification);
468 } else {
469 bt_put(notification);
470 }
471 }
cab3f160 472end:
44d3cbf0
JG
473 bt_put(source_it);
474 bt_put(component);
cab3f160
JG
475 return ret;
476}
477
478BT_HIDDEN
479enum bt_notification_iterator_status trimmer_iterator_seek_time(
480 struct bt_notification_iterator *iterator, int64_t time)
481{
482 enum bt_notification_iterator_status ret;
483
484 ret = BT_NOTIFICATION_ITERATOR_STATUS_OK;
485end:
486 return ret;
487}
This page took 0.045859 seconds and 4 git commands to generate.