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 from barectf
import templates
25 from barectf
import metadata
26 import barectf
.codegen
39 return (v
+ (align
- 1)) & -align
42 class _SerializationAction
:
43 def __init__(self
, offset_in_byte
, type, names
):
44 assert(offset_in_byte
>= 0 and offset_in_byte
< 8)
45 self
._offset
_in
_byte
= offset_in_byte
47 self
._names
= copy
.deepcopy(names
)
50 def offset_in_byte(self
):
51 return self
._offset
_in
_byte
62 class _AlignSerializationAction(_SerializationAction
):
63 def __init__(self
, offset_in_byte
, type, names
, value
):
64 super().__init
__(offset_in_byte
, type, names
)
72 class _SerializeSerializationAction(_SerializationAction
):
73 def __init__(self
, offset_in_byte
, type, names
):
74 super().__init
__(offset_in_byte
, type, names
)
77 class _SerializationActions
:
82 self
._last
_alignment
= None
83 self
._last
_bit
_array
_size
= None
86 self
._offset
_in
_byte
= 0
88 def append_root_scope_type(self
, t
, name
):
92 assert(type(t
) is metadata
.Struct
)
100 def align(self
, alignment
):
101 do_align
= self
._must
_align
(alignment
)
102 self
._last
_alignment
= alignment
103 self
._last
_bit
_array
_size
= alignment
104 self
._try
_append
_align
_action
(alignment
, do_align
)
106 def _must_align(self
, align_req
):
107 return self
._last
_alignment
!= align_req
or self
._last
_bit
_array
_size
% align_req
!= 0
109 def _append_type(self
, t
):
110 assert(type(t
) in (metadata
.Struct
, metadata
.String
, metadata
.Integer
,
111 metadata
.FloatingPoint
, metadata
.Enum
,
114 if type(t
) in (metadata
.String
, metadata
.Array
):
115 assert(type(t
) is metadata
.String
or self
._names
[-1] == 'uuid')
116 do_align
= self
._must
_align
(8)
117 self
._last
_alignment
= 8
118 self
._last
_bit
_array
_size
= 8
119 self
._try
_append
_align
_action
(8, do_align
, t
)
120 self
._append
_serialize
_action
(t
)
121 elif type(t
) in (metadata
.Integer
, metadata
.FloatingPoint
,
122 metadata
.Enum
, metadata
.Struct
):
123 do_align
= self
._must
_align
(t
.align
)
124 self
._last
_alignment
= t
.align
126 if type(t
) is metadata
.Struct
:
127 self
._last
_bit
_array
_size
= t
.align
129 self
._last
_bit
_array
_size
= t
.size
131 self
._try
_append
_align
_action
(t
.align
, do_align
, t
)
133 if type(t
) is metadata
.Struct
:
134 for field_name
, field_type
in t
.fields
.items():
135 self
._names
.append(field_name
)
136 self
._append
_type
(field_type
)
139 self
._append
_serialize
_action
(t
, t
.size
)
141 def _try_append_align_action(self
, alignment
, do_align
, t
=None):
142 offset_in_byte
= self
._offset
_in
_byte
143 self
._offset
_in
_byte
= _align(self
._offset
_in
_byte
, alignment
) % 8
145 if do_align
and alignment
> 1:
146 self
._actions
.append(_AlignSerializationAction(offset_in_byte
,
150 def _append_serialize_action(self
, t
, size
=None):
151 assert(type(t
) in (metadata
.Integer
, metadata
.FloatingPoint
,
152 metadata
.Enum
, metadata
.String
,
155 offset_in_byte
= self
._offset
_in
_byte
157 if t
.size
is not None:
158 self
._offset
_in
_byte
+= t
.size
159 self
._offset
_in
_byte
%= 8
161 self
._actions
.append(_SerializeSerializationAction(offset_in_byte
,
172 _PREFIX_TPH
: 'trace packet header',
173 _PREFIX_SPC
: 'stream packet context',
174 _PREFIX_SEH
: 'stream event header',
175 _PREFIX_SEC
: 'stream event context',
176 _PREFIX_EC
: 'event context',
177 _PREFIX_EP
: 'event payload',
181 class CCodeGenerator
:
182 def __init__(self
, cfg
):
184 self
._cg
= barectf
.codegen
.CodeGenerator('\t')
185 self
._type
_to
_get
_ctype
_func
= {
186 metadata
.Integer
: self
._get
_int
_ctype
,
187 metadata
.FloatingPoint
: self
._get
_float
_ctype
,
188 metadata
.Enum
: self
._get
_enum
_ctype
,
189 metadata
.String
: self
._get
_string
_ctype
,
191 self
._type
_to
_generate
_serialize
_func
= {
192 metadata
.Integer
: self
._generate
_serialize
_int
,
193 metadata
.FloatingPoint
: self
._generate
_serialize
_float
,
194 metadata
.Enum
: self
._generate
_serialize
_enum
,
195 metadata
.String
: self
._generate
_serialize
_string
,
197 self
._saved
_serialization
_actions
= {}
199 def _get_stream_clock(self
, stream
):
202 if stream
.event_header_type
is not None:
203 if 'timestamp' in stream
.event_header_type
.fields
:
204 field
= stream
.event_header_type
['timestamp']
206 if stream
.packet_context_type
is not None:
207 if field
is None and 'timestamp_begin' in stream
.packet_context_type
.fields
:
208 field
= stream
.packet_context_type
['timestamp_begin']
210 if field
is None and 'timestamp_end' in stream
.packet_context_type
.fields
:
211 field
= stream
.packet_context_type
['timestamp_end']
216 if field
.property_mappings
:
217 return field
.property_mappings
[0].object
219 def _generate_ctx_parent(self
):
220 tmpl
= templates
._CTX
_PARENT
221 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
))
223 def _generate_ctx(self
, stream
):
224 tmpl
= templates
._CTX
_BEGIN
225 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
,
227 tmpl
= 'uint32_t off_tph_{fname};'
229 trace_packet_header_type
= self
._cfg
.metadata
.trace
.packet_header_type
231 if trace_packet_header_type
is not None:
232 for field_name
in trace_packet_header_type
.fields
:
233 self
._cg
.add_lines(tmpl
.format(fname
=field_name
))
235 tmpl
= 'uint32_t off_spc_{fname};'
237 if stream
.packet_context_type
is not None:
238 for field_name
in stream
.packet_context_type
.fields
:
239 self
._cg
.add_lines(tmpl
.format(fname
=field_name
))
241 clock
= self
._get
_stream
_clock
(stream
)
243 if clock
is not None:
244 line
= '{} cur_last_event_ts;'.format(clock
.return_ctype
)
245 self
._cg
.add_line(line
)
248 tmpl
= templates
._CTX
_END
249 self
._cg
.add_lines(tmpl
)
251 def _generate_ctxs(self
):
252 for stream
in self
._cfg
.metadata
.streams
.values():
253 self
._generate
_ctx
(stream
)
255 def _generate_clock_cb(self
, clock
):
256 tmpl
= templates
._CLOCK
_CB
257 self
._cg
.add_lines(tmpl
.format(return_ctype
=clock
.return_ctype
,
260 def _generate_clock_cbs(self
):
261 for clock
in self
._cfg
.metadata
.clocks
.values():
262 self
._generate
_clock
_cb
(clock
)
264 def _generate_platform_callbacks(self
):
265 tmpl
= templates
._PLATFORM
_CALLBACKS
_BEGIN
266 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
))
268 self
._generate
_clock
_cbs
()
270 tmpl
= templates
._PLATFORM
_CALLBACKS
_END
271 self
._cg
.add_lines(tmpl
)
273 def generate_bitfield_header(self
):
275 tmpl
= templates
._BITFIELD
276 tmpl
= tmpl
.replace('$prefix$', self
._cfg
.prefix
)
277 tmpl
= tmpl
.replace('$PREFIX$', self
._cfg
.prefix
.upper())
279 if self
._cfg
.metadata
.trace
.byte_order
== metadata
.ByteOrder
.BE
:
280 endian_def
= 'BIG_ENDIAN'
282 endian_def
= 'LITTLE_ENDIAN'
284 tmpl
= tmpl
.replace('$ENDIAN_DEF$', endian_def
)
285 self
._cg
.add_lines(tmpl
)
289 def _generate_func_init_proto(self
):
290 tmpl
= templates
._FUNC
_INIT
_PROTO
291 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
))
293 def _get_int_ctype(self
, t
):
294 signed
= 'u' if not t
.signed
else ''
305 return '{}int{}_t'.format(signed
, sz
)
307 def _get_float_ctype(self
, t
):
308 if t
.exp_size
== 8 and t
.mant_size
== 24 and t
.align
== 32:
310 elif t
.exp_size
== 11 and t
.mant_size
== 53 and t
.align
== 64:
317 def _get_enum_ctype(self
, t
):
318 return self
._get
_int
_ctype
(t
.value_type
)
320 def _get_string_ctype(self
, t
):
321 return 'const char *'
323 def _get_type_ctype(self
, t
):
324 return self
._type
_to
_get
_ctype
_func
[type(t
)](t
)
326 def _generate_type_ctype(self
, t
):
327 ctype
= self
._get
_type
_ctype
(t
)
328 self
._cg
.append_to_last_line(ctype
)
330 def _generate_proto_param(self
, t
, name
):
331 self
._generate
_type
_ctype
(t
)
332 self
._cg
.append_to_last_line(' ')
333 self
._cg
.append_to_last_line(name
)
335 def _generate_proto_params(self
, t
, name_prefix
, exclude_list
):
338 for field_name
, field_type
in t
.fields
.items():
339 if field_name
in exclude_list
:
342 name
= name_prefix
+ field_name
343 self
._cg
.append_to_last_line(',')
344 self
._cg
.add_line('')
345 self
._generate
_proto
_param
(field_type
, name
)
349 def _generate_func_open_proto(self
, stream
):
350 tmpl
= templates
._FUNC
_OPEN
_PROTO
_BEGIN
351 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
,
353 trace_packet_header_type
= self
._cfg
.metadata
.trace
.packet_header_type
355 if trace_packet_header_type
is not None:
356 exclude_list
= ['magic', 'stream_id', 'uuid']
357 self
._generate
_proto
_params
(trace_packet_header_type
, _PREFIX_TPH
,
360 if stream
.packet_context_type
is not None:
368 self
._generate
_proto
_params
(stream
.packet_context_type
,
369 _PREFIX_SPC
, exclude_list
)
371 tmpl
= templates
._FUNC
_OPEN
_PROTO
_END
372 self
._cg
.add_lines(tmpl
)
374 def _generate_func_close_proto(self
, stream
):
375 tmpl
= templates
._FUNC
_CLOSE
_PROTO
376 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
,
379 def _generate_func_trace_proto_params(self
, stream
, event
):
380 if stream
.event_header_type
is not None:
385 self
._generate
_proto
_params
(stream
.event_header_type
,
386 _PREFIX_SEH
, exclude_list
)
388 if stream
.event_context_type
is not None:
389 self
._generate
_proto
_params
(stream
.event_context_type
,
392 if event
.context_type
is not None:
393 self
._generate
_proto
_params
(event
.context_type
,
396 if event
.payload_type
is not None:
397 self
._generate
_proto
_params
(event
.payload_type
,
400 def _generate_func_trace_proto(self
, stream
, event
):
401 tmpl
= templates
._FUNC
_TRACE
_PROTO
_BEGIN
402 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
,
403 sname
=stream
.name
, evname
=event
.name
))
404 self
._generate
_func
_trace
_proto
_params
(stream
, event
)
405 tmpl
= templates
._FUNC
_TRACE
_PROTO
_END
406 self
._cg
.add_lines(tmpl
)
408 def _punctuate_proto(self
):
409 self
._cg
.append_to_last_line(';')
411 def generate_header(self
):
413 dt
= datetime
.datetime
.now().isoformat()
414 bh_filename
= self
.get_bitfield_header_filename()
416 default_stream_def
= ''
418 if self
._cfg
.options
.gen_prefix_def
:
419 prefix_def
= '#define _BARECTF_PREFIX {}'.format(self
._cfg
.prefix
)
421 if self
._cfg
.options
.gen_default_stream_def
and self
._cfg
.metadata
.default_stream_name
is not None:
422 default_stream_def
= '#define _BARECTF_DEFAULT_STREAM {}'.format(self
._cfg
.metadata
.default_stream_name
)
424 default_stream_trace_defs
= ''
425 default_stream_name
= self
._cfg
.metadata
.default_stream_name
427 if default_stream_name
is not None:
428 default_stream
= self
._cfg
.metadata
.streams
[default_stream_name
]
431 for ev_name
in default_stream
.events
.keys():
432 tmpl
= templates
._DEFINE
_DEFAULT
_STREAM
_TRACE
433 define
= tmpl
.format(prefix
=self
._cfg
.prefix
,
434 sname
=default_stream_name
,
438 default_stream_trace_defs
= '\n'.join(lines
)
440 tmpl
= templates
._HEADER
_BEGIN
441 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
,
442 ucprefix
=self
._cfg
.prefix
.upper(),
443 bitfield_header_filename
=bh_filename
,
444 version
=barectf
.__version
__, date
=dt
,
445 prefix_def
=prefix_def
,
446 default_stream_def
=default_stream_def
,
447 default_stream_trace_defs
=default_stream_trace_defs
))
448 self
._cg
.add_empty_line()
450 # platform callbacks structure
451 self
._generate
_platform
_callbacks
()
452 self
._cg
.add_empty_line()
455 self
._generate
_ctx
_parent
()
456 self
._cg
.add_empty_line()
459 self
._generate
_ctxs
()
460 self
._cg
.add_empty_line()
462 # initialization function prototype
463 self
._generate
_func
_init
_proto
()
464 self
._punctuate
_proto
()
465 self
._cg
.add_empty_line()
467 for stream
in self
._cfg
.metadata
.streams
.values():
468 self
._generate
_func
_open
_proto
(stream
)
469 self
._punctuate
_proto
()
470 self
._cg
.add_empty_line()
471 self
._generate
_func
_close
_proto
(stream
)
472 self
._punctuate
_proto
()
473 self
._cg
.add_empty_line()
475 for ev
in stream
.events
.values():
476 self
._generate
_func
_trace
_proto
(stream
, ev
)
477 self
._punctuate
_proto
()
478 self
._cg
.add_empty_line()
480 tmpl
= templates
._HEADER
_END
481 self
._cg
.add_lines(tmpl
.format(ucprefix
=self
._cfg
.prefix
.upper()))
485 def _get_call_event_param_list_from_struct(self
, t
, prefix
, exclude_list
):
488 for field_name
in t
.fields
:
489 if field_name
in exclude_list
:
492 lst
+= ', {}{}'.format(prefix
, field_name
)
496 def _get_call_event_param_list(self
, stream
, event
):
498 gcp_func
= self
._get
_call
_event
_param
_list
_from
_struct
500 if stream
.event_header_type
is not None:
505 lst
+= gcp_func(stream
.event_header_type
, _PREFIX_SEH
, exclude_list
)
507 if stream
.event_context_type
is not None:
508 lst
+= gcp_func(stream
.event_context_type
, _PREFIX_SEC
, [])
510 if event
.context_type
is not None:
511 lst
+= gcp_func(event
.context_type
, _PREFIX_EC
, [])
513 if event
.payload_type
is not None:
514 lst
+= gcp_func(event
.payload_type
, _PREFIX_EP
, [])
518 def _generate_align(self
, at
, align
):
519 self
._cg
.add_line('_ALIGN({}, {});'.format(at
, align
))
521 def _generate_align_type(self
, at
, t
):
525 self
._generate
_align
(at
, t
.align
)
527 def _generate_incr_pos(self
, var
, value
):
528 self
._cg
.add_line('{} += {};'.format(var
, value
))
530 def _generate_incr_pos_bytes(self
, var
, value
):
531 self
._generate
_incr
_pos
(var
, '_BYTES_TO_BITS({})'.format(value
))
533 def _generate_func_get_event_size_proto(self
, stream
, event
):
534 tmpl
= templates
._FUNC
_GET
_EVENT
_SIZE
_PROTO
_BEGIN
535 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
,
536 sname
=stream
.name
, evname
=event
.name
))
537 self
._generate
_func
_trace
_proto
_params
(stream
, event
)
538 tmpl
= templates
._FUNC
_GET
_EVENT
_SIZE
_PROTO
_END
539 self
._cg
.add_lines(tmpl
)
541 def _generate_func_get_event_size(self
, stream
, event
):
542 self
._generate
_func
_get
_event
_size
_proto
(stream
, event
)
543 tmpl
= templates
._FUNC
_GET
_EVENT
_SIZE
_BODY
_BEGIN
544 lines
= tmpl
.format(prefix
=self
._cfg
.prefix
)
545 self
._cg
.add_lines(lines
)
546 self
._cg
.add_empty_line()
548 ser_actions
= _SerializationActions()
549 ser_actions
.append_root_scope_type(stream
.event_header_type
,
551 ser_actions
.append_root_scope_type(stream
.event_context_type
,
553 ser_actions
.append_root_scope_type(event
.context_type
, _PREFIX_EC
)
554 ser_actions
.append_root_scope_type(event
.payload_type
, _PREFIX_EP
)
556 for action
in ser_actions
.actions
:
557 if type(action
) is _AlignSerializationAction
:
559 if len(action
.names
) == 1:
560 line
= 'align {} structure'.format(_PREFIX_TO_NAME
[action
.names
[0]])
562 fmt
= 'align field `{}` ({})'
563 line
= fmt
.format(action
.names
[-1],
564 _PREFIX_TO_NAME
[action
.names
[0]])
566 self
._cg
.add_cc_line(line
)
568 self
._generate
_align
('at', action
.value
)
569 self
._cg
.add_empty_line()
570 elif type(action
) is _SerializeSerializationAction
:
571 assert(len(action
.names
) >= 2)
572 fmt
= 'add size of field `{}` ({})'
573 line
= fmt
.format(action
.names
[-1], _PREFIX_TO_NAME
[action
.names
[0]])
574 self
._cg
.add_cc_line(line
)
576 if type(action
.type) is metadata
.String
:
577 param
= ''.join(action
.names
)
578 self
._generate
_incr
_pos
_bytes
('at',
579 'strlen({}) + 1'.format(param
))
581 self
._generate
_incr
_pos
('at', action
.type.size
)
583 self
._cg
.add_empty_line()
586 tmpl
= templates
._FUNC
_GET
_EVENT
_SIZE
_BODY
_END
587 self
._cg
.add_lines(tmpl
)
589 def _generate_func_serialize_event_proto(self
, stream
, event
):
590 tmpl
= templates
._FUNC
_SERIALIZE
_EVENT
_PROTO
_BEGIN
591 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
,
592 sname
=stream
.name
, evname
=event
.name
))
593 self
._generate
_func
_trace
_proto
_params
(stream
, event
)
594 tmpl
= templates
._FUNC
_SERIALIZE
_EVENT
_PROTO
_END
595 self
._cg
.add_lines(tmpl
)
597 def _generate_bitfield_write(self
, ctype
, var
, ctx
, action
):
598 ptr
= '&{ctx}->buf[_BITS_TO_BYTES({ctx}->at)]'.format(ctx
=ctx
)
599 start
= action
.offset_in_byte
600 suffix
= 'le' if action
.type.byte_order
is metadata
.ByteOrder
.LE
else 'be'
601 func
= '{}bt_bitfield_write_{}'.format(self
._cfg
.prefix
, suffix
)
602 call_fmt
= '{func}({ptr}, uint8_t, {start}, {size}, {ctype}, ({ctype}) {var});'
603 call
= call_fmt
.format(func
=func
, ptr
=ptr
, start
=start
,
604 size
=action
.type.size
, ctype
=ctype
, var
=var
)
605 self
._cg
.add_line(call
)
607 def _generate_serialize_int(self
, var
, ctx
, action
):
608 ctype
= self
._get
_int
_ctype
(action
.type)
609 self
._generate
_bitfield
_write
(ctype
, var
, ctx
, action
)
610 self
._generate
_incr
_pos
('{}->at'.format(ctx
), action
.type.size
)
612 def _generate_serialize_float(self
, var
, ctx
, action
):
613 ctype
= self
._get
_type
_ctype
(action
.type)
616 if ctype
== 'float' or ctype
== 'double':
621 int_ctype
= 'uint32_t'
622 elif ctype
== 'double':
624 int_ctype
= 'uint64_t'
626 # union for reading the bytes of the floating point number
627 self
._cg
.add_empty_line()
628 self
._cg
.add_line('{')
630 self
._cg
.add_line('union {name} {name};'.format(name
=union_name
))
631 self
._cg
.add_empty_line()
632 self
._cg
.add_line('{}.f = {};'.format(union_name
, var
))
633 bf_var
= '{}.u'.format(union_name
)
635 bf_var
= '({}) {}'.format(ctype
, var
)
638 self
._generate
_bitfield
_write
(int_ctype
, bf_var
, ctx
, action
)
642 self
._cg
.add_line('}')
643 self
._cg
.add_empty_line()
645 self
._generate
_incr
_pos
('{}->at'.format(ctx
), action
.type.size
)
647 def _generate_serialize_enum(self
, var
, ctx
, action
):
648 sub_action
= _SerializeSerializationAction(action
.offset_in_byte
,
649 action
.type.value_type
,
651 self
._generate
_serialize
_from
_action
(var
, ctx
, sub_action
)
653 def _generate_serialize_string(self
, var
, ctx
, action
):
654 tmpl
= '_write_cstring({}, {});'.format(ctx
, var
)
655 self
._cg
.add_lines(tmpl
)
657 def _generate_serialize_from_action(self
, var
, ctx
, action
):
658 func
= self
._type
_to
_generate
_serialize
_func
[type(action
.type)]
659 func(var
, ctx
, action
)
661 def _generate_serialize_statements_from_actions(self
, prefix
, action_iter
,
663 for action
in action_iter
:
664 if type(action
) is _AlignSerializationAction
:
666 if len(action
.names
) == 1:
667 line
= 'align {} structure'.format(_PREFIX_TO_NAME
[action
.names
[0]])
669 fmt
= 'align field `{}` ({})'
670 line
= fmt
.format(action
.names
[-1],
671 _PREFIX_TO_NAME
[action
.names
[0]])
673 self
._cg
.add_cc_line(line
)
675 self
._generate
_align
('ctx->at', action
.value
)
676 self
._cg
.add_empty_line()
677 elif type(action
) is _SerializeSerializationAction
:
678 assert(len(action
.names
) >= 2)
679 fmt
= 'serialize field `{}` ({})'
680 line
= fmt
.format(action
.names
[-1],
681 _PREFIX_TO_NAME
[action
.names
[0]])
682 self
._cg
.add_cc_line(line
)
683 field_name
= action
.names
[-1]
684 src
= prefix
+ field_name
686 if spec_src
is not None and field_name
in spec_src
:
687 src
= spec_src
[field_name
]
689 self
._generate
_serialize
_from
_action
(src
, 'ctx', action
)
690 self
._cg
.add_empty_line()
692 def _generate_func_serialize_event(self
, stream
, event
, orig_ser_actions
):
693 self
._generate
_func
_serialize
_event
_proto
(stream
, event
)
694 tmpl
= templates
._FUNC
_SERIALIZE
_EVENT
_BODY
_BEGIN
695 lines
= tmpl
.format(prefix
=self
._cfg
.prefix
)
696 self
._cg
.add_lines(lines
)
698 self
._cg
.add_empty_line()
700 if stream
.event_header_type
is not None:
701 t
= stream
.event_header_type
702 exclude_list
= ['timestamp', 'id']
703 params
= self
._get
_call
_event
_param
_list
_from
_struct
(t
, _PREFIX_SEH
,
705 tmpl
= '_serialize_stream_event_header_{sname}(ctx, {evid}{params});'
706 self
._cg
.add_cc_line('stream event header')
707 self
._cg
.add_line(tmpl
.format(sname
=stream
.name
, evid
=event
.id,
709 self
._cg
.add_empty_line()
711 if stream
.event_context_type
is not None:
712 t
= stream
.event_context_type
713 params
= self
._get
_call
_event
_param
_list
_from
_struct
(t
, _PREFIX_SEC
,
715 tmpl
= '_serialize_stream_event_context_{sname}(ctx{params});'
716 self
._cg
.add_cc_line('stream event context')
717 self
._cg
.add_line(tmpl
.format(sname
=stream
.name
, params
=params
))
718 self
._cg
.add_empty_line()
720 if event
.context_type
is not None or event
.payload_type
is not None:
721 ser_actions
= copy
.deepcopy(orig_ser_actions
)
723 if event
.context_type
is not None:
724 ser_action_index
= len(ser_actions
.actions
)
725 ser_actions
.append_root_scope_type(event
.context_type
, _PREFIX_EC
)
726 ser_action_iter
= itertools
.islice(ser_actions
.actions
,
727 ser_action_index
, None)
728 self
._generate
_serialize
_statements
_from
_actions
(_PREFIX_EC
,
731 if event
.payload_type
is not None:
732 ser_action_index
= len(ser_actions
.actions
)
733 ser_actions
.append_root_scope_type(event
.payload_type
, _PREFIX_EP
)
734 ser_action_iter
= itertools
.islice(ser_actions
.actions
,
735 ser_action_index
, None)
736 self
._generate
_serialize
_statements
_from
_actions
(_PREFIX_EP
,
740 tmpl
= templates
._FUNC
_SERIALIZE
_EVENT
_BODY
_END
741 self
._cg
.add_lines(tmpl
)
743 def _generate_func_serialize_stream_event_header_proto(self
, stream
):
744 tmpl
= templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_HEADER
_PROTO
_BEGIN
745 clock_ctype
= 'const int'
746 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
,
749 if stream
.event_header_type
is not None:
754 self
._generate
_proto
_params
(stream
.event_header_type
,
755 _PREFIX_SEH
, exclude_list
)
757 tmpl
= templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_HEADER
_PROTO
_END
758 self
._cg
.add_lines(tmpl
)
760 def _generate_func_serialize_stream_event_context_proto(self
, stream
):
761 tmpl
= templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_CONTEXT
_PROTO
_BEGIN
762 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
,
765 if stream
.event_context_type
is not None:
766 self
._generate
_proto
_params
(stream
.event_context_type
,
769 tmpl
= templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_CONTEXT
_PROTO
_END
770 self
._cg
.add_lines(tmpl
)
772 def _generate_func_serialize_stream_event_header(self
, stream
,
774 self
._generate
_func
_serialize
_stream
_event
_header
_proto
(stream
)
775 tmpl
= templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_HEADER
_BODY
_BEGIN
776 lines
= tmpl
.format(prefix
=self
._cfg
.prefix
, sname
=stream
.name
)
777 self
._cg
.add_lines(lines
)
779 clock
= self
._get
_stream
_clock
(stream
)
781 if clock
is not None:
782 tmpl
= 'struct {prefix}{sname}_ctx *s_ctx = FROM_VOID_PTR(struct {prefix}{sname}_ctx, vctx);'
783 line
= tmpl
.format(prefix
=self
._cfg
.prefix
,
785 self
._cg
.add_line(line
)
786 tmpl
= 'const {} ts = s_ctx->cur_last_event_ts;'
787 line
= tmpl
.format(clock
.return_ctype
)
788 self
._cg
.add_line(line
)
790 self
._cg
.add_empty_line()
792 if stream
.event_header_type
is not None:
795 if 'id' in stream
.event_header_type
.fields
:
796 id_t
= stream
.event_header_type
.fields
['id']
797 id_t_ctype
= self
._get
_int
_ctype
(id_t
)
798 spec_src
['id'] = '({}) event_id'.format(id_t_ctype
)
800 if 'timestamp' in stream
.event_header_type
.fields
:
801 field
= stream
.event_header_type
.fields
['timestamp']
802 ts_ctype
= self
._get
_int
_ctype
(field
)
803 spec_src
['timestamp'] = '({}) ts'.format(ts_ctype
)
805 self
._generate
_serialize
_statements
_from
_actions
(_PREFIX_SEH
,
810 tmpl
= templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_HEADER
_BODY
_END
811 self
._cg
.add_lines(tmpl
)
813 def _generate_func_serialize_stream_event_context(self
, stream
,
815 self
._generate
_func
_serialize
_stream
_event
_context
_proto
(stream
)
816 tmpl
= templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_CONTEXT
_BODY
_BEGIN
817 lines
= tmpl
.format(prefix
=self
._cfg
.prefix
)
818 self
._cg
.add_lines(lines
)
821 if stream
.event_context_type
is not None:
822 self
._generate
_serialize
_statements
_from
_actions
(_PREFIX_SEC
,
826 tmpl
= templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_CONTEXT
_BODY
_END
827 self
._cg
.add_lines(tmpl
)
829 def _generate_func_trace(self
, stream
, event
):
830 self
._generate
_func
_trace
_proto
(stream
, event
)
831 params
= self
._get
_call
_event
_param
_list
(stream
, event
)
832 clock
= self
._get
_stream
_clock
(stream
)
834 if clock
is not None:
835 tmpl
= 'ctx->cur_last_event_ts = ctx->parent.cbs.{}_clock_get_value(ctx->parent.data);'
836 save_ts_line
= tmpl
.format(clock
.name
)
838 save_ts_line
= '/* (no clock) */'
840 tmpl
= templates
._FUNC
_TRACE
_BODY
841 self
._cg
.add_lines(tmpl
.format(sname
=stream
.name
, evname
=event
.name
,
842 params
=params
, save_ts
=save_ts_line
))
844 def _generate_func_init(self
):
845 self
._generate
_func
_init
_proto
()
846 tmpl
= templates
._FUNC
_INIT
_BODY
847 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
))
849 def _generate_field_name_cc_line(self
, field_name
):
850 self
._cg
.add_cc_line('`{}` field'.format(field_name
))
852 def _save_serialization_action(self
, name
, action
):
853 self
._saved
_serialization
_actions
[name
] = action
855 def _get_open_close_ts_line(self
, stream
):
856 clock
= self
._get
_stream
_clock
(stream
)
861 tmpl
= '\tconst {} ts = ctx->parent.use_cur_last_event_ts ? ctx->cur_last_event_ts : ctx->parent.cbs.{}_clock_get_value(ctx->parent.data);'
862 line
= tmpl
.format(clock
.return_ctype
, clock
.name
)
865 def _generate_func_open(self
, stream
):
866 def generate_save_offset(name
, action
):
867 tmpl
= 'ctx->off_spc_{} = ctx->parent.at;'.format(name
)
868 self
._cg
.add_line(tmpl
)
869 self
._save
_serialization
_action
(name
, action
)
871 self
._generate
_func
_open
_proto
(stream
)
872 tmpl
= templates
._FUNC
_OPEN
_BODY
_BEGIN
873 spc_type
= stream
.packet_context_type
874 ts_line
= self
._get
_open
_close
_ts
_line
(stream
)
875 lines
= tmpl
.format(ts
=ts_line
)
876 self
._cg
.add_lines(lines
)
878 self
._cg
.add_cc_line('do not open a packet that is already open')
879 self
._cg
.add_line('if (ctx->parent.packet_is_open) {')
881 self
._cg
.add_line('ctx->parent.in_tracing_section = saved_in_tracing_section;')
882 self
._cg
.add_line('return;')
884 self
._cg
.add_line('}')
885 self
._cg
.add_empty_line()
886 self
._cg
.add_line('ctx->parent.at = 0;')
887 tph_type
= self
._cfg
.metadata
.trace
.packet_header_type
888 ser_actions
= _SerializationActions()
890 if tph_type
is not None:
891 self
._cg
.add_empty_line()
892 self
._cg
.add_cc_line('trace packet header')
893 self
._cg
.add_line('{')
895 ser_actions
.append_root_scope_type(tph_type
, _PREFIX_TPH
)
897 for action
in ser_actions
.actions
:
898 if type(action
) is _AlignSerializationAction
:
900 if len(action
.names
) == 1:
901 line
= 'align trace packet header structure'
903 line
= 'align field `{}`'.format(action
.names
[-1])
905 self
._cg
.add_cc_line(line
)
907 self
._generate
_align
('ctx->parent.at', action
.value
)
908 self
._cg
.add_empty_line()
909 elif type(action
) is _SerializeSerializationAction
:
910 assert(len(action
.names
) >= 2)
911 fmt
= 'serialize field `{}`'
912 line
= fmt
.format(action
.names
[-1])
913 self
._cg
.add_cc_line(line
)
914 field_name
= action
.names
[-1]
915 src
= _PREFIX_TPH
+ field_name
917 if field_name
== 'magic':
919 elif field_name
== 'stream_id':
920 stream_id_ctype
= self
._get
_int
_ctype
(action
.type)
921 src
= '({}) {}'.format(stream_id_ctype
, stream
.id)
922 elif field_name
== 'uuid':
923 self
._cg
.add_line('{')
925 self
._cg
.add_line('static uint8_t uuid[] = {')
928 for b
in self
._cfg
.metadata
.trace
.uuid
.bytes
:
929 self
._cg
.add_line('{},'.format(b
))
932 self
._cg
.add_line('};')
933 self
._cg
.add_empty_line()
934 self
._generate
_align
('ctx->parent.at', 8)
935 line
= 'memcpy(&ctx->parent.buf[_BITS_TO_BYTES(ctx->parent.at)], uuid, 16);'
936 self
._cg
.add_line(line
)
937 self
._generate
_incr
_pos
_bytes
('ctx->parent.at', 16)
939 self
._cg
.add_line('}')
940 self
._cg
.add_empty_line()
943 self
._generate
_serialize
_from
_action
(src
, '(&ctx->parent)', action
)
944 self
._cg
.add_empty_line()
947 self
._cg
.add_lines('}')
949 spc_action_index
= len(ser_actions
.actions
)
951 if spc_type
is not None:
952 self
._cg
.add_empty_line()
953 self
._cg
.add_cc_line('stream packet context')
954 self
._cg
.add_line('{')
956 ser_actions
.append_root_scope_type(spc_type
, _PREFIX_SPC
)
957 tmpl_off
= 'off_spc_{fname}'
959 for action
in itertools
.islice(ser_actions
.actions
, spc_action_index
, None):
960 if type(action
) is _AlignSerializationAction
:
962 if len(action
.names
) == 1:
963 line
= 'align stream packet context structure'
965 line
= 'align field `{}`'.format(action
.names
[-1])
967 self
._cg
.add_cc_line(line
)
969 self
._generate
_align
('ctx->parent.at', action
.value
)
970 self
._cg
.add_empty_line()
971 elif type(action
) is _SerializeSerializationAction
:
972 assert(len(action
.names
) >= 2)
973 fmt
= 'serialize field `{}`'
974 line
= fmt
.format(action
.names
[-1])
975 self
._cg
.add_cc_line(line
)
976 field_name
= action
.names
[-1]
977 src
= _PREFIX_SPC
+ field_name
980 if field_name
== 'timestamp_begin':
981 ctype
= self
._get
_type
_ctype
(action
.type)
982 src
= '({}) ts'.format(ctype
)
983 elif field_name
in ['timestamp_end', 'content_size',
986 elif field_name
== 'packet_size':
987 ctype
= self
._get
_type
_ctype
(action
.type)
988 src
= '({}) ctx->parent.packet_size'.format(ctype
)
991 generate_save_offset(field_name
, action
)
992 self
._generate
_incr
_pos
('ctx->parent.at',
995 self
._generate
_serialize
_from
_action
(src
, '(&ctx->parent)',
998 self
._cg
.add_empty_line()
1001 self
._cg
.add_lines('}')
1004 tmpl
= templates
._FUNC
_OPEN
_BODY
_END
1005 self
._cg
.add_lines(tmpl
)
1007 def _generate_func_close(self
, stream
):
1008 def generate_goto_offset(name
):
1009 tmpl
= 'ctx->parent.at = ctx->off_spc_{};'.format(name
)
1010 self
._cg
.add_line(tmpl
)
1012 self
._generate
_func
_close
_proto
(stream
)
1013 tmpl
= templates
._FUNC
_CLOSE
_BODY
_BEGIN
1014 spc_type
= stream
.packet_context_type
1015 ts_line
= self
._get
_open
_close
_ts
_line
(stream
)
1016 lines
= tmpl
.format(ts
=ts_line
)
1017 self
._cg
.add_lines(lines
)
1019 self
._cg
.add_cc_line('do not close a packet that is not open')
1020 self
._cg
.add_line('if (!ctx->parent.packet_is_open) {')
1022 self
._cg
.add_line('ctx->parent.in_tracing_section = saved_in_tracing_section;')
1023 self
._cg
.add_line('return;')
1025 self
._cg
.add_line('}')
1026 self
._cg
.add_empty_line()
1027 self
._cg
.add_cc_line('save content size')
1028 self
._cg
.add_line('ctx->parent.content_size = ctx->parent.at;')
1030 if spc_type
is not None:
1031 field_name
= 'timestamp_end'
1033 if field_name
in spc_type
.fields
:
1034 t
= spc_type
.fields
[field_name
]
1035 ctype
= self
._get
_type
_ctype
(t
)
1036 src
= '({}) ts'.format(ctype
)
1037 self
._cg
.add_empty_line()
1038 self
._generate
_field
_name
_cc
_line
(field_name
)
1039 generate_goto_offset(field_name
)
1040 action
= self
._saved
_serialization
_actions
[field_name
]
1041 self
._generate
_serialize
_from
_action
(src
, '(&ctx->parent)', action
)
1043 field_name
= 'content_size'
1045 if 'content_size' in spc_type
.fields
:
1046 t
= spc_type
.fields
[field_name
]
1047 ctype
= self
._get
_type
_ctype
(t
)
1048 src
= '({}) ctx->parent.content_size'.format(ctype
)
1049 self
._cg
.add_empty_line()
1050 self
._generate
_field
_name
_cc
_line
(field_name
)
1051 generate_goto_offset(field_name
)
1052 action
= self
._saved
_serialization
_actions
[field_name
]
1053 self
._generate
_serialize
_from
_action
(src
, '(&ctx->parent)', action
)
1055 field_name
= 'events_discarded'
1057 if field_name
in spc_type
.fields
:
1058 t
= spc_type
.fields
[field_name
]
1059 ctype
= self
._get
_type
_ctype
(t
)
1060 src
= '({}) ctx->parent.events_discarded'.format(ctype
)
1061 self
._cg
.add_empty_line()
1062 self
._generate
_field
_name
_cc
_line
(field_name
)
1063 generate_goto_offset(field_name
)
1064 action
= self
._saved
_serialization
_actions
[field_name
]
1065 self
._generate
_serialize
_from
_action
(src
, '(&ctx->parent)', action
)
1068 tmpl
= templates
._FUNC
_CLOSE
_BODY
_END
1069 self
._cg
.add_lines(tmpl
)
1071 def generate_c_src(self
):
1073 dt
= datetime
.datetime
.now().isoformat()
1074 header_filename
= self
.get_header_filename()
1075 tmpl
= templates
._C
_SRC
1076 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
,
1077 header_filename
=header_filename
,
1078 version
=barectf
.__version
__, date
=dt
))
1079 self
._cg
.add_empty_line()
1081 # initialization function
1082 self
._generate
_func
_init
()
1083 self
._cg
.add_empty_line()
1085 for stream
in self
._cfg
.metadata
.streams
.values():
1086 self
._generate
_func
_open
(stream
)
1087 self
._cg
.add_empty_line()
1088 self
._generate
_func
_close
(stream
)
1089 self
._cg
.add_empty_line()
1090 ser_actions
= _SerializationActions()
1092 if stream
.event_header_type
is not None:
1093 ser_actions
.append_root_scope_type(stream
.event_header_type
,
1095 self
._generate
_func
_serialize
_stream
_event
_header
(stream
,
1096 iter(ser_actions
.actions
))
1097 self
._cg
.add_empty_line()
1099 if stream
.event_context_type
is not None:
1100 ser_action_index
= len(ser_actions
.actions
)
1101 ser_actions
.append_root_scope_type(stream
.event_context_type
,
1103 ser_action_iter
= itertools
.islice(ser_actions
.actions
,
1104 ser_action_index
, None)
1105 self
._generate
_func
_serialize
_stream
_event
_context
(stream
,
1107 self
._cg
.add_empty_line()
1109 for ev
in stream
.events
.values():
1110 self
._generate
_func
_get
_event
_size
(stream
, ev
)
1111 self
._cg
.add_empty_line()
1112 self
._generate
_func
_serialize
_event
(stream
, ev
, ser_actions
)
1113 self
._cg
.add_empty_line()
1114 self
._generate
_func
_trace
(stream
, ev
)
1115 self
._cg
.add_empty_line()
1117 return self
._cg
.code
1119 def get_header_filename(self
):
1120 return '{}.h'.format(self
._cfg
.prefix
.rstrip('_'))
1122 def get_bitfield_header_filename(self
):
1123 return '{}-bitfield.h'.format(self
._cfg
.prefix
.rstrip('_'))