Decouple component class from plugin subsystem, remove component factory
[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"
33b34c43
PP
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>
44d3cbf0
JG
37#include <babeltrace/ctf-ir/event.h>
38#include <babeltrace/ctf-ir/stream.h>
39#include <babeltrace/ctf-ir/stream-class.h>
ac0c6bdd 40#include <babeltrace/ctf-ir/clock-class.h>
44d3cbf0
JG
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;
ac0c6bdd 202 struct bt_ctf_clock_class *clock_class = NULL;
72208f03 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? */
ac0c6bdd
PP
224 clock_class = bt_ctf_trace_get_clock_class(trace, 0);
225 if (!clock_class) {
72208f03 226 goto end;
44d3cbf0 227 }
44d3cbf0 228
ac0c6bdd 229 clock_value = bt_ctf_event_get_clock_value(event, clock_class);
72208f03 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 265 bt_put(event);
ac0c6bdd 266 bt_put(clock_class);
72208f03
JG
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;
ac0c6bdd 282 struct bt_ctf_clock_class *clock_class = 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);
ac0c6bdd
PP
287 clock_class = bt_ctf_field_type_integer_get_mapped_clock_class(
288 integer_type);
289 if (!clock_class) {
72208f03 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
ac0c6bdd 306 clock_value = bt_ctf_clock_value_create(clock_class, raw_clock_value);
72208f03
JG
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);
ac0c6bdd 314 bt_put(clock_class);
72208f03
JG
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);
381end:
55595636 382 *_packet_in_range = in_range;
72208f03
JG
383 bt_put(packet);
384 bt_put(packet_context);
385 bt_put(timestamp_begin);
386 bt_put(timestamp_end);
55595636 387 return ret;
72208f03
JG
388}
389
390/* Return true if the notification should be forwarded. */
391static
55595636
MD
392enum bt_notification_iterator_status evaluate_notification(
393 struct bt_notification *notification,
394 struct trimmer_bound *begin, struct trimmer_bound *end,
395 bool *in_range)
72208f03 396{
72208f03 397 enum bt_notification_type type;
55595636
MD
398 enum bt_notification_iterator_status ret =
399 BT_NOTIFICATION_ITERATOR_STATUS_OK;
72208f03 400
b61397c4 401 *in_range = true;
72208f03
JG
402 type = bt_notification_get_type(notification);
403 switch (type) {
404 case BT_NOTIFICATION_TYPE_EVENT:
55595636
MD
405 ret = evaluate_event_notification(notification, begin,
406 end, in_range);
72208f03
JG
407 break;
408 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
409 case BT_NOTIFICATION_TYPE_PACKET_END:
55595636
MD
410 ret = evaluate_packet_notification(notification, begin,
411 end, in_range);
72208f03 412 break;
44d3cbf0 413 default:
72208f03 414 /* Accept all other notifications. */
44d3cbf0
JG
415 break;
416 }
55595636 417 return ret;
cab3f160
JG
418}
419
420BT_HIDDEN
421enum bt_notification_iterator_status trimmer_iterator_next(
422 struct bt_notification_iterator *iterator)
423{
44d3cbf0
JG
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 =
55595636 429 BT_NOTIFICATION_ITERATOR_STATUS_OK;
44d3cbf0 430 enum bt_component_status component_ret;
72208f03 431 bool notification_in_range = false;
cab3f160 432
44d3cbf0
JG
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
72208f03 446 while (!notification_in_range) {
44d3cbf0
JG
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
55595636
MD
461 ret = evaluate_notification(notification,
462 &trimmer->begin, &trimmer->end,
463 &notification_in_range);
72208f03 464 if (notification_in_range) {
44d3cbf0
JG
465 BT_MOVE(trim_it->current_notification, notification);
466 } else {
467 bt_put(notification);
468 }
6d5f6792
JG
469
470 if (ret != BT_NOTIFICATION_ITERATOR_STATUS_OK) {
471 break;
472 }
44d3cbf0 473 }
cab3f160 474end:
44d3cbf0
JG
475 bt_put(source_it);
476 bt_put(component);
cab3f160
JG
477 return ret;
478}
479
480BT_HIDDEN
481enum 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;
487end:
488 return ret;
489}
This page took 0.085625 seconds and 4 git commands to generate.