trimmer: error checking, reporting, begin > end check
[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;
263 }
44d3cbf0 264end:
72208f03
JG
265 bt_put(event);
266 bt_put(clock);
267 bt_put(trace);
268 bt_put(stream);
269 bt_put(stream_class);
270 bt_put(clock_value);
55595636
MD
271 *_event_in_range = in_range;
272 return ret;
44d3cbf0
JG
273}
274
44d3cbf0 275static
72208f03 276int ns_from_integer_field(struct bt_ctf_field *integer, int64_t *ns)
44d3cbf0 277{
72208f03
JG
278 int ret = 0;
279 int is_signed;
280 uint64_t raw_clock_value;
281 struct bt_ctf_field_type *integer_type = NULL;
44d3cbf0 282 struct bt_ctf_clock *clock = NULL;
44d3cbf0
JG
283 struct bt_ctf_clock_value *clock_value = NULL;
284
72208f03
JG
285 integer_type = bt_ctf_field_get_type(integer);
286 assert(integer_type);
287 clock = bt_ctf_field_type_integer_get_mapped_clock(integer_type);
288 if (!clock) {
289 ret = -1;
44d3cbf0
JG
290 goto end;
291 }
292
72208f03
JG
293 is_signed = bt_ctf_field_type_integer_get_signed(integer_type);
294 if (!is_signed) {
295 ret = bt_ctf_field_unsigned_integer_get_value(integer,
296 &raw_clock_value);
297 if (ret) {
44d3cbf0
JG
298 goto end;
299 }
72208f03
JG
300 } else {
301 /* Signed clock values are unsupported. */
302 goto end;
303 }
44d3cbf0 304
72208f03
JG
305 clock_value = bt_ctf_clock_value_create(clock, raw_clock_value);
306 if (!clock_value) {
307 goto end;
308 }
44d3cbf0 309
72208f03
JG
310 ret = bt_ctf_clock_value_get_value_ns_from_epoch(clock_value, ns);
311end:
312 bt_put(integer_type);
313 bt_put(clock);
314 bt_put(clock_value);
315 return ret;
316}
44d3cbf0 317
72208f03 318static
55595636
MD
319enum bt_notification_iterator_status evaluate_packet_notification(
320 struct bt_notification *notification,
321 struct trimmer_bound *begin, struct trimmer_bound *end,
322 bool *_packet_in_range)
72208f03 323{
55595636
MD
324 enum bt_notification_iterator_status ret =
325 BT_NOTIFICATION_ITERATOR_STATUS_OK;
72208f03
JG
326 int64_t begin_ns, pkt_begin_ns, end_ns, pkt_end_ns;
327 bool in_range = true;
328 struct bt_ctf_packet *packet = NULL;
329 struct bt_ctf_field *packet_context = NULL,
330 *timestamp_begin = NULL,
331 *timestamp_end = NULL;
332
333 switch (bt_notification_get_type(notification)) {
334 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
335 packet = bt_notification_packet_begin_get_packet(notification);
44d3cbf0 336 break;
72208f03
JG
337 case BT_NOTIFICATION_TYPE_PACKET_END:
338 packet = bt_notification_packet_end_get_packet(notification);
339 break;
340 default:
55595636 341 break;
44d3cbf0 342 }
72208f03
JG
343 assert(packet);
344
345 packet_context = bt_ctf_packet_get_context(packet);
346 if (!packet_context) {
347 goto end;
348 }
349
350 if (!bt_ctf_field_is_structure(packet_context)) {
351 goto end;
352 }
353
354 timestamp_begin = bt_ctf_field_structure_get_field(
355 packet_context, "timestamp_begin");
356 if (!timestamp_begin || !bt_ctf_field_is_integer(timestamp_begin)) {
357 goto end;
358 }
359 timestamp_end = bt_ctf_field_structure_get_field(
360 packet_context, "timestamp_end");
361 if (!timestamp_end || !bt_ctf_field_is_integer(timestamp_end)) {
362 goto end;
363 }
364
55595636 365 if (ns_from_integer_field(timestamp_begin, &pkt_begin_ns)) {
72208f03
JG
366 goto end;
367 }
55595636 368 if (ns_from_integer_field(timestamp_end, &pkt_end_ns)) {
72208f03
JG
369 goto end;
370 }
371
372 begin_ns = begin->set ? begin->value : INT64_MIN;
373 end_ns = end->set ? end->value : INT64_MAX;
374
375 /*
376 * Accept if there is any overlap between the selected region and the
377 * packet.
378 */
379 in_range = (pkt_end_ns >= begin_ns) && (pkt_begin_ns <= end_ns);
380end:
55595636 381 *_packet_in_range = in_range;
72208f03
JG
382 bt_put(packet);
383 bt_put(packet_context);
384 bt_put(timestamp_begin);
385 bt_put(timestamp_end);
55595636 386 return ret;
72208f03
JG
387}
388
389/* Return true if the notification should be forwarded. */
390static
55595636
MD
391enum bt_notification_iterator_status evaluate_notification(
392 struct bt_notification *notification,
393 struct trimmer_bound *begin, struct trimmer_bound *end,
394 bool *in_range)
72208f03 395{
72208f03 396 enum bt_notification_type type;
55595636
MD
397 enum bt_notification_iterator_status ret =
398 BT_NOTIFICATION_ITERATOR_STATUS_OK;
72208f03
JG
399
400 type = bt_notification_get_type(notification);
401 switch (type) {
402 case BT_NOTIFICATION_TYPE_EVENT:
55595636
MD
403 ret = evaluate_event_notification(notification, begin,
404 end, in_range);
72208f03
JG
405 break;
406 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
407 case BT_NOTIFICATION_TYPE_PACKET_END:
55595636
MD
408 ret = evaluate_packet_notification(notification, begin,
409 end, in_range);
72208f03 410 break;
44d3cbf0 411 default:
72208f03 412 /* Accept all other notifications. */
44d3cbf0
JG
413 break;
414 }
55595636 415 return ret;
cab3f160
JG
416}
417
418BT_HIDDEN
419enum bt_notification_iterator_status trimmer_iterator_next(
420 struct bt_notification_iterator *iterator)
421{
44d3cbf0
JG
422 struct trimmer_iterator *trim_it = NULL;
423 struct bt_component *component = NULL;
424 struct trimmer *trimmer = NULL;
425 struct bt_notification_iterator *source_it = NULL;
426 enum bt_notification_iterator_status ret =
55595636 427 BT_NOTIFICATION_ITERATOR_STATUS_OK;
44d3cbf0 428 enum bt_component_status component_ret;
72208f03 429 bool notification_in_range = false;
cab3f160 430
44d3cbf0
JG
431 trim_it = bt_notification_iterator_get_private_data(iterator);
432 assert(trim_it);
433
434 component = bt_notification_iterator_get_component(iterator);
435 assert(component);
436 trimmer = bt_component_get_private_data(component);
437 assert(trimmer);
438
439 /* FIXME, should handle input iterator groups. */
440 component_ret = bt_component_filter_get_input_iterator(component, 0,
441 &source_it);
442 assert((component_ret == BT_COMPONENT_STATUS_OK) && source_it);
443
72208f03 444 while (!notification_in_range) {
44d3cbf0
JG
445 struct bt_notification *notification;
446
447 ret = bt_notification_iterator_next(source_it);
448 if (ret != BT_NOTIFICATION_ITERATOR_STATUS_OK) {
449 goto end;
450 }
451
452 notification = bt_notification_iterator_get_notification(
453 source_it);
454 if (!notification) {
455 ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
456 goto end;
457 }
458
55595636
MD
459 ret = evaluate_notification(notification,
460 &trimmer->begin, &trimmer->end,
461 &notification_in_range);
72208f03 462 if (notification_in_range) {
44d3cbf0
JG
463 BT_MOVE(trim_it->current_notification, notification);
464 } else {
465 bt_put(notification);
466 }
467 }
cab3f160 468end:
44d3cbf0
JG
469 bt_put(source_it);
470 bt_put(component);
cab3f160
JG
471 return ret;
472}
473
474BT_HIDDEN
475enum bt_notification_iterator_status trimmer_iterator_seek_time(
476 struct bt_notification_iterator *iterator, int64_t time)
477{
478 enum bt_notification_iterator_status ret;
479
480 ret = BT_NOTIFICATION_ITERATOR_STATUS_OK;
481end:
482 return ret;
483}
This page took 0.051787 seconds and 4 git commands to generate.