barectf.h.j2: add barectf_discarded_event_records_count()
[barectf.git] / barectf / templates / c / barectf.c.j2
1 {#
2 # The MIT License (MIT)
3 #
4 # Copyright (c) 2020 Philippe Proulx <pproulx@efficios.com>
5 #
6 # Permission is hereby granted, free of charge, to any person obtaining
7 # a copy of this software and associated documentation files (the
8 # "Software"), to deal in the Software without restriction, including
9 # without limitation the rights to use, copy, modify, merge, publish,
10 # distribute, sublicense, and/or sell copies of the Software, and to
11 # permit persons to whom the Software is furnished to do so, subject to
12 # the following conditions:
13 #
14 # The above copyright notice and this permission notice shall be
15 # included in all copies or substantial portions of the Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 #}
25 {% import 'common.j2' as common %}
26 {% import 'c/common.j2' as c_common %}
27 {% import 'c/barectf.c-macros.j2' as macros %}
28 {% set prefix = common.prefix %}
29 {% set ucprefix = common.ucprefix %}
30 {% set ctx_struct_name = c_common.ctx_struct_name %}
31 {% set cg_opts = cfg.options.code_generation_options %}
32 {% set const_params = true %}
33 {% include 'license-header.j2' %}
34
35
36 #include <stdint.h>
37 #include <string.h>
38 #include <assert.h>
39
40 #include "{{ header_file_name }}"
41 #include "{{ bitfield_header_file_name }}"
42
43 #define _ALIGN(_at_var, _align) \
44 do { \
45 (_at_var) = ((_at_var) + ((_align) - 1)) & -(_align); \
46 } while (0)
47
48 #ifdef __cplusplus
49 # define _TO_VOID_PTR(_value) static_cast<void *>(_value)
50 # define _FROM_VOID_PTR(_type, _value) static_cast<_type *>(_value)
51 #else
52 # define _TO_VOID_PTR(_value) ((void *) (_value))
53 # define _FROM_VOID_PTR(_type, _value) ((_type *) (_value))
54 #endif
55
56 #define _BITS_TO_BYTES(_x) ((_x) >> 3)
57 #define _BYTES_TO_BITS(_x) ((_x) << 3)
58
59 union _f2u {
60 float f;
61 uint32_t u;
62 };
63
64 union _d2u {
65 double f;
66 uint64_t u;
67 };
68
69 uint32_t {{ prefix }}packet_size(const void * const ctx)
70 {
71 return _FROM_VOID_PTR(const struct {{ ctx_struct_name }}, ctx)->packet_size;
72 }
73
74 int {{ prefix }}packet_is_full(const void * const vctx)
75 {
76 const struct {{ ctx_struct_name }} * const ctx = _FROM_VOID_PTR(const struct {{ ctx_struct_name }}, vctx);
77
78 return ctx->at == ctx->packet_size;
79 }
80
81 int {{ prefix }}packet_is_empty(const void * const vctx)
82 {
83 const struct {{ ctx_struct_name }} * const ctx = _FROM_VOID_PTR(const struct {{ ctx_struct_name }}, vctx);
84
85 return ctx->at <= ctx->off_content;
86 }
87
88 uint32_t {{ prefix }}packet_events_discarded(const void * const vctx)
89 {
90 return _FROM_VOID_PTR(const struct {{ ctx_struct_name }}, vctx)->events_discarded;
91 }
92
93 uint32_t {{ prefix }}discarded_event_records_count(const void * const vctx)
94 {
95 return {{ prefix }}packet_events_discarded(vctx);
96 }
97
98 uint8_t *{{ prefix }}packet_buf(const void * const vctx)
99 {
100 return _FROM_VOID_PTR(const struct {{ ctx_struct_name }}, vctx)->buf;
101 }
102
103 uint32_t {{ prefix }}packet_buf_size(const void * const vctx)
104 {
105 const struct {{ ctx_struct_name }} * const ctx = _FROM_VOID_PTR(const struct {{ ctx_struct_name }}, vctx);
106
107 return _BITS_TO_BYTES(ctx->packet_size);
108 }
109
110 void {{ prefix }}packet_set_buf(void * const vctx, uint8_t * const buf,
111 const uint32_t buf_size)
112 {
113 struct {{ ctx_struct_name }} * const ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
114
115 ctx->buf = buf;
116 ctx->packet_size = _BYTES_TO_BITS(buf_size);
117 }
118
119 int {{ prefix }}packet_is_open(const void * const vctx)
120 {
121 return _FROM_VOID_PTR(const struct {{ ctx_struct_name }}, vctx)->packet_is_open;
122 }
123
124 int {{ prefix }}is_in_tracing_section(const void * const vctx)
125 {
126 return _FROM_VOID_PTR(const struct {{ ctx_struct_name }}, vctx)->in_tracing_section;
127 }
128
129 volatile const int *{{ prefix }}is_in_tracing_section_ptr(const void * const vctx)
130 {
131 return &_FROM_VOID_PTR(const struct {{ ctx_struct_name }}, vctx)->in_tracing_section;
132 }
133
134 int {{ prefix }}is_tracing_enabled(const void * const vctx)
135 {
136 return _FROM_VOID_PTR(const struct {{ ctx_struct_name }}, vctx)->is_tracing_enabled;
137 }
138
139 void {{ prefix }}enable_tracing(void * const vctx, const int enable)
140 {
141 _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx)->is_tracing_enabled = enable;
142 }
143
144 static
145 void _write_c_str(struct {{ ctx_struct_name }} * const ctx, const char * const src)
146 {
147 const uint32_t sz = strlen(src) + 1;
148
149 memcpy(&ctx->buf[_BITS_TO_BYTES(ctx->at)], src, sz);
150 ctx->at += _BYTES_TO_BITS(sz);
151 }
152
153 static
154 int _reserve_er_space(void * const vctx, const uint32_t er_size)
155 {
156 int ret;
157 struct {{ ctx_struct_name }} * const ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
158
159 /* Event _cannot_ fit? */
160 if (er_size > (ctx->packet_size - ctx->off_content)) {
161 goto no_space;
162 }
163
164 /* Packet is full? */
165 if ({{ prefix }}packet_is_full(ctx)) {
166 /* Yes: is the back end full? */
167 if (ctx->cbs.is_backend_full(ctx->data)) {
168 /* Yes: discard event record */
169 goto no_space;
170 }
171
172 /* Back-end is _not_ full: open new packet */
173 ctx->use_cur_last_event_ts = 1;
174 ctx->cbs.open_packet(ctx->data);
175 ctx->use_cur_last_event_ts = 0;
176 }
177
178 /* Event fits the current packet? */
179 if (er_size > (ctx->packet_size - ctx->at)) {
180 /* No: close packet now */
181 ctx->use_cur_last_event_ts = 1;
182 ctx->cbs.close_packet(ctx->data);
183 ctx->use_cur_last_event_ts = 0;
184
185 /* Is the back end full? */
186 if (ctx->cbs.is_backend_full(ctx->data)) {
187 /* Yes: discard event record */
188 goto no_space;
189 }
190
191 /* Back-end is _not_ full: open new packet */
192 ctx->use_cur_last_event_ts = 1;
193 ctx->cbs.open_packet(ctx->data);
194 ctx->use_cur_last_event_ts = 0;
195 assert(er_size <= (ctx->packet_size - ctx->at));
196 }
197
198 ret = 1;
199 goto end;
200
201 no_space:
202 ctx->events_discarded++;
203 ret = 0;
204
205 end:
206 return ret;
207 }
208
209 static
210 void _commit_er(void * const vctx)
211 {
212 struct {{ ctx_struct_name }} * const ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
213
214 /* Is the packet full? */
215 if ({{ prefix }}packet_is_full(ctx)) {
216 /* Yes: close it now */
217 ctx->cbs.close_packet(ctx->data);
218 }
219 }
220
221 {% include 'c/ctx-init-func-proto.j2' %}
222
223 {
224 struct {{ ctx_struct_name }} * const ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
225 ctx->cbs = cbs;
226 ctx->data = data;
227 ctx->buf = buf;
228 ctx->packet_size = _BYTES_TO_BITS(buf_size);
229 ctx->at = 0;
230 ctx->events_discarded = 0;
231 ctx->packet_is_open = 0;
232 ctx->in_tracing_section = 0;
233 ctx->is_tracing_enabled = 1;
234 ctx->use_cur_last_event_ts = 0;
235 }
236
237 {% for dst in cfg.trace.type.data_stream_types | sort %}
238 {% set def_clk_type = dst.default_clock_type %}
239 {% set sctx_name %}{{ prefix }}{{ dst.name }}{% endset %}
240 {% set this_ds_ops = ds_ops[dst] %}
241 {% include 'c/open-func-proto.j2' %}
242
243 {
244 {{ macros.open_close_func_preamble(dst) | indent_tab }}
245
246 /*
247 * This function is either called by a tracing function, or
248 * directly by the platform.
249 *
250 * If it's called by a tracing function, then
251 * `ctx->in_tracing_section` is 1, so it's safe to open
252 * the packet here (alter the packet), even if tracing was
253 * disabled in the meantime because we're already in a tracing
254 * section (which finishes at the end of the tracing function
255 * call).
256 *
257 * If it's called directly by the platform, then if tracing is
258 * disabled, we don't want to alter the packet, and return
259 * immediately.
260 */
261 if (!ctx->is_tracing_enabled && !saved_in_tracing_section) {
262 ctx->in_tracing_section = 0;
263 goto end;
264 }
265
266 /* We can alter the packet */
267 ctx->in_tracing_section = 1;
268
269 /* Do not open a packet that is already open */
270 if (ctx->packet_is_open) {
271 ctx->in_tracing_section = saved_in_tracing_section;
272 goto end;
273 }
274
275 ctx->at = 0;
276 {% set pkt_header_op = this_ds_ops.pkt_header_op %}
277 {% if pkt_header_op %}
278
279 {{ pkt_header_op.serialize_str(dst=dst) | indent_tab }}
280 {% endif %}
281
282 {{ this_ds_ops.pkt_ctx_op.serialize_str(dst=dst) | indent_tab }}
283
284 /* Save content beginning's offset */
285 ctx->off_content = ctx->at;
286
287 /* Mark current packet as open */
288 ctx->packet_is_open = 1;
289
290 /* Not tracing anymore */
291 ctx->in_tracing_section = saved_in_tracing_section;
292
293 end:
294 return;
295 }
296
297 {% include 'c/close-func-proto.j2' %}
298
299 {
300 {{ macros.open_close_func_preamble(dst) | indent_tab }}
301
302 /*
303 * This function is either called by a tracing function, or
304 * directly by the platform.
305 *
306 * If it's called by a tracing function, then
307 * `ctx->in_tracing_section` is 1, so it's safe to close
308 * the packet here (alter the packet), even if tracing was
309 * disabled in the meantime, because we're already in a tracing
310 * section (which finishes at the end of the tracing function
311 * call).
312 *
313 * If it's called directly by the platform, then if tracing is
314 * disabled, we don't want to alter the packet, and return
315 * immediately.
316 */
317 if (!ctx->is_tracing_enabled && !saved_in_tracing_section) {
318 ctx->in_tracing_section = 0;
319 goto end;
320 }
321
322 /* We can alter the packet */
323 ctx->in_tracing_section = 1;
324
325 /* Do not close a packet that is not open */
326 if (!ctx->packet_is_open) {
327 ctx->in_tracing_section = saved_in_tracing_section;
328 goto end;
329 }
330
331 /* Save content size */
332 ctx->content_size = ctx->at;
333 {% set name = 'timestamp_end' %}
334 {% if name in dst._pkt_ctx_ft.members %}
335 {% set op = ds_op_pkt_ctx_op(dst, name) %}
336
337 /* Go back to `timestamp_end` field offset */
338 ctx->at = sctx->off_{{ op | op_src_var_name }};
339
340 {% set src = 'ts' %}
341 {% filter indent_tab(indent_first=true) %}
342 {% include 'c/serialize-write-saved-int-statements.j2' %}
343
344 {% endfilter %}
345 {% endif %}
346 {% set name = 'content_size' %}
347 {% if name in dst._pkt_ctx_ft.members %}
348 {% set op = ds_op_pkt_ctx_op(dst, name) %}
349
350 /* Go back to `content_size` field offset */
351 ctx->at = sctx->off_{{ op | op_src_var_name }};
352
353 {% set src %}ctx->{{ name }}{% endset %}
354 {% filter indent_tab(indent_first=true) %}
355 {% include 'c/serialize-write-saved-int-statements.j2' %}
356
357 {% endfilter %}
358 {% endif %}
359 {% set name = 'events_discarded' %}
360 {% if name in dst._pkt_ctx_ft.members %}
361 {% set op = ds_op_pkt_ctx_op(dst, name) %}
362
363 /* Go back to `events_discarded` field offset */
364 ctx->at = sctx->off_{{ op | op_src_var_name }};
365
366 {% set src %}ctx->{{ name }}{% endset %}
367 {% filter indent_tab(indent_first=true) %}
368 {% include 'c/serialize-write-saved-int-statements.j2' %}
369
370 {% endfilter %}
371 {% endif %}
372
373 /* Go back to end of packet */
374 ctx->at = ctx->packet_size;
375
376 /* Mark packet as closed */
377 ctx->packet_is_open = 0;
378
379 /* Not tracing anymore */
380 ctx->in_tracing_section = saved_in_tracing_section;
381
382 end:
383 return;
384 }
385 {% if dst._er_header_ft %}
386
387 static void _serialize_er_header_{{ dst.name }}(void * const vctx,
388 const uint32_t ert_id)
389 {
390 struct {{ ctx_struct_name }} * const ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
391 {% if def_clk_type %}
392 struct {{ sctx_name }}_ctx * const sctx = _FROM_VOID_PTR(struct {{ sctx_name }}_ctx, vctx);
393 const {{ cg_opts.clock_type_c_types[def_clk_type] }} ts = sctx->cur_last_event_ts;
394 {% endif %}
395
396 {{ this_ds_ops.er_header_op.serialize_str(dst=dst) | indent_tab }}
397 }
398 {% endif %}
399 {% if dst.event_record_common_context_field_type %}
400
401 static void _serialize_er_common_ctx_{{ dst.name }}(void * const vctx{{ dst | serialize_er_common_ctx_func_params_str(const_params) }})
402 {
403 struct {{ ctx_struct_name }} * const ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
404
405 {{ this_ds_ops.er_common_ctx_op.serialize_str(dst=dst) | indent_tab }}
406 }
407 {% endif %}
408 {# internal serialization functions #}
409 {% for ert in dst.event_record_types | sort %}
410
411 static void _serialize_er_{{ dst.name }}_{{ ert.name }}(void * const vctx{{ (dst, ert) | trace_func_params_str(const_params) }})
412 {
413 struct {{ ctx_struct_name }} * const ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
414 {% if dst._er_header_ft %}
415
416 /* Serialize header */
417 _serialize_er_header_{{ dst.name }}(ctx, {{ ert.id }});
418 {% endif %}
419 {% if dst.event_record_common_context_field_type %}
420
421 /* Serialize common context */
422 {% set params = macros.ft_call_params(root_ft_prefixes.ERCC, dst.event_record_common_context_field_type) %}
423 _serialize_er_common_ctx_{{ dst.name }}(ctx{{ params }});
424 {% endif %}
425 {% set this_er_ops = this_ds_ops.er_ops[ert] %}
426 {% if this_er_ops.spec_ctx_op %}
427
428 {{ this_er_ops.spec_ctx_op.serialize_str(dst=dst, ert=ert) | indent_tab }}
429 {% endif %}
430 {% if this_er_ops.payload_op %}
431
432 {{ this_er_ops.payload_op.serialize_str(dst=dst, ert=ert) | indent_tab }}
433 {% endif %}
434 }
435 {% endfor %}
436 {# internal size functions #}
437 {% for ert in dst.event_record_types | sort %}
438 {% set this_er_ops = this_ds_ops.er_ops[ert] %}
439
440 static uint32_t _er_size_{{ dst.name }}_{{ ert.name }}(void * const vctx{{ (dst, ert) | trace_func_params_str(const_params, only_dyn=true) }})
441 {
442 struct {{ ctx_struct_name }} * const ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
443 uint32_t at = ctx->at;
444 {% if this_ds_ops.er_header_op %}
445
446 {{ this_ds_ops.er_header_op.size_str(dst=dst) | indent_tab }}
447 {% endif %}
448 {% if this_ds_ops.er_common_ctx_op %}
449
450 {{ this_ds_ops.er_common_ctx_op.size_str(dst=dst) | indent_tab }}
451 {% endif %}
452 {% if this_er_ops.spec_ctx_op %}
453
454 {{ this_er_ops.spec_ctx_op.size_str(dst=dst, ert=ert) | indent_tab }}
455 {% endif %}
456 {% if this_er_ops.payload_op %}
457
458 {{ this_er_ops.payload_op.size_str(dst=dst, ert=ert) | indent_tab }}
459 {% endif %}
460
461 return at - ctx->at;
462 }
463 {% endfor %}
464 {# public tracing functions #}
465 {% for ert in dst.event_record_types | sort %}
466
467 {% include 'c/trace-func-proto.j2' %}
468
469 {
470 struct {{ ctx_struct_name }} * const ctx = &sctx->parent;
471 uint32_t er_size;
472
473 {% if def_clk_type %}
474 /* Save timestamp */
475 sctx->cur_last_event_ts = ctx->cbs.{{ def_clk_type.name }}_clock_get_value(ctx->data);
476
477 {% endif %}
478 if (!ctx->is_tracing_enabled) {
479 goto end;
480 }
481
482 /* We can alter the packet */
483 ctx->in_tracing_section = 1;
484
485 /* Compute event record size */
486 {% set er_common_ctx_params = macros.ft_call_params(root_ft_prefixes.ERCC, dst.event_record_common_context_field_type, true) %}
487 {% set spec_ctx_params = macros.ft_call_params(root_ft_prefixes.ERSC, ert.specific_context_field_type, true) %}
488 {% set payload_params = macros.ft_call_params(root_ft_prefixes.ERP, ert.payload_field_type, true) %}
489 {% set params %}{{ er_common_ctx_params }}{{ spec_ctx_params }}{{ payload_params }}{% endset %}
490 er_size = _er_size_{{ dst.name }}_{{ ert.name }}(_TO_VOID_PTR(ctx){{ params }});
491
492 /* Is there enough space to serialize? */
493 if (!_reserve_er_space(_TO_VOID_PTR(ctx), er_size)) {
494 /* no: forget this */
495 ctx->in_tracing_section = 0;
496 goto end;
497 }
498
499 /* Serialize event record */
500 {% set er_common_ctx_params = macros.ft_call_params(root_ft_prefixes.ERCC, dst.event_record_common_context_field_type) %}
501 {% set spec_ctx_params = macros.ft_call_params(root_ft_prefixes.ERSC, ert.specific_context_field_type) %}
502 {% set payload_params = macros.ft_call_params(root_ft_prefixes.ERP, ert.payload_field_type) %}
503 {% set params %}{{ er_common_ctx_params }}{{ spec_ctx_params }}{{ payload_params }}{% endset %}
504 _serialize_er_{{ dst.name }}_{{ ert.name }}(_TO_VOID_PTR(ctx){{ params }});
505
506 /* Commit event record */
507 _commit_er(_TO_VOID_PTR(ctx));
508
509 /* Not tracing anymore */
510 ctx->in_tracing_section = 0;
511
512 end:
513 return;
514 }
515 {% endfor %}
516 {% endfor %}
This page took 0.039857 seconds and 4 git commands to generate.