Split CTF IR and CTF writer APIs and implementations
[babeltrace.git] / lib / ctf-writer / stream-class.c
1 /*
2 * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24 #define BT_LOG_TAG "CTF-WRITER-STREAM-CLASS"
25 #include <babeltrace/lib-logging-internal.h>
26
27 #include <babeltrace/ref.h>
28 #include <babeltrace/ctf-writer/writer-internal.h>
29 #include <babeltrace/ctf-writer/stream-class-internal.h>
30 #include <babeltrace/ctf-writer/field-types-internal.h>
31 #include <babeltrace/ctf-writer/event-internal.h>
32 #include <babeltrace/ctf-writer/event.h>
33 #include <babeltrace/ctf-writer/trace.h>
34 #include <babeltrace/compiler-internal.h>
35 #include <babeltrace/assert-internal.h>
36 #include <babeltrace/assert-pre-internal.h>
37 #include <inttypes.h>
38
39 static
40 int init_event_header(struct bt_ctf_stream_class *stream_class)
41 {
42 int ret = 0;
43 struct bt_ctf_field_type *event_header_type =
44 bt_ctf_field_type_structure_create();
45 struct bt_ctf_field_type *_uint32_t =
46 get_field_type(FIELD_TYPE_ALIAS_UINT32_T);
47 struct bt_ctf_field_type *_uint64_t =
48 get_field_type(FIELD_TYPE_ALIAS_UINT64_T);
49
50 if (!event_header_type) {
51 BT_LOGE_STR("Cannot create empty structure field type.");
52 ret = -1;
53 goto end;
54 }
55
56 ret = bt_ctf_field_type_structure_add_field(event_header_type,
57 _uint32_t, "id");
58 if (ret) {
59 BT_LOGE_STR("Cannot add `id` field to event header field type.");
60 goto end;
61 }
62
63 ret = bt_ctf_field_type_structure_add_field(event_header_type,
64 _uint64_t, "timestamp");
65 if (ret) {
66 BT_LOGE_STR("Cannot add `timestamp` field to event header field type.");
67 goto end;
68 }
69
70 bt_put(stream_class->common.event_header_field_type);
71 stream_class->common.event_header_field_type =
72 (void *) event_header_type;
73 event_header_type = NULL;
74
75 end:
76 if (ret) {
77 bt_put(event_header_type);
78 }
79
80 bt_put(_uint32_t);
81 bt_put(_uint64_t);
82 return ret;
83 }
84
85 static
86 int init_packet_context(struct bt_ctf_stream_class *stream_class)
87 {
88 int ret = 0;
89 struct bt_ctf_field_type *packet_context_type =
90 bt_ctf_field_type_structure_create();
91 struct bt_ctf_field_type *_uint64_t =
92 get_field_type(FIELD_TYPE_ALIAS_UINT64_T);
93 struct bt_ctf_field_type *ts_begin_end_uint64_t;
94
95 if (!packet_context_type) {
96 BT_LOGE_STR("Cannot create empty structure field type.");
97 ret = -1;
98 goto end;
99 }
100
101 ts_begin_end_uint64_t = bt_ctf_field_type_copy(_uint64_t);
102 if (!ts_begin_end_uint64_t) {
103 BT_LOGE_STR("Cannot copy integer field type for `timestamp_begin` and `timestamp_end` fields.");
104 ret = -1;
105 goto end;
106 }
107
108 /*
109 * We create a stream packet context as proposed in the CTF
110 * specification.
111 */
112 ret = bt_ctf_field_type_structure_add_field(packet_context_type,
113 ts_begin_end_uint64_t, "timestamp_begin");
114 if (ret) {
115 BT_LOGE_STR("Cannot add `timestamp_begin` field to event header field type.");
116 goto end;
117 }
118
119 ret = bt_ctf_field_type_structure_add_field(packet_context_type,
120 ts_begin_end_uint64_t, "timestamp_end");
121 if (ret) {
122 BT_LOGE_STR("Cannot add `timestamp_end` field to event header field type.");
123 goto end;
124 }
125
126 ret = bt_ctf_field_type_structure_add_field(packet_context_type,
127 _uint64_t, "content_size");
128 if (ret) {
129 BT_LOGE_STR("Cannot add `content_size` field to event header field type.");
130 goto end;
131 }
132
133 ret = bt_ctf_field_type_structure_add_field(packet_context_type,
134 _uint64_t, "packet_size");
135 if (ret) {
136 BT_LOGE_STR("Cannot add `packet_size` field to event header field type.");
137 goto end;
138 }
139
140 ret = bt_ctf_field_type_structure_add_field(packet_context_type,
141 _uint64_t, "events_discarded");
142 if (ret) {
143 BT_LOGE_STR("Cannot add `events_discarded` field to event header field type.");
144 goto end;
145 }
146
147 bt_put(stream_class->common.packet_context_field_type);
148 stream_class->common.packet_context_field_type =
149 (void *) packet_context_type;
150 packet_context_type = NULL;
151
152 end:
153 if (ret) {
154 bt_put(packet_context_type);
155 goto end;
156 }
157
158 bt_put(_uint64_t);
159 bt_put(ts_begin_end_uint64_t);
160 return ret;
161 }
162
163 static
164 void bt_ctf_stream_class_destroy(struct bt_object *obj)
165 {
166 struct bt_ctf_stream_class *stream_class;
167
168 stream_class = (void *) obj;
169 BT_LOGD("Destroying CTF writer stream class: addr=%p, name=\"%s\", id=%" PRId64,
170 stream_class, bt_ctf_stream_class_get_name(stream_class),
171 bt_ctf_stream_class_get_id(stream_class));
172 bt_stream_class_common_finalize(BT_TO_COMMON(stream_class));
173 bt_put(stream_class->clock);
174 g_free(stream_class);
175 }
176
177 struct bt_ctf_stream_class *bt_ctf_stream_class_create(const char *name)
178 {
179 struct bt_ctf_stream_class *stream_class;
180 int ret;
181
182 BT_LOGD("Creating CTF writer stream class object: name=\"%s\"", name);
183 stream_class = g_new0(struct bt_ctf_stream_class, 1);
184 if (!stream_class) {
185 BT_LOGE_STR("Failed to allocate one CTF writer stream class.");
186 goto error;
187 }
188
189 ret = bt_stream_class_common_initialize(BT_TO_COMMON(stream_class),
190 name, bt_ctf_stream_class_destroy);
191 if (ret) {
192 /* bt_stream_class_common_initialize() logs errors */
193 goto error;
194 }
195
196 ret = init_event_header(stream_class);
197 if (ret) {
198 BT_LOGE_STR("Cannot initialize stream class's event header field type.");
199 goto error;
200 }
201
202 ret = init_packet_context(stream_class);
203 if (ret) {
204 BT_LOGE_STR("Cannot initialize stream class's packet context field type.");
205 goto error;
206 }
207
208 BT_LOGD("Created CTF writer stream class object: addr=%p, name=\"%s\"",
209 stream_class, name);
210 return stream_class;
211
212 error:
213 BT_PUT(stream_class);
214 return stream_class;
215 }
216
217 static
218 int try_map_clock_class(struct bt_ctf_stream_class *stream_class,
219 struct bt_ctf_field_type *parent_ft, const char *field_name)
220 {
221 struct bt_ctf_clock_class *mapped_clock_class = NULL;
222 int ret = 0;
223 struct bt_ctf_field_type *ft =
224 bt_ctf_field_type_structure_get_field_type_by_name(parent_ft,
225 field_name);
226
227 BT_ASSERT(stream_class->clock);
228
229 if (!ft) {
230 /* Field does not exist: not an error */
231 goto end;
232 }
233
234 BT_ASSERT(((struct bt_field_type_common *) ft)->id ==
235 BT_CTF_FIELD_TYPE_ID_INTEGER);
236 mapped_clock_class =
237 bt_ctf_field_type_integer_get_mapped_clock_class(ft);
238 if (!mapped_clock_class) {
239 struct bt_ctf_field_type *ft_copy;
240
241 if (!stream_class->clock) {
242 BT_LOGW("Cannot automatically set field's type mapped clock class: stream class's clock is not set: "
243 "stream-class-addr=%p, stream-class-name=\"%s\", "
244 "stream-class-id=%" PRId64 ", ft-addr=%p",
245 stream_class,
246 bt_ctf_stream_class_get_name(stream_class),
247 bt_ctf_stream_class_get_id(stream_class), ft);
248 ret = -1;
249 goto end;
250 }
251
252 ft_copy = bt_ctf_field_type_copy(ft);
253 if (!ft_copy) {
254 BT_LOGE("Failed to copy integer field type: ft-addr=%p",
255 ft);
256 }
257
258 ret = bt_field_type_common_integer_set_mapped_clock_class_no_check_frozen(
259 (void *) ft_copy,
260 BT_TO_COMMON(stream_class->clock->clock_class));
261 BT_ASSERT(ret == 0);
262
263 ret = bt_field_type_common_structure_replace_field(
264 (void *) parent_ft, field_name, (void *) ft_copy);
265 bt_put(ft_copy);
266 BT_LOGV("Automatically mapped field type to stream class's clock class: "
267 "stream-class-addr=%p, stream-class-name=\"%s\", "
268 "stream-class-id=%" PRId64 ", ft-addr=%p, "
269 "ft-copy-addr=%p",
270 stream_class,
271 bt_ctf_stream_class_get_name(stream_class),
272 bt_ctf_stream_class_get_id(stream_class), ft, ft_copy);
273 }
274
275 end:
276 bt_put(ft);
277 bt_put(mapped_clock_class);
278 return ret;
279 }
280
281 BT_HIDDEN
282 int bt_ctf_stream_class_map_clock_class(
283 struct bt_ctf_stream_class *stream_class,
284 struct bt_ctf_field_type *packet_context_type,
285 struct bt_ctf_field_type *event_header_type)
286 {
287 int ret = 0;
288
289 BT_ASSERT(stream_class);
290
291 if (!stream_class->clock) {
292 /* No clock class to map to */
293 goto end;
294 }
295
296 if (packet_context_type) {
297 if (try_map_clock_class(stream_class, packet_context_type,
298 "timestamp_begin")) {
299 BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_begin` field's mapped clock class.");
300 ret = -1;
301 goto end;
302 }
303
304 if (try_map_clock_class(stream_class, packet_context_type,
305 "timestamp_end")) {
306 BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_end` field's mapped clock class.");
307 ret = -1;
308 goto end;
309 }
310 }
311
312 if (event_header_type) {
313 if (try_map_clock_class(stream_class, event_header_type,
314 "timestamp")) {
315 BT_LOGE_STR("Cannot automatically set stream class's event header field type's `timestamp` field's mapped clock class.");
316 ret = -1;
317 goto end;
318 }
319 }
320
321 end:
322 return ret;
323 }
324
325 struct bt_ctf_clock *bt_ctf_stream_class_get_clock(
326 struct bt_ctf_stream_class *stream_class)
327 {
328 struct bt_ctf_clock *clock = NULL;
329
330 if (!stream_class) {
331 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
332 goto end;
333 }
334
335 if (!stream_class->clock) {
336 BT_LOGV("Stream class has no clock: "
337 "addr=%p, name=\"%s\", id=%" PRId64,
338 stream_class,
339 bt_ctf_stream_class_get_name(stream_class),
340 bt_ctf_stream_class_get_id(stream_class));
341 goto end;
342 }
343
344 clock = bt_get(stream_class->clock);
345
346 end:
347 return clock;
348 }
349
350 int bt_ctf_stream_class_set_clock(
351 struct bt_ctf_stream_class *stream_class,
352 struct bt_ctf_clock *clock)
353 {
354 int ret = 0;
355
356 if (!stream_class || !clock) {
357 BT_LOGW("Invalid parameter: stream class or clock is NULL: "
358 "stream-class-addr=%p, clock-addr=%p",
359 stream_class, clock);
360 ret = -1;
361 goto end;
362 }
363
364 if (stream_class->common.frozen) {
365 BT_LOGW("Invalid parameter: stream class is frozen: "
366 "addr=%p, name=\"%s\", id=%" PRId64,
367 stream_class,
368 bt_ctf_stream_class_get_name(stream_class),
369 bt_ctf_stream_class_get_id(stream_class));
370 ret = -1;
371 goto end;
372 }
373
374 /* Replace the current clock of this stream class. */
375 bt_put(stream_class->clock);
376 stream_class->clock = bt_get(clock);
377 BT_LOGV("Set stream class's clock: "
378 "addr=%p, name=\"%s\", id=%" PRId64 ", "
379 "clock-addr=%p, clock-name=\"%s\"",
380 stream_class,
381 bt_ctf_stream_class_get_name(stream_class),
382 bt_ctf_stream_class_get_id(stream_class),
383 stream_class->clock,
384 bt_ctf_clock_get_name(stream_class->clock));
385
386 end:
387 return ret;
388 }
389
390 BT_HIDDEN
391 int bt_ctf_stream_class_serialize(struct bt_ctf_stream_class *stream_class,
392 struct metadata_context *context)
393 {
394 int ret = 0;
395 size_t i;
396 struct bt_ctf_trace *trace;
397 struct bt_ctf_field_type *packet_header_type = NULL;
398
399 BT_LOGD("Serializing stream class's metadata: "
400 "stream-class-addr=%p, stream-class-name=\"%s\", "
401 "stream-class-id=%" PRId64 ", metadata-context-addr=%p",
402 stream_class,
403 bt_ctf_stream_class_get_name(stream_class),
404 bt_ctf_stream_class_get_id(stream_class), context);
405 g_string_assign(context->field_name, "");
406 context->current_indentation_level = 1;
407 if (!stream_class->common.id_set) {
408 BT_LOGW_STR("Stream class's ID is not set.");
409 ret = -1;
410 goto end;
411 }
412
413 g_string_append(context->string, "stream {\n");
414
415 /*
416 * The reference to the trace is only borrowed since the
417 * serialization of the stream class might have been triggered
418 * by the trace's destruction. In such a case, the trace's
419 * reference count would, unexepectedly, go through the sequence
420 * 1 -> 0 -> 1 -> 0 -> ..., provoking an endless loop of destruction
421 * and serialization.
422 */
423 trace = BT_FROM_COMMON(bt_stream_class_common_borrow_trace(
424 BT_TO_COMMON(stream_class)));
425 BT_ASSERT(trace);
426 packet_header_type = bt_ctf_trace_get_packet_header_field_type(trace);
427 trace = NULL;
428 if (packet_header_type) {
429 struct bt_ctf_field_type *stream_id_type;
430
431 stream_id_type =
432 bt_ctf_field_type_structure_get_field_type_by_name(
433 packet_header_type, "stream_id");
434 if (stream_id_type) {
435 /*
436 * Only set the stream's id if the trace's packet header
437 * contains a stream_id field. This field is only
438 * needed if the trace contains only one stream
439 * class.
440 */
441 g_string_append_printf(context->string,
442 "\tid = %" PRId64 ";\n",
443 stream_class->common.id);
444 }
445 bt_put(stream_id_type);
446 }
447 if (stream_class->common.event_header_field_type) {
448 BT_LOGD_STR("Serializing stream class's event header field type's metadata.");
449 g_string_append(context->string, "\tevent.header := ");
450 ret = bt_ctf_field_type_serialize_recursive(
451 (void *) stream_class->common.event_header_field_type,
452 context);
453 if (ret) {
454 BT_LOGW("Cannot serialize stream class's event header field type's metadata: "
455 "ret=%d", ret);
456 goto end;
457 }
458 g_string_append(context->string, ";");
459 }
460
461
462 if (stream_class->common.packet_context_field_type) {
463 BT_LOGD_STR("Serializing stream class's packet context field type's metadata.");
464 g_string_append(context->string, "\n\n\tpacket.context := ");
465 ret = bt_ctf_field_type_serialize_recursive(
466 (void *) stream_class->common.packet_context_field_type,
467 context);
468 if (ret) {
469 BT_LOGW("Cannot serialize stream class's packet context field type's metadata: "
470 "ret=%d", ret);
471 goto end;
472 }
473 g_string_append(context->string, ";");
474 }
475
476 if (stream_class->common.event_context_field_type) {
477 BT_LOGD_STR("Serializing stream class's event context field type's metadata.");
478 g_string_append(context->string, "\n\n\tevent.context := ");
479 ret = bt_ctf_field_type_serialize_recursive(
480 (void *) stream_class->common.event_context_field_type,
481 context);
482 if (ret) {
483 BT_LOGW("Cannot serialize stream class's event context field type's metadata: "
484 "ret=%d", ret);
485 goto end;
486 }
487 g_string_append(context->string, ";");
488 }
489
490 g_string_append(context->string, "\n};\n\n");
491
492 for (i = 0; i < stream_class->common.event_classes->len; i++) {
493 struct bt_ctf_event_class *event_class =
494 stream_class->common.event_classes->pdata[i];
495
496 ret = bt_ctf_event_class_serialize(event_class, context);
497 if (ret) {
498 BT_LOGW("Cannot serialize event class's metadata: "
499 "event-class-addr=%p, event-class-name=\"%s\", "
500 "event-class-id=%" PRId64,
501 event_class,
502 bt_ctf_event_class_get_name(event_class),
503 bt_ctf_event_class_get_id(event_class));
504 goto end;
505 }
506 }
507
508 end:
509 bt_put(packet_header_type);
510 context->current_indentation_level = 0;
511 return ret;
512 }
513
514 struct bt_ctf_trace *bt_ctf_stream_class_get_trace(
515 struct bt_ctf_stream_class *stream_class)
516 {
517 return BT_FROM_COMMON(bt_stream_class_common_get_trace(
518 BT_TO_COMMON(stream_class)));
519 }
520
521 const char *bt_ctf_stream_class_get_name(
522 struct bt_ctf_stream_class *stream_class)
523 {
524 return bt_stream_class_common_get_name(BT_TO_COMMON(stream_class));
525 }
526
527 int bt_ctf_stream_class_set_name(
528 struct bt_ctf_stream_class *stream_class, const char *name)
529 {
530 return bt_stream_class_common_set_name(BT_TO_COMMON(stream_class),
531 name);
532 }
533
534 int64_t bt_ctf_stream_class_get_id(
535 struct bt_ctf_stream_class *stream_class)
536 {
537 return bt_stream_class_common_get_id(BT_TO_COMMON(stream_class));
538 }
539
540 int bt_ctf_stream_class_set_id(
541 struct bt_ctf_stream_class *stream_class, uint64_t id)
542 {
543 return bt_stream_class_common_set_id(BT_TO_COMMON(stream_class), id);
544 }
545
546 struct bt_ctf_field_type *bt_ctf_stream_class_get_packet_context_type(
547 struct bt_ctf_stream_class *stream_class)
548 {
549 return BT_FROM_COMMON(
550 bt_stream_class_common_get_packet_context_field_type(
551 BT_TO_COMMON(stream_class)));
552 }
553
554 int bt_ctf_stream_class_set_packet_context_type(
555 struct bt_ctf_stream_class *stream_class,
556 struct bt_ctf_field_type *packet_context_type)
557 {
558 return bt_stream_class_common_set_packet_context_field_type(
559 BT_TO_COMMON(stream_class), (void *) packet_context_type);
560 }
561
562 struct bt_ctf_field_type *
563 bt_ctf_stream_class_get_event_header_type(
564 struct bt_ctf_stream_class *stream_class)
565 {
566 return BT_FROM_COMMON(
567 bt_stream_class_common_get_event_header_field_type(
568 BT_TO_COMMON(stream_class)));
569 }
570
571 int bt_ctf_stream_class_set_event_header_type(
572 struct bt_ctf_stream_class *stream_class,
573 struct bt_ctf_field_type *event_header_type)
574 {
575 return bt_stream_class_common_set_event_header_field_type(
576 BT_TO_COMMON(stream_class), (void *) event_header_type);
577 }
578
579 struct bt_ctf_field_type *
580 bt_ctf_stream_class_get_event_context_type(
581 struct bt_ctf_stream_class *stream_class)
582 {
583 return BT_FROM_COMMON(
584 bt_stream_class_common_get_event_context_field_type(
585 BT_TO_COMMON(stream_class)));
586 }
587
588 int bt_ctf_stream_class_set_event_context_type(
589 struct bt_ctf_stream_class *stream_class,
590 struct bt_ctf_field_type *event_context_type)
591 {
592 return bt_stream_class_common_set_event_context_field_type(
593 BT_TO_COMMON(stream_class), (void *) event_context_type);
594 }
595
596 int64_t bt_ctf_stream_class_get_event_class_count(
597 struct bt_ctf_stream_class *stream_class)
598 {
599 return bt_stream_class_common_get_event_class_count(
600 BT_TO_COMMON(stream_class));
601 }
602
603 struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_index(
604 struct bt_ctf_stream_class *stream_class, uint64_t index)
605 {
606 return BT_FROM_COMMON(
607 bt_stream_class_common_get_event_class_by_index(
608 BT_TO_COMMON(stream_class), index));
609 }
610
611 struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_id(
612 struct bt_ctf_stream_class *stream_class, uint64_t id)
613 {
614 return BT_FROM_COMMON(
615 bt_stream_class_common_get_event_class_by_id(
616 BT_TO_COMMON(stream_class), id));
617 }
618
619 int bt_ctf_stream_class_add_event_class(
620 struct bt_ctf_stream_class *stream_class,
621 struct bt_ctf_event_class *event_class)
622 {
623 return bt_stream_class_common_add_event_class(
624 BT_TO_COMMON(stream_class), BT_TO_COMMON(event_class),
625 (bt_validation_flag_copy_field_type_func) bt_ctf_field_type_copy);
626 }
This page took 0.042169 seconds and 4 git commands to generate.