{# # The MIT License (MIT) # # Copyright (c) 2020 Philippe Proulx # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #} {% import 'common.j2' as common %} {% import 'c/common.j2' as c_common %} {% import 'c/barectf.c-macros.j2' as macros %} {% set prefix = common.prefix %} {% set ucprefix = common.ucprefix %} {% set ctx_struct_name = c_common.ctx_struct_name %} {% set cg_opts = cfg.options.code_generation_options %} /* * The MIT License (MIT) * * Copyright (c) 2015-2020 Philippe Proulx * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * * The following C code was generated by barectf v{{ barectf_version.__version__ }} * on {{ common.gen_date }}. * * For more details, see . */ #include #include #include #include "{{ header_file_name }}" #include "{{ bitfield_header_file_name }}" #define _ALIGN(_at, _align) \ do { \ (_at) = ((_at) + ((_align) - 1)) & -(_align); \ } while (0) #ifdef __cplusplus # define _TO_VOID_PTR(_value) static_cast(_value) # define _FROM_VOID_PTR(_type, _value) static_cast<_type *>(_value) #else # define _TO_VOID_PTR(_value) ((void *) (_value)) # define _FROM_VOID_PTR(_type, _value) ((_type *) (_value)) #endif #define _BITS_TO_BYTES(_x) ((_x) >> 3) #define _BYTES_TO_BITS(_x) ((_x) << 3) union _f2u { float f; uint32_t u; }; union _d2u { double f; uint64_t u; }; uint32_t {{ prefix }}packet_size(void *ctx) { return _FROM_VOID_PTR(struct {{ ctx_struct_name }}, ctx)->packet_size; } int {{ prefix }}packet_is_full(void *vctx) { struct {{ ctx_struct_name }} *ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx); return ctx->at == ctx->packet_size; } int {{ prefix }}packet_is_empty(void *vctx) { struct {{ ctx_struct_name }} *ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx); return ctx->at <= ctx->off_content; } uint32_t {{ prefix }}packet_events_discarded(void *vctx) { return _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx)->events_discarded; } uint8_t *{{ prefix }}packet_buf(void *vctx) { return _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx)->buf; } uint32_t {{ prefix }}packet_buf_size(void *vctx) { struct {{ ctx_struct_name }} *ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx); return _BITS_TO_BYTES(ctx->packet_size); } void {{ prefix }}packet_set_buf(void *vctx, uint8_t *buf, uint32_t buf_size) { struct {{ ctx_struct_name }} *ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx); ctx->buf = buf; ctx->packet_size = _BYTES_TO_BITS(buf_size); } int {{ prefix }}packet_is_open(void *vctx) { return _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx)->packet_is_open; } int {{ prefix }}is_in_tracing_section(void *vctx) { return _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx)->in_tracing_section; } volatile const int *{{ prefix }}is_in_tracing_section_ptr(void *vctx) { return &_FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx)->in_tracing_section; } int {{ prefix }}is_tracing_enabled(void *vctx) { return _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx)->is_tracing_enabled; } void {{ prefix }}enable_tracing(void *vctx, int enable) { _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx)->is_tracing_enabled = enable; } static void _write_c_str(struct {{ ctx_struct_name }} *ctx, const char *src) { uint32_t sz = strlen(src) + 1; memcpy(&ctx->buf[_BITS_TO_BYTES(ctx->at)], src, sz); ctx->at += _BYTES_TO_BITS(sz); } static int _reserve_ev_space(void *vctx, uint32_t ev_size) { struct {{ ctx_struct_name }} *ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx); /* event _cannot_ fit? */ if (ev_size > (ctx->packet_size - ctx->off_content)) { ctx->events_discarded++; return 0; } /* packet is full? */ if ({{ prefix }}packet_is_full(ctx)) { /* yes: is back-end full? */ if (ctx->cbs.is_backend_full(ctx->data)) { /* yes: discard event */ ctx->events_discarded++; return 0; } /* back-end is not full: open new packet */ ctx->use_cur_last_event_ts = 1; ctx->cbs.open_packet(ctx->data); ctx->use_cur_last_event_ts = 0; } /* event fits the current packet? */ if (ev_size > (ctx->packet_size - ctx->at)) { /* no: close packet now */ ctx->use_cur_last_event_ts = 1; ctx->cbs.close_packet(ctx->data); ctx->use_cur_last_event_ts = 0; /* is back-end full? */ if (ctx->cbs.is_backend_full(ctx->data)) { /* yes: discard event */ ctx->events_discarded++; return 0; } /* back-end is not full: open new packet */ ctx->use_cur_last_event_ts = 1; ctx->cbs.open_packet(ctx->data); ctx->use_cur_last_event_ts = 0; assert(ev_size <= (ctx->packet_size - ctx->at)); } return 1; } static void _commit_ev(void *vctx) { struct {{ ctx_struct_name }} *ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx); /* is packet full? */ if ({{ prefix }}packet_is_full(ctx)) { /* yes: close it now */ ctx->cbs.close_packet(ctx->data); } } {% include 'c/ctx-init-func-proto.j2' %} { struct {{ ctx_struct_name }} *ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx); ctx->cbs = cbs; ctx->data = data; ctx->buf = buf; ctx->packet_size = _BYTES_TO_BITS(buf_size); ctx->at = 0; ctx->events_discarded = 0; ctx->packet_is_open = 0; ctx->in_tracing_section = 0; ctx->is_tracing_enabled = 1; ctx->use_cur_last_event_ts = 0; } {% for stream_type in cfg.trace.type.stream_types | sort %} {% set def_clk_type = stream_type.default_clock_type %} {% set sctx_name %}{{ prefix }}{{ stream_type.name }}{% endset %} {% set this_stream_ops = stream_ops[stream_type] %} {% include 'c/open-func-proto.j2' %} { {{ macros.open_close_func_preamble(stream_type) | indent_tab }} /* * This function is either called by a tracing function, or * directly by the platform. * * If it's called by a tracing function, then * `ctx->in_tracing_section` is 1, so it's safe to open * the packet here (alter the packet), even if tracing was * disabled in the meantime because we're already in a tracing * section (which finishes at the end of the tracing function * call). * * If it's called directly by the platform, then if tracing is * disabled, we don't want to alter the packet, and return * immediately. */ if (!ctx->is_tracing_enabled && !saved_in_tracing_section) { ctx->in_tracing_section = 0; return; } /* we can alter the packet */ ctx->in_tracing_section = 1; /* do not open a packet that is already open */ if (ctx->packet_is_open) { ctx->in_tracing_section = saved_in_tracing_section; return; } ctx->at = 0; {% set pkt_header_ops = this_stream_ops.pkt_header_ops %} {% if pkt_header_ops %} /* serialize packet header */ { {% for op in pkt_header_ops %} {{ op.serialize_str(stream_type=stream_type) | indent_tab(2) }} {% endfor %} } {% endif %} /* serialize packet context */ { {% for op in this_stream_ops.pkt_ctx_ops %} {{ op.serialize_str(stream_type=stream_type) | indent_tab(2) }} {% endfor %} } /* save content beginning's offset */ ctx->off_content = ctx->at; /* mark current packet as open */ ctx->packet_is_open = 1; /* not tracing anymore */ ctx->in_tracing_section = saved_in_tracing_section; } {% include 'c/close-func-proto.j2' %} { {{ macros.open_close_func_preamble(stream_type) | indent_tab }} /* * This function is either called by a tracing function, or * directly by the platform. * * If it's called by a tracing function, then * `ctx->in_tracing_section` is 1, so it's safe to close * the packet here (alter the packet), even if tracing was * disabled in the meantime, because we're already in a tracing * section (which finishes at the end of the tracing function * call). * * If it's called directly by the platform, then if tracing is * disabled, we don't want to alter the packet, and return * immediately. */ if (!ctx->is_tracing_enabled && !saved_in_tracing_section) { ctx->in_tracing_section = 0; return; } /* we can alter the packet */ ctx->in_tracing_section = 1; /* do not close a packet that is not open */ if (!ctx->packet_is_open) { ctx->in_tracing_section = saved_in_tracing_section; return; } /* save content size */ ctx->content_size = ctx->at; {% if 'timestamp_end' in stream_type._pkt_ctx_ft.members %} {% set op = stream_op_pkt_ctx_op(stream_type, 'timestamp_end') %} /* go back to `timestamp_end` field offset */ ctx->at = sctx->off_{{ c_common.op_src(op) }}; {% set src = 'ts' %} {% filter indent_tab(indent_first=True) %} {% include 'c/serialize-write-saved-int-statements.j2' %} {% endfilter %} {% endif %} {% if 'content_size' in stream_type._pkt_ctx_ft.members %} {% set op = stream_op_pkt_ctx_op(stream_type, 'content_size') %} /* go back to `content_size` field offset */ ctx->at = sctx->off_{{ c_common.op_src(op) }}; {% set src = 'ctx->content_size' %} {% filter indent_tab(indent_first=True) %} {% include 'c/serialize-write-saved-int-statements.j2' %} {% endfilter %} {% endif %} {% if 'events_discarded' in stream_type._pkt_ctx_ft.members %} {% set op = stream_op_pkt_ctx_op(stream_type, 'events_discarded') %} /* go back to `events_discarded` field offset */ ctx->at = sctx->off_{{ c_common.op_src(op) }}; {% set src = 'ctx->events_discarded' %} {% filter indent_tab(indent_first=True) %} {% include 'c/serialize-write-saved-int-statements.j2' %} {% endfilter %} {% endif %} /* go back to end of packet */ ctx->at = ctx->packet_size; /* mark packet as closed */ ctx->packet_is_open = 0; /* not tracing anymore */ ctx->in_tracing_section = saved_in_tracing_section; } {% if stream_type._ev_header_ft %} static void _serialize_ev_header_{{ stream_type.name }}(void *vctx, uint32_t ev_type_id) { struct {{ ctx_struct_name }} *ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx); {% if def_clk_type %} struct {{ sctx_name }}_ctx *sctx = _FROM_VOID_PTR(struct {{ sctx_name }}_ctx, vctx); const {{ cg_opts.clock_type_c_types[def_clk_type] }} ts = sctx->cur_last_event_ts; {% endif %} /* serialize event header */ { {% for op in this_stream_ops.ev_header_ops %} {{ op.serialize_str(stream_type=stream_type) | indent_tab(2) }} {% endfor %} } } {% endif %} {% if stream_type.event_common_context_field_type %} static void _serialize_ev_common_ctx_{{ stream_type.name }}(void *vctx{{ stream_type | serialize_ev_common_ctx_func_params_str }}) { struct {{ ctx_struct_name }} *ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx); /* serialize event common context */ { {% for op in this_stream_ops.ev_common_ctx_ops %} {{ op.serialize_str(stream_type=stream_type) | indent_tab(2) }} {% endfor %} } } {% endif %} {# internal serialization functions #} {% for ev_type in stream_type.event_types | sort %} static void _serialize_ev_{{ stream_type.name }}_{{ ev_type.name }}(void *vctx{{ (stream_type, ev_type) | trace_func_params_str }}) { struct {{ ctx_struct_name }} *ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx); {% if stream_type._ev_header_ft %} /* serialize header */ _serialize_ev_header_{{ stream_type.name }}(ctx, {{ ev_type.id }}); {% endif %} {% if stream_type.event_common_context_field_type %} /* serialize common context */ {% set params = macros.ft_call_params(root_ft_prefixes.SEC, stream_type.event_common_context_field_type) %} _serialize_ev_common_ctx_{{ stream_type.name }}(ctx{{ params }}); {% endif %} {% set this_ev_ops = this_stream_ops.ev_ops[ev_type] %} {% if this_ev_ops.spec_ctx_ops %} /* serialize specific context */ { {% for op in this_ev_ops.spec_ctx_ops %} {{ op.serialize_str(stream_type=stream_type, ev_type=ev_type) | indent_tab(2) }} {% endfor %} } {% endif %} {% if this_ev_ops.payload_ops %} /* serialize payload */ { {% for op in this_ev_ops.payload_ops %} {{ op.serialize_str(stream_type=stream_type, ev_type=ev_type) | indent_tab(2) }} {% endfor %} } {% endif %} } {% endfor %} {# internal size functions #} {% for ev_type in stream_type.event_types | sort %} {% set this_ev_ops = this_stream_ops.ev_ops[ev_type] %} static uint32_t _ev_size_{{ stream_type.name }}_{{ ev_type.name }}(void *vctx{{ (stream_type, ev_type) | trace_func_params_str }}) { struct {{ ctx_struct_name }} *ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx); uint32_t at = ctx->at; {% if this_stream_ops.ev_header_ops %} /* add header size */ { {% for op in this_stream_ops.ev_header_ops %} {{ op.size_str(stream_type=stream_type) | indent_tab(2) }} {% endfor %} } {% endif %} {% if this_stream_ops.ev_common_ctx_ops %} /* add common context size */ { {% for op in this_stream_ops.ev_common_ctx_ops %} {{ op.size_str(stream_type=stream_type) | indent_tab(2) }} {% endfor %} } {% endif %} {% if this_ev_ops.spec_ctx_ops %} /* add specific context size */ { {% for op in this_ev_ops.spec_ctx_ops %} {{ op.size_str(stream_type=stream_type, ev_type=ev_type) | indent_tab(2) }} {% endfor %} } {% endif %} {% if this_ev_ops.payload_ops %} /* add payload size */ { {% for op in this_ev_ops.payload_ops %} {{ op.size_str(stream_type=stream_type, ev_type=ev_type) | indent_tab(2) }} {% endfor %} } {% endif %} return at - ctx->at; } {% endfor %} {# public tracing functions #} {% for ev_type in stream_type.event_types | sort %} {% include 'c/trace-func-proto.j2' %} { struct {{ ctx_struct_name }} *ctx = &sctx->parent; uint32_t ev_size; {% if def_clk_type %} /* save time */ sctx->cur_last_event_ts = ctx->cbs.{{ def_clk_type.name }}_clock_get_value(ctx->data); {% endif %} if (!ctx->is_tracing_enabled) { return; } /* we can alter the packet */ ctx->in_tracing_section = 1; /* compute event size */ {% set ev_common_ctx_params = macros.ft_call_params(root_ft_prefixes.SEC, stream_type.event_common_context_field_type) %} {% set spec_ctx_params = macros.ft_call_params(root_ft_prefixes.EC, ev_type.specific_context_field_type) %} {% set payload_params = macros.ft_call_params(root_ft_prefixes.EP, ev_type.payload_field_type) %} {% set params %}{{ ev_common_ctx_params }}{{ spec_ctx_params }}{{ payload_params }}{% endset %} ev_size = _ev_size_{{ stream_type.name }}_{{ ev_type.name }}(_TO_VOID_PTR(ctx){{ params }}); /* do we have enough space to serialize? */ if (!_reserve_ev_space(_TO_VOID_PTR(ctx), ev_size)) { /* no: forget this */ ctx->in_tracing_section = 0; return; } /* serialize event */ _serialize_ev_{{ stream_type.name }}_{{ ev_type.name }}(_TO_VOID_PTR(ctx){{ params }}); /* commit event */ _commit_ev(_TO_VOID_PTR(ctx)); /* not tracing anymore */ ctx->in_tracing_section = 0; } {% endfor %} {% endfor %}