1 # The MIT License (MIT)
3 # Copyright (c) 2014-2020 Philippe Proulx <pproulx@efficios.com>
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
13 # The above copyright notice and this permission notice shall be
14 # included in all copies or substantial portions of the Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 import barectf
.tsdl182gen
as barectf_tsdl182gen
25 import barectf
.templates
as barectf_templates
26 import barectf
.template
as barectf_template
27 import barectf
.codegen
as barectf_codegen
28 import barectf
.config
as barectf_config
29 import barectf
.version
as barectf_version
36 def __init__(self
, name
, contents
):
38 self
._contents
= contents
50 def __init__(self
, configuration
):
51 self
._config
= configuration
52 self
._file
_name
_prefix
= configuration
.options
.code_generation_options
.file_name_prefix
53 self
._ccode
_gen
= _CCodeGenerator(configuration
)
54 self
._c
_headers
= None
55 self
._c
_sources
= None
56 self
._metadata
_stream
= None
59 def _barectf_header_name(self
):
60 return f
'{self._file_name_prefix}.h'
62 def generate_c_headers(self
):
63 if self
._c
_headers
is None:
64 bitfield_header_name
= f
'{self._file_name_prefix}-bitfield.h'
66 _GeneratedFile(self
._barectf
_header
_name
,
67 self
._ccode
_gen
.generate_header(bitfield_header_name
)),
68 _GeneratedFile(bitfield_header_name
,
69 self
._ccode
_gen
.generate_bitfield_header()),
72 return self
._c
_headers
74 def generate_c_sources(self
):
75 if self
._c
_sources
is None:
77 _GeneratedFile(f
'{self._file_name_prefix}.c',
78 self
._ccode
_gen
.generate_c_src(self
._barectf
_header
_name
))
81 return self
._c
_sources
83 def generate_metadata_stream(self
):
84 if self
._metadata
_stream
is None:
85 self
._metadata
_stream
= _GeneratedFile('metadata',
86 barectf_tsdl182gen
._from
_config
(self
._config
))
88 return self
._metadata
_stream
92 return (v
+ (align
- 1)) & -align
95 class _SerializationAction
:
96 def __init__(self
, offset_in_byte
, ft
, names
):
97 assert(offset_in_byte
>= 0 and offset_in_byte
< 8)
98 self
._offset
_in
_byte
= offset_in_byte
100 self
._names
= copy
.deepcopy(names
)
103 def offset_in_byte(self
):
104 return self
._offset
_in
_byte
115 class _AlignSerializationAction(_SerializationAction
):
116 def __init__(self
, offset_in_byte
, ft
, names
, value
):
117 super().__init
__(offset_in_byte
, ft
, names
)
125 class _SerializeSerializationAction(_SerializationAction
):
129 class _SerializationActions
:
134 self
._last
_alignment
= None
135 self
._last
_bit
_array
_size
= None
138 self
._offset
_in
_byte
= 0
140 def append_root_scope_ft(self
, ft
, name
):
144 assert(type(ft
) is barectf_config
.StructureFieldType
)
152 def align(self
, alignment
):
153 do_align
= self
._must
_align
(alignment
)
154 self
._last
_alignment
= alignment
155 self
._last
_bit
_array
_size
= alignment
156 self
._try
_append
_align
_action
(alignment
, do_align
)
158 def _must_align(self
, align_req
):
159 return self
._last
_alignment
!= align_req
or self
._last
_bit
_array
_size
% align_req
!= 0
161 def _append_ft(self
, ft
):
162 if isinstance(ft
, (barectf_config
.StringFieldType
, barectf_config
._ArrayFieldType
)):
163 assert(type(ft
) is barectf_config
.StringFieldType
or self
._names
[-1] == 'uuid')
164 do_align
= self
._must
_align
(8)
165 self
._last
_alignment
= 8
166 self
._last
_bit
_array
_size
= 8
167 self
._try
_append
_align
_action
(8, do_align
, ft
)
168 self
._append
_serialize
_action
(ft
)
170 do_align
= self
._must
_align
(ft
.alignment
)
171 self
._last
_alignment
= ft
.alignment
173 if type(ft
) is barectf_config
.StructureFieldType
:
174 self
._last
_bit
_array
_size
= ft
.alignment
176 self
._last
_bit
_array
_size
= ft
.size
178 self
._try
_append
_align
_action
(ft
.alignment
, do_align
, ft
)
180 if type(ft
) is barectf_config
.StructureFieldType
:
181 for member_name
, member
in ft
.members
.items():
182 self
._names
.append(member_name
)
183 self
._append
_ft
(member
.field_type
)
186 self
._append
_serialize
_action
(ft
)
188 def _try_append_align_action(self
, alignment
, do_align
, ft
=None):
189 offset_in_byte
= self
._offset
_in
_byte
190 self
._offset
_in
_byte
= _align(self
._offset
_in
_byte
, alignment
) % 8
192 if do_align
and alignment
> 1:
193 self
._actions
.append(_AlignSerializationAction(offset_in_byte
, ft
, self
._names
,
196 def _append_serialize_action(self
, ft
):
197 assert(type(ft
) is not barectf_config
.StructureFieldType
)
198 offset_in_byte
= self
._offset
_in
_byte
200 if isinstance(ft
, barectf_config
._BitArrayFieldType
):
201 self
._offset
_in
_byte
+= ft
.size
202 self
._offset
_in
_byte
%= 8
204 self
._actions
.append(_SerializeSerializationAction(offset_in_byte
, ft
, self
._names
))
214 _PREFIX_TPH
: 'trace packet header',
215 _PREFIX_SPC
: 'stream packet context',
216 _PREFIX_SEH
: 'stream event header',
217 _PREFIX_SEC
: 'stream event context',
218 _PREFIX_EC
: 'event context',
219 _PREFIX_EP
: 'event payload',
223 class _CCodeGenerator
:
224 def __init__(self
, cfg
):
226 code_gen_opts
= cfg
.options
.code_generation_options
227 self
._iden
_prefix
= code_gen_opts
.identifier_prefix
228 self
._cg
= barectf_codegen
._CodeGenerator
('\t')
229 self
._saved
_serialization
_actions
= {}
231 def _create_template(self
, name
: str) -> barectf_template
._Template
:
232 return barectf_template
._Template
(name
, cfg
=self
._cfg
)
234 def _create_file_template(self
, name
: str) -> barectf_template
._Template
:
235 return barectf_template
._Template
(name
, True, self
._cfg
)
238 def _trace_type(self
):
239 return self
._cfg
.trace
.type
241 def _clk_type_c_type(self
, clk_type
):
242 return self
._cfg
.options
.code_generation_options
.clock_type_c_types
[clk_type
]
244 def _generate_ctx_parent(self
):
245 tmpl
= barectf_templates
._CTX
_PARENT
246 self
._cg
.add_lines(tmpl
.format(prefix
=self
._iden
_prefix
))
248 def _generate_ctx(self
, stream_type
):
249 tmpl
= barectf_templates
._CTX
_BEGIN
250 self
._cg
.add_lines(tmpl
.format(prefix
=self
._iden
_prefix
, sname
=stream_type
.name
))
252 pkt_header_ft
= self
._trace
_type
._pkt
_header
_ft
254 if pkt_header_ft
is not None:
255 for member_name
in pkt_header_ft
.members
:
256 self
._cg
.add_lines(f
'uint32_t off_tph_{member_name};')
258 for member_name
in stream_type
._pkt
_ctx
_ft
.members
:
259 self
._cg
.add_lines(f
'uint32_t off_spc_{member_name};')
261 if stream_type
.default_clock_type
is not None:
262 self
._cg
.add_line(f
'{self._clk_type_c_type(stream_type.default_clock_type)} cur_last_event_ts;')
265 tmpl
= barectf_templates
._CTX
_END
266 self
._cg
.add_lines(tmpl
)
268 def _generate_ctxs(self
):
269 for stream_type
in self
._trace
_type
.stream_types
:
270 self
._generate
_ctx
(stream_type
)
272 def _generate_clock_cb(self
, clk_type
):
273 tmpl
= barectf_templates
._CLOCK
_CB
274 self
._cg
.add_lines(tmpl
.format(return_ctype
=self
._clk
_type
_c
_type
(clk_type
),
275 cname
=clk_type
.name
))
277 def _generate_clock_cbs(self
):
280 for stream_type
in self
._trace
_type
.stream_types
:
281 def_clk_type
= stream_type
.default_clock_type
283 if def_clk_type
is not None and def_clk_type
not in clk_names
:
284 self
._generate
_clock
_cb
(def_clk_type
)
285 clk_names
.add(def_clk_type
)
287 def _generate_platform_callbacks(self
):
288 tmpl
= barectf_templates
._PLATFORM
_CALLBACKS
_BEGIN
289 self
._cg
.add_lines(tmpl
.format(prefix
=self
._iden
_prefix
))
291 self
._generate
_clock
_cbs
()
293 tmpl
= barectf_templates
._PLATFORM
_CALLBACKS
_END
294 self
._cg
.add_lines(tmpl
)
296 def generate_bitfield_header(self
):
298 tmpl
= barectf_templates
._BITFIELD
299 tmpl
= tmpl
.replace('$prefix$', self
._iden
_prefix
)
300 tmpl
= tmpl
.replace('$PREFIX$', self
._iden
_prefix
.upper())
302 if self
._trace
_type
.default_byte_order
== barectf_config
.ByteOrder
.BIG_ENDIAN
:
303 endian_def
= 'BIG_ENDIAN'
305 endian_def
= 'LITTLE_ENDIAN'
307 tmpl
= tmpl
.replace('$ENDIAN_DEF$', endian_def
)
308 self
._cg
.add_lines(tmpl
)
312 def _generate_func_init_proto(self
):
313 tmpl
= barectf_templates
._FUNC
_INIT
_PROTO
314 self
._cg
.add_lines(tmpl
.format(prefix
=self
._iden
_prefix
))
316 def _get_ft_c_type(self
, ft
):
317 if isinstance(ft
, barectf_config
._IntegerFieldType
):
318 sign_prefix
= 'u' if isinstance(ft
, barectf_config
.UnsignedIntegerFieldType
) else ''
330 return f
'{sign_prefix}int{sz}_t'
331 elif type(ft
) is barectf_config
.RealFieldType
:
332 if ft
.size
== 32 and ft
.alignment
== 32:
334 elif ft
.size
== 64 and ft
.alignment
== 64:
339 assert type(ft
) is barectf_config
.StringFieldType
340 return 'const char *'
342 def _generate_ft_c_type(self
, ft
):
343 c_type
= self
._get
_ft
_c
_type
(ft
)
344 self
._cg
.append_to_last_line(c_type
)
346 def _generate_proto_param(self
, ft
, name
):
347 self
._generate
_ft
_c
_type
(ft
)
348 self
._cg
.append_to_last_line(' ')
349 self
._cg
.append_to_last_line(name
)
351 def _generate_proto_params(self
, ft
, name_prefix
, exclude_set
=None):
352 if exclude_set
is None:
357 for member_name
, member
in ft
.members
.items():
358 if member_name
in exclude_set
:
361 self
._cg
.append_to_last_line(',')
362 self
._cg
.add_line('')
363 self
._generate
_proto
_param
(member
.field_type
, name_prefix
+ member_name
)
367 def _generate_func_open_proto(self
, stream_type
):
368 tmpl
= barectf_templates
._FUNC
_OPEN
_PROTO
_BEGIN
369 self
._cg
.add_lines(tmpl
.format(prefix
=self
._iden
_prefix
, sname
=stream_type
.name
))
371 if self
._trace
_type
._pkt
_header
_ft
is not None:
372 self
._generate
_proto
_params
(self
._trace
_type
._pkt
_header
_ft
, _PREFIX_TPH
,
373 {'magic', 'stream_id', 'uuid'})
382 self
._generate
_proto
_params
(stream_type
._pkt
_ctx
_ft
, _PREFIX_SPC
, exclude_set
)
383 tmpl
= barectf_templates
._FUNC
_OPEN
_PROTO
_END
384 self
._cg
.add_lines(tmpl
)
386 def _generate_func_close_proto(self
, stream_type
):
387 tmpl
= barectf_templates
._FUNC
_CLOSE
_PROTO
388 self
._cg
.add_lines(tmpl
.format(prefix
=self
._iden
_prefix
, sname
=stream_type
.name
))
390 def _generate_func_trace_proto_params(self
, stream_type
, ev_type
):
391 if stream_type
._ev
_header
_ft
is not None:
392 self
._generate
_proto
_params
(stream_type
._ev
_header
_ft
, _PREFIX_SEH
, {'id', 'timestamp'})
394 if stream_type
.event_common_context_field_type
is not None:
395 self
._generate
_proto
_params
(stream_type
.event_common_context_field_type
, _PREFIX_SEC
)
397 if ev_type
.specific_context_field_type
is not None:
398 self
._generate
_proto
_params
(ev_type
.specific_context_field_type
, _PREFIX_EC
)
400 if ev_type
.payload_field_type
is not None:
401 self
._generate
_proto
_params
(ev_type
.payload_field_type
, _PREFIX_EP
)
403 def _generate_func_trace_proto(self
, stream_type
, ev_type
):
404 tmpl
= barectf_templates
._FUNC
_TRACE
_PROTO
_BEGIN
405 self
._cg
.add_lines(tmpl
.format(prefix
=self
._iden
_prefix
, sname
=stream_type
.name
,
406 evname
=ev_type
.name
))
407 self
._generate
_func
_trace
_proto
_params
(stream_type
, ev_type
)
408 tmpl
= barectf_templates
._FUNC
_TRACE
_PROTO
_END
409 self
._cg
.add_lines(tmpl
)
411 def _punctuate_proto(self
):
412 self
._cg
.append_to_last_line(';')
414 def generate_header(self
, bitfield_header_name
):
416 dt
= datetime
.datetime
.now().isoformat()
418 def_stream_type_name_def
= ''
419 cg_opts
= self
._cfg
.options
.code_generation_options
420 header_opts
= cg_opts
.header_options
422 if header_opts
.identifier_prefix_definition
:
423 prefix_def
= f
'#define _BARECTF_PREFIX {self._iden_prefix}'
425 def_stream_type
= cg_opts
.default_stream_type
427 if header_opts
.default_stream_type_name_definition
and def_stream_type
is not None:
428 def_stream_type_name_def
= f
'#define _BARECTF_DEFAULT_STREAM {def_stream_type.name}'
430 def_stream_type_trace_defs
= ''
432 if def_stream_type
is not None:
435 for ev_type
in def_stream_type
.event_types
:
436 tmpl
= barectf_templates
._DEFINE
_DEFAULT
_STREAM
_TRACE
437 define
= tmpl
.format(prefix
=self
._iden
_prefix
, sname
=def_stream_type
.name
,
441 def_stream_type_trace_defs
= '\n'.join(lines
)
443 tmpl
= barectf_templates
._HEADER
_BEGIN
444 self
._cg
.add_lines(tmpl
.format(prefix
=self
._iden
_prefix
,
445 ucprefix
=self
._iden
_prefix
.upper(),
446 bitfield_header_filename
=bitfield_header_name
,
447 version
=barectf_version
.__version
__, date
=dt
,
448 prefix_def
=prefix_def
,
449 default_stream_def
=def_stream_type_name_def
,
450 default_stream_trace_defs
=def_stream_type_trace_defs
))
451 self
._cg
.add_empty_line()
453 # platform callbacks structure
454 self
._generate
_platform
_callbacks
()
455 self
._cg
.add_empty_line()
458 self
._generate
_ctx
_parent
()
459 self
._cg
.add_empty_line()
462 self
._generate
_ctxs
()
463 self
._cg
.add_empty_line()
465 # initialization function prototype
466 self
._generate
_func
_init
_proto
()
467 self
._punctuate
_proto
()
468 self
._cg
.add_empty_line()
470 for stream_type
in self
._trace
_type
.stream_types
:
471 self
._generate
_func
_open
_proto
(stream_type
)
472 self
._punctuate
_proto
()
473 self
._cg
.add_empty_line()
474 self
._generate
_func
_close
_proto
(stream_type
)
475 self
._punctuate
_proto
()
476 self
._cg
.add_empty_line()
478 for ev_type
in stream_type
.event_types
:
479 self
._generate
_func
_trace
_proto
(stream_type
, ev_type
)
480 self
._punctuate
_proto
()
481 self
._cg
.add_empty_line()
483 tmpl
= barectf_templates
._HEADER
_END
484 self
._cg
.add_lines(tmpl
.format(ucprefix
=self
._iden
_prefix
.upper()))
487 def _get_call_event_param_list_from_struct_ft(self
, ft
, prefix
, exclude_set
=None):
488 if exclude_set
is None:
493 for member_name
in ft
.members
:
494 if member_name
in exclude_set
:
497 lst
+= f
', {prefix}{member_name}'
501 def _get_call_event_param_list(self
, stream_type
, ev_type
):
504 if stream_type
._ev
_header
_ft
is not None:
505 lst
+= self
._get
_call
_event
_param
_list
_from
_struct
_ft
(stream_type
._ev
_header
_ft
,
506 _PREFIX_SEH
, {'id', 'timestamp'})
508 if stream_type
.event_common_context_field_type
is not None:
509 lst
+= self
._get
_call
_event
_param
_list
_from
_struct
_ft
(stream_type
.event_common_context_field_type
,
512 if ev_type
.specific_context_field_type
is not None:
513 lst
+= self
._get
_call
_event
_param
_list
_from
_struct
_ft
(ev_type
.specific_context_field_type
,
516 if ev_type
.payload_field_type
is not None:
517 lst
+= self
._get
_call
_event
_param
_list
_from
_struct
_ft
(ev_type
.payload_field_type
,
522 def _generate_align(self
, at
, align
):
523 self
._cg
.add_line(f
'_ALIGN({at}, {align});')
525 def _generate_incr_pos(self
, var
, value
):
526 self
._cg
.add_line(f
'{var} += {value};')
528 def _generate_incr_pos_bytes(self
, var
, value
):
529 self
._generate
_incr
_pos
(var
, f
'_BYTES_TO_BITS({value})')
531 def _generate_func_get_event_size_proto(self
, stream_type
, ev_type
):
532 tmpl
= barectf_templates
._FUNC
_GET
_EVENT
_SIZE
_PROTO
_BEGIN
533 self
._cg
.add_lines(tmpl
.format(prefix
=self
._iden
_prefix
, sname
=stream_type
.name
,
534 evname
=ev_type
.name
))
535 self
._generate
_func
_trace
_proto
_params
(stream_type
, ev_type
)
536 tmpl
= barectf_templates
._FUNC
_GET
_EVENT
_SIZE
_PROTO
_END
537 self
._cg
.add_lines(tmpl
)
539 def _generate_func_get_event_size(self
, stream_type
, ev_type
):
540 self
._generate
_func
_get
_event
_size
_proto
(stream_type
, ev_type
)
541 tmpl
= barectf_templates
._FUNC
_GET
_EVENT
_SIZE
_BODY
_BEGIN
542 lines
= tmpl
.format(prefix
=self
._iden
_prefix
)
543 self
._cg
.add_lines(lines
)
544 self
._cg
.add_empty_line()
546 ser_actions
= _SerializationActions()
547 ser_actions
.append_root_scope_ft(stream_type
._ev
_header
_ft
, _PREFIX_SEH
)
548 ser_actions
.append_root_scope_ft(stream_type
.event_common_context_field_type
, _PREFIX_SEC
)
549 ser_actions
.append_root_scope_ft(ev_type
.specific_context_field_type
, _PREFIX_EC
)
550 ser_actions
.append_root_scope_ft(ev_type
.payload_field_type
, _PREFIX_EP
)
552 for action
in ser_actions
.actions
:
553 if type(action
) is _AlignSerializationAction
:
555 if len(action
.names
) == 1:
556 line
= f
'align {_PREFIX_TO_NAME[action.names[0]]} structure'
558 line
= f
'align field `{action.names[-1]}` ({_PREFIX_TO_NAME[action.names[0]]})'
560 self
._cg
.add_cc_line(line
)
562 self
._generate
_align
('at', action
.value
)
563 self
._cg
.add_empty_line()
565 assert type(action
) is _SerializeSerializationAction
566 assert(len(action
.names
) >= 2)
567 line
= f
'add size of field `{action.names[-1]}` ({_PREFIX_TO_NAME[action.names[0]]})'
568 self
._cg
.add_cc_line(line
)
570 if type(action
.ft
) is barectf_config
.StringFieldType
:
571 param
= ''.join(action
.names
)
572 self
._generate
_incr
_pos
_bytes
('at', f
'strlen({param}) + 1')
574 self
._generate
_incr
_pos
('at', action
.ft
.size
)
576 self
._cg
.add_empty_line()
579 tmpl
= barectf_templates
._FUNC
_GET
_EVENT
_SIZE
_BODY
_END
580 self
._cg
.add_lines(tmpl
)
582 def _generate_func_serialize_event_proto(self
, stream_type
, ev_type
):
583 tmpl
= barectf_templates
._FUNC
_SERIALIZE
_EVENT
_PROTO
_BEGIN
584 self
._cg
.add_lines(tmpl
.format(prefix
=self
._iden
_prefix
, sname
=stream_type
.name
,
585 evname
=ev_type
.name
))
586 self
._generate
_func
_trace
_proto
_params
(stream_type
, ev_type
)
587 tmpl
= barectf_templates
._FUNC
_SERIALIZE
_EVENT
_PROTO
_END
588 self
._cg
.add_lines(tmpl
)
590 def _generate_serialize_from_action(self
, var
, ctx
, action
):
591 def gen_bitfield_write(c_type
, var
, ctx
, action
):
592 ptr
= f
'&{ctx}->buf[_BITS_TO_BYTES({ctx}->at)]'
593 start
= action
.offset_in_byte
594 suffix
= 'le' if action
.ft
.byte_order
is barectf_config
.ByteOrder
.LITTLE_ENDIAN
else 'be'
595 func
= f
'{self._iden_prefix}bt_bitfield_write_{suffix}'
596 call
= f
'{func}({ptr}, uint8_t, {start}, {action.ft.size}, {c_type}, ({c_type}) {var});'
597 self
._cg
.add_line(call
)
599 def gen_serialize_int(var
, ctx
, action
):
600 c_type
= self
._get
_ft
_c
_type
(action
.ft
)
601 gen_bitfield_write(c_type
, var
, ctx
, action
)
602 self
._generate
_incr
_pos
(f
'{ctx}->at', action
.ft
.size
)
604 def gen_serialize_real(var
, ctx
, action
):
605 c_type
= self
._get
_ft
_c
_type
(action
.ft
)
608 if c_type
== 'float' or c_type
== 'double':
611 if c_type
== 'float':
613 int_c_type
= 'uint32_t'
615 assert c_type
== 'double'
617 int_c_type
= 'uint64_t'
619 # union for reading the bytes of the floating point number
620 self
._cg
.add_empty_line()
621 self
._cg
.add_line('{')
623 self
._cg
.add_line(f
'union {union_name} {union_name};')
624 self
._cg
.add_empty_line()
625 self
._cg
.add_line(f
'{union_name}.f = {var};')
626 bf_var
= f
'{union_name}.u'
628 bf_var
= f
'({c_type}) {var}'
631 gen_bitfield_write(int_c_type
, bf_var
, ctx
, action
)
635 self
._cg
.add_line('}')
636 self
._cg
.add_empty_line()
638 self
._generate
_incr
_pos
(f
'{ctx}->at', action
.ft
.size
)
640 def gen_serialize_string(var
, ctx
, action
):
641 self
._cg
.add_lines(f
'_write_cstring({ctx}, {var});')
643 if isinstance(action
.ft
, barectf_config
._IntegerFieldType
):
644 return gen_serialize_int(var
, ctx
, action
)
645 elif type(action
.ft
) is barectf_config
.RealFieldType
:
646 return gen_serialize_real(var
, ctx
, action
)
648 assert type(action
.ft
) is barectf_config
.StringFieldType
649 return gen_serialize_string(var
, ctx
, action
)
651 def _generate_serialize_statements_from_actions(self
, prefix
, action_iter
, spec_src
=None):
652 for action
in action_iter
:
653 if type(action
) is _AlignSerializationAction
:
655 if len(action
.names
) == 1:
656 line
= f
'align {_PREFIX_TO_NAME[action.names[0]]} structure'
658 line
= f
'align field `{action.names[-1]}` ({_PREFIX_TO_NAME[action.names[0]]})'
660 self
._cg
.add_cc_line(line
)
662 self
._generate
_align
('ctx->at', action
.value
)
663 self
._cg
.add_empty_line()
665 assert type(action
) is _SerializeSerializationAction
666 assert(len(action
.names
) >= 2)
667 member_name
= action
.names
[-1]
668 line
= f
'serialize field `{member_name}` ({_PREFIX_TO_NAME[action.names[0]]})'
669 self
._cg
.add_cc_line(line
)
670 src
= prefix
+ member_name
672 if spec_src
is not None and member_name
in spec_src
:
673 src
= spec_src
[member_name
]
675 self
._generate
_serialize
_from
_action
(src
, 'ctx', action
)
676 self
._cg
.add_empty_line()
678 def _generate_func_serialize_event(self
, stream_type
, ev_type
, orig_ser_actions
):
679 self
._generate
_func
_serialize
_event
_proto
(stream_type
, ev_type
)
680 tmpl
= barectf_templates
._FUNC
_SERIALIZE
_EVENT
_BODY
_BEGIN
681 lines
= tmpl
.format(prefix
=self
._iden
_prefix
)
682 self
._cg
.add_lines(lines
)
684 self
._cg
.add_empty_line()
686 if stream_type
._ev
_header
_ft
is not None:
687 params
= self
._get
_call
_event
_param
_list
_from
_struct
_ft
(stream_type
._ev
_header
_ft
,
690 self
._cg
.add_cc_line('stream event header')
691 line
= f
'_serialize_stream_event_header_{stream_type.name}(ctx, {ev_type.id}{params});'
692 self
._cg
.add_line(line
)
693 self
._cg
.add_empty_line()
695 if stream_type
.event_common_context_field_type
is not None:
696 params
= self
._get
_call
_event
_param
_list
_from
_struct
_ft
(stream_type
.event_common_context_field_type
,
698 self
._cg
.add_cc_line('stream event context')
699 line
= f
'_serialize_stream_event_context_{stream_type.name}(ctx{params});'
700 self
._cg
.add_line(line
)
701 self
._cg
.add_empty_line()
703 if ev_type
.specific_context_field_type
is not None or ev_type
.payload_field_type
is not None:
704 ser_actions
= copy
.deepcopy(orig_ser_actions
)
706 if ev_type
.specific_context_field_type
is not None:
707 ser_action_index
= len(ser_actions
.actions
)
708 ser_actions
.append_root_scope_ft(ev_type
.specific_context_field_type
, _PREFIX_EC
)
709 ser_action_iter
= itertools
.islice(ser_actions
.actions
, ser_action_index
, None)
710 self
._generate
_serialize
_statements
_from
_actions
(_PREFIX_EC
, ser_action_iter
)
712 if ev_type
.payload_field_type
is not None:
713 ser_action_index
= len(ser_actions
.actions
)
714 ser_actions
.append_root_scope_ft(ev_type
.payload_field_type
, _PREFIX_EP
)
715 ser_action_iter
= itertools
.islice(ser_actions
.actions
, ser_action_index
, None)
716 self
._generate
_serialize
_statements
_from
_actions
(_PREFIX_EP
, ser_action_iter
)
719 tmpl
= barectf_templates
._FUNC
_SERIALIZE
_EVENT
_BODY
_END
720 self
._cg
.add_lines(tmpl
)
722 def _generate_func_serialize_event_header_proto(self
, stream_type
):
723 tmpl
= barectf_templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_HEADER
_PROTO
_BEGIN
724 self
._cg
.add_lines(tmpl
.format(prefix
=self
._iden
_prefix
, sname
=stream_type
.name
))
726 if stream_type
._ev
_header
_ft
is not None:
727 self
._generate
_proto
_params
(stream_type
._ev
_header
_ft
, _PREFIX_SEH
,
730 tmpl
= barectf_templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_HEADER
_PROTO
_END
731 self
._cg
.add_lines(tmpl
)
733 def _generate_func_serialize_event_common_context_proto(self
, stream_type
):
734 tmpl
= barectf_templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_CONTEXT
_PROTO
_BEGIN
735 self
._cg
.add_lines(tmpl
.format(prefix
=self
._iden
_prefix
, sname
=stream_type
.name
))
737 if stream_type
.event_common_context_field_type
is not None:
738 self
._generate
_proto
_params
(stream_type
.event_common_context_field_type
, _PREFIX_SEC
)
740 tmpl
= barectf_templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_CONTEXT
_PROTO
_END
741 self
._cg
.add_lines(tmpl
)
743 def _generate_func_serialize_event_header(self
, stream_type
, ser_action_iter
):
744 self
._generate
_func
_serialize
_event
_header
_proto
(stream_type
)
745 tmpl
= barectf_templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_HEADER
_BODY
_BEGIN
746 lines
= tmpl
.format(prefix
=self
._iden
_prefix
, sname
=stream_type
.name
)
747 self
._cg
.add_lines(lines
)
750 if stream_type
.default_clock_type
is not None:
751 line
= f
'struct {self._iden_prefix}{stream_type.name}_ctx *s_ctx = FROM_VOID_PTR(struct {self._iden_prefix}{stream_type.name}_ctx, vctx);'
752 self
._cg
.add_line(line
)
753 line
= f
'const {self._clk_type_c_type(stream_type.default_clock_type)} ts = s_ctx->cur_last_event_ts;'
754 self
._cg
.add_line(line
)
756 self
._cg
.add_empty_line()
758 if stream_type
._ev
_header
_ft
is not None:
761 member
= stream_type
._ev
_header
_ft
.members
.get(member_name
)
763 if member
is not None:
764 spec_src
[member_name
] = f
'({self._get_ft_c_type(member.field_type)}) event_id'
766 member_name
= 'timestamp'
767 member
= stream_type
._ev
_header
_ft
.members
.get(member_name
)
769 if member
is not None:
770 spec_src
[member_name
] = f
'({self._get_ft_c_type(member.field_type)}) ts'
772 self
._generate
_serialize
_statements
_from
_actions
(_PREFIX_SEH
, ser_action_iter
,
776 tmpl
= barectf_templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_HEADER
_BODY
_END
777 self
._cg
.add_lines(tmpl
)
779 def _generate_func_serialize_event_common_context(self
, stream_type
, ser_action_iter
):
780 self
._generate
_func
_serialize
_event
_common
_context
_proto
(stream_type
)
781 tmpl
= barectf_templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_CONTEXT
_BODY
_BEGIN
782 lines
= tmpl
.format(prefix
=self
._iden
_prefix
)
783 self
._cg
.add_lines(lines
)
786 if stream_type
.event_common_context_field_type
is not None:
787 self
._generate
_serialize
_statements
_from
_actions
(_PREFIX_SEC
, ser_action_iter
)
790 tmpl
= barectf_templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_CONTEXT
_BODY
_END
791 self
._cg
.add_lines(tmpl
)
793 def _generate_func_trace(self
, stream_type
, ev_type
):
794 self
._generate
_func
_trace
_proto
(stream_type
, ev_type
)
795 params
= self
._get
_call
_event
_param
_list
(stream_type
, ev_type
)
796 def_clk_type
= stream_type
.default_clock_type
798 if def_clk_type
is not None:
799 save_ts_line
= f
'ctx->cur_last_event_ts = ctx->parent.cbs.{def_clk_type.name}_clock_get_value(ctx->parent.data);'
801 save_ts_line
= '/* (no clock) */'
803 tmpl
= barectf_templates
._FUNC
_TRACE
_BODY
804 self
._cg
.add_lines(tmpl
.format(sname
=stream_type
.name
, evname
=ev_type
.name
, params
=params
,
805 save_ts
=save_ts_line
))
807 def _generate_func_init(self
):
808 self
._generate
_func
_init
_proto
()
809 tmpl
= barectf_templates
._FUNC
_INIT
_BODY
810 self
._cg
.add_lines(tmpl
.format(prefix
=self
._iden
_prefix
))
812 def _generate_member_name_cc_line(self
, member_name
):
813 self
._cg
.add_cc_line(f
'`{member_name}` field')
815 def _save_serialization_action(self
, name
, action
):
816 self
._saved
_serialization
_actions
[name
] = action
818 def _get_open_close_ts_line(self
, stream_type
):
819 def_clk_type
= stream_type
.default_clock_type
821 if def_clk_type
is None:
824 c_type
= self
._clk
_type
_c
_type
(def_clk_type
)
825 return f
'\tconst {c_type} ts = ctx->parent.use_cur_last_event_ts ? ctx->cur_last_event_ts : ctx->parent.cbs.{def_clk_type.name}_clock_get_value(ctx->parent.data);'
827 def _generate_func_open(self
, stream_type
):
828 def generate_save_offset(name
, action
):
829 self
._cg
.add_line(f
'ctx->off_spc_{name} = ctx->parent.at;')
830 self
._save
_serialization
_action
(name
, action
)
832 self
._generate
_func
_open
_proto
(stream_type
)
833 tmpl
= barectf_templates
._FUNC
_OPEN
_BODY
_BEGIN
834 pkt_ctx_ft
= stream_type
._pkt
_ctx
_ft
835 ts_line
= self
._get
_open
_close
_ts
_line
(stream_type
)
836 lines
= tmpl
.format(ts
=ts_line
)
837 self
._cg
.add_lines(lines
)
839 self
._cg
.add_cc_line('do not open a packet that is already open')
840 self
._cg
.add_line('if (ctx->parent.packet_is_open) {')
842 self
._cg
.add_line('ctx->parent.in_tracing_section = saved_in_tracing_section;')
843 self
._cg
.add_line('return;')
845 self
._cg
.add_line('}')
846 self
._cg
.add_empty_line()
847 self
._cg
.add_line('ctx->parent.at = 0;')
848 pkt_header_ft
= self
._trace
_type
._pkt
_header
_ft
849 ser_actions
= _SerializationActions()
851 if pkt_header_ft
is not None:
852 self
._cg
.add_empty_line()
853 self
._cg
.add_cc_line('trace packet header')
854 self
._cg
.add_line('{')
856 ser_actions
.append_root_scope_ft(pkt_header_ft
, _PREFIX_TPH
)
858 for action
in ser_actions
.actions
:
859 if type(action
) is _AlignSerializationAction
:
861 if len(action
.names
) == 1:
862 line
= 'align trace packet header structure'
864 line
= f
'align field `{action.names[-1]}`'
866 self
._cg
.add_cc_line(line
)
868 self
._generate
_align
('ctx->parent.at', action
.value
)
869 self
._cg
.add_empty_line()
871 assert type(action
) is _SerializeSerializationAction
872 assert(len(action
.names
) >= 2)
873 member_name
= action
.names
[-1]
874 line
= f
'serialize field `{member_name}`'
875 self
._cg
.add_cc_line(line
)
876 src
= _PREFIX_TPH
+ member_name
878 if member_name
== 'magic':
880 elif member_name
== 'stream_id':
881 src
= f
'({self._get_ft_c_type(action.ft)}) {stream_type.id}'
882 elif member_name
== 'uuid':
883 self
._cg
.add_line('{')
885 self
._cg
.add_line('static uint8_t uuid[] = {')
888 for b
in self
._trace
_type
.uuid
.bytes
:
889 self
._cg
.add_line(f
'{b},')
892 self
._cg
.add_line('};')
893 self
._cg
.add_empty_line()
894 self
._generate
_align
('ctx->parent.at', 8)
895 line
= 'memcpy(&ctx->parent.buf[_BITS_TO_BYTES(ctx->parent.at)], uuid, 16);'
896 self
._cg
.add_line(line
)
897 self
._generate
_incr
_pos
_bytes
('ctx->parent.at', 16)
899 self
._cg
.add_line('}')
900 self
._cg
.add_empty_line()
903 self
._generate
_serialize
_from
_action
(src
, '(&ctx->parent)', action
)
904 self
._cg
.add_empty_line()
907 self
._cg
.add_lines('}')
909 spc_action_index
= len(ser_actions
.actions
)
910 self
._cg
.add_empty_line()
911 self
._cg
.add_cc_line('stream packet context')
912 self
._cg
.add_line('{')
914 ser_actions
.append_root_scope_ft(pkt_ctx_ft
, _PREFIX_SPC
)
916 for action
in itertools
.islice(ser_actions
.actions
, spc_action_index
, None):
917 if type(action
) is _AlignSerializationAction
:
919 if len(action
.names
) == 1:
920 line
= 'align stream packet context structure'
922 line
= f
'align field `{action.names[-1]}`'
924 self
._cg
.add_cc_line(line
)
926 self
._generate
_align
('ctx->parent.at', action
.value
)
927 self
._cg
.add_empty_line()
929 assert type(action
) is _SerializeSerializationAction
930 assert(len(action
.names
) >= 2)
931 member_name
= action
.names
[-1]
932 line
= f
'serialize field `{member_name}`'
933 self
._cg
.add_cc_line(line
)
934 src
= _PREFIX_SPC
+ member_name
937 if member_name
== 'timestamp_begin':
938 src
= f
'({self._get_ft_c_type(action.ft)}) ts'
939 elif member_name
in {'timestamp_end', 'content_size', 'events_discarded'}:
941 elif member_name
== 'packet_size':
942 src
= f
'({self._get_ft_c_type(action.ft)}) ctx->parent.packet_size'
945 generate_save_offset(member_name
, action
)
946 self
._generate
_incr
_pos
('ctx->parent.at', action
.ft
.size
)
948 self
._generate
_serialize
_from
_action
(src
, '(&ctx->parent)', action
)
950 self
._cg
.add_empty_line()
953 self
._cg
.add_lines('}')
955 tmpl
= barectf_templates
._FUNC
_OPEN
_BODY
_END
956 self
._cg
.add_lines(tmpl
)
958 def _generate_func_close(self
, stream_type
):
959 def generate_goto_offset(name
):
960 self
._cg
.add_line(f
'ctx->parent.at = ctx->off_spc_{name};')
962 self
._generate
_func
_close
_proto
(stream_type
)
963 tmpl
= barectf_templates
._FUNC
_CLOSE
_BODY
_BEGIN
964 pkt_ctx_ft
= stream_type
._pkt
_ctx
_ft
965 ts_line
= self
._get
_open
_close
_ts
_line
(stream_type
)
966 lines
= tmpl
.format(ts
=ts_line
)
967 self
._cg
.add_lines(lines
)
969 self
._cg
.add_cc_line('do not close a packet that is not open')
970 self
._cg
.add_line('if (!ctx->parent.packet_is_open) {')
972 self
._cg
.add_line('ctx->parent.in_tracing_section = saved_in_tracing_section;')
973 self
._cg
.add_line('return;')
975 self
._cg
.add_line('}')
976 self
._cg
.add_empty_line()
977 self
._cg
.add_cc_line('save content size')
978 self
._cg
.add_line('ctx->parent.content_size = ctx->parent.at;')
979 member_name
= 'timestamp_end'
980 member
= pkt_ctx_ft
.members
.get(member_name
)
982 if member
is not None:
983 self
._cg
.add_empty_line()
984 self
._generate
_member
_name
_cc
_line
(member_name
)
985 generate_goto_offset(member_name
)
986 action
= self
._saved
_serialization
_actions
[member_name
]
987 c_type
= self
._get
_ft
_c
_type
(member
.field_type
)
988 self
._generate
_serialize
_from
_action
(f
'({c_type}) ts', '(&ctx->parent)', action
)
990 member_name
= 'content_size'
991 member
= pkt_ctx_ft
.members
.get(member_name
)
993 if member
is not None:
994 self
._cg
.add_empty_line()
995 self
._generate
_member
_name
_cc
_line
(member_name
)
996 generate_goto_offset(member_name
)
997 action
= self
._saved
_serialization
_actions
[member_name
]
998 c_type
= self
._get
_ft
_c
_type
(member
.field_type
)
999 self
._generate
_serialize
_from
_action
(f
'({c_type}) ctx->parent.content_size',
1000 '(&ctx->parent)', action
)
1002 member_name
= 'events_discarded'
1003 member
= pkt_ctx_ft
.members
.get(member_name
)
1005 if member
is not None:
1006 self
._cg
.add_empty_line()
1007 self
._generate
_member
_name
_cc
_line
(member_name
)
1008 generate_goto_offset(member_name
)
1009 action
= self
._saved
_serialization
_actions
[member_name
]
1010 c_type
= self
._get
_ft
_c
_type
(member
.field_type
)
1011 self
._generate
_serialize
_from
_action
(f
'({c_type}) ctx->parent.events_discarded',
1012 '(&ctx->parent)', action
)
1015 tmpl
= barectf_templates
._FUNC
_CLOSE
_BODY
_END
1016 self
._cg
.add_lines(tmpl
)
1018 def generate_c_src(self
, header_name
):
1020 dt
= datetime
.datetime
.now().isoformat()
1021 tmpl
= barectf_templates
._C
_SRC
1022 self
._cg
.add_lines(tmpl
.format(prefix
=self
._iden
_prefix
, header_filename
=header_name
,
1023 version
=barectf_version
.__version
__, date
=dt
))
1024 self
._cg
.add_empty_line()
1026 # initialization function
1027 self
._generate
_func
_init
()
1028 self
._cg
.add_empty_line()
1030 for stream_type
in self
._trace
_type
.stream_types
:
1031 self
._generate
_func
_open
(stream_type
)
1032 self
._cg
.add_empty_line()
1033 self
._generate
_func
_close
(stream_type
)
1034 self
._cg
.add_empty_line()
1035 ser_actions
= _SerializationActions()
1037 if stream_type
._ev
_header
_ft
is not None:
1038 ser_actions
.append_root_scope_ft(stream_type
._ev
_header
_ft
, _PREFIX_SEH
)
1039 self
._generate
_func
_serialize
_event
_header
(stream_type
, iter(ser_actions
.actions
))
1040 self
._cg
.add_empty_line()
1042 if stream_type
.event_common_context_field_type
is not None:
1043 ser_action_index
= len(ser_actions
.actions
)
1044 ser_actions
.append_root_scope_ft(stream_type
.event_common_context_field_type
,
1046 ser_action_iter
= itertools
.islice(ser_actions
.actions
, ser_action_index
, None)
1047 self
._generate
_func
_serialize
_event
_common
_context
(stream_type
, ser_action_iter
)
1048 self
._cg
.add_empty_line()
1050 for ev_type
in stream_type
.event_types
:
1051 self
._generate
_func
_get
_event
_size
(stream_type
, ev_type
)
1052 self
._cg
.add_empty_line()
1053 self
._generate
_func
_serialize
_event
(stream_type
, ev_type
, ser_actions
)
1054 self
._cg
.add_empty_line()
1055 self
._generate
_func
_trace
(stream_type
, ev_type
)
1056 self
._cg
.add_empty_line()
1058 return self
._cg
.code