1 # The MIT License (MIT)
3 # Copyright (c) 2014-2016 Philippe Proulx <pproulx@efficios.com>
5 # Permission is hereby granted, free of charge, to any person obtaining a copy
6 # of this software and associated documentation files (the "Software"), to deal
7 # in the Software without restriction, including without limitation the rights
8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 # copies of the Software, and to permit persons to whom the Software is
10 # furnished to do so, subject to the following conditions:
12 # The above copyright notice and this permission notice shall be included in
13 # all copies or substantial portions of the Software.
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 from barectf
import templates
24 from barectf
import metadata
25 import barectf
.codegen
36 return (v
+ (align
- 1)) & -align
39 class _StaticAlignSizeAutomatonByteOffset
:
42 self
._type
_to
_update
_byte
_offset
_func
= {
43 metadata
.Integer
: self
._write
_static
_size
,
44 metadata
.FloatingPoint
: self
._write
_static
_size
,
45 metadata
.Enum
: self
._write
_static
_size
,
46 metadata
.String
: self
._write
_string
_size
,
50 def byte_offset(self
):
51 return self
._byte
_offset
54 def byte_offset(self
, value
):
55 self
._byte
_offset
= value
57 def _wrap_byte_offset(self
):
58 self
._byte
_offset
%= 8
60 def align(self
, align
):
62 self
._byte
_offset
= _align(self
._byte
_offset
, align
)
64 # wrap on current byte
65 self
._wrap
_byte
_offset
()
67 def write_type(self
, t
):
68 self
._type
_to
_update
_byte
_offset
_func
[type(t
)](t
)
70 def _write_string_size(self
, t
):
73 def _write_static_size(self
, t
):
74 # increment byte offset
75 self
._byte
_offset
+= t
.size
77 # wrap on current byte
78 self
._wrap
_byte
_offset
()
84 def set_unknown(self
):
85 self
._byte
_offset
= None
88 class _StaticAlignSizeAutomatonPreSize
:
92 def reset(self
, initial_align
):
93 self
._max
_align
= initial_align
96 def add_type(self
, t
):
97 if t
.align
> self
._max
_align
:
98 # type alignment is greater than the maximum alignment we
99 # got so far since the last reset, so we don't know how many
100 # padding bits are needed between this type and the previous
101 # one, hence the static size is set to the type's size
102 # (since we're aligned) and our new alignment is saved
103 self
._max
_align
= t
.align
105 if type(t
) is metadata
.Struct
:
112 # type alignment is lesser than or equal to the maximum
113 # alignment we got so far, so we just align the static size
114 # and add the type's size
115 self
._size
= _align(self
._size
, t
.align
)
117 if type(t
) is not metadata
.Struct
:
135 class CCodeGenerator
:
136 def __init__(self
, cfg
):
138 self
._cg
= barectf
.codegen
.CodeGenerator('\t')
139 self
._type
_to
_get
_ctype
_func
= {
140 metadata
.Integer
: self
._get
_int
_ctype
,
141 metadata
.FloatingPoint
: self
._get
_float
_ctype
,
142 metadata
.Enum
: self
._get
_enum
_ctype
,
143 metadata
.String
: self
._get
_string
_ctype
,
145 self
._type
_to
_generate
_serialize
_func
= {
146 metadata
.Integer
: self
._generate
_serialize
_int
,
147 metadata
.FloatingPoint
: self
._generate
_serialize
_float
,
148 metadata
.Enum
: self
._generate
_serialize
_enum
,
149 metadata
.String
: self
._generate
_serialize
_string
,
151 self
._saved
_byte
_offsets
= {}
152 self
._uf
_written
= False
153 self
._ud
_written
= False
154 self
._sasa
= _StaticAlignSizeAutomatonByteOffset()
156 def _generate_ctx_parent(self
):
157 tmpl
= templates
._CTX
_PARENT
158 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
))
160 def _generate_ctx(self
, stream
):
161 tmpl
= templates
._CTX
_BEGIN
162 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
,
164 tmpl
= 'uint32_t off_tph_{fname};'
166 trace_packet_header_type
= self
._cfg
.metadata
.trace
.packet_header_type
168 if trace_packet_header_type
is not None:
169 for field_name
in trace_packet_header_type
.fields
:
170 self
._cg
.add_lines(tmpl
.format(fname
=field_name
))
172 tmpl
= 'uint32_t off_spc_{fname};'
174 if stream
.packet_context_type
is not None:
175 for field_name
in stream
.packet_context_type
.fields
:
176 self
._cg
.add_lines(tmpl
.format(fname
=field_name
))
179 tmpl
= templates
._CTX
_END
180 self
._cg
.add_lines(tmpl
)
182 def _generate_ctxs(self
):
183 for stream
in self
._cfg
.metadata
.streams
.values():
184 self
._generate
_ctx
(stream
)
186 def _generate_clock_cb(self
, clock
):
187 tmpl
= templates
._CLOCK
_CB
188 self
._cg
.add_lines(tmpl
.format(return_ctype
=clock
.return_ctype
,
191 def _generate_clock_cbs(self
):
192 for clock
in self
._cfg
.metadata
.clocks
.values():
193 self
._generate
_clock
_cb
(clock
)
195 def _generate_platform_callbacks(self
):
196 tmpl
= templates
._PLATFORM
_CALLBACKS
_BEGIN
197 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
))
199 self
._generate
_clock
_cbs
()
201 tmpl
= templates
._PLATFORM
_CALLBACKS
_END
202 self
._cg
.add_lines(tmpl
)
204 def generate_bitfield_header(self
):
206 tmpl
= templates
._BITFIELD
207 tmpl
= tmpl
.replace('$prefix$', self
._cfg
.prefix
)
208 tmpl
= tmpl
.replace('$PREFIX$', self
._cfg
.prefix
.upper())
210 if self
._cfg
.metadata
.trace
.byte_order
== metadata
.ByteOrder
.BE
:
211 endian_def
= 'BIG_ENDIAN'
213 endian_def
= 'LITTLE_ENDIAN'
215 tmpl
= tmpl
.replace('$ENDIAN_DEF$', endian_def
)
216 self
._cg
.add_lines(tmpl
)
220 def _generate_func_init_proto(self
):
221 tmpl
= templates
._FUNC
_INIT
_PROTO
222 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
))
224 def _get_int_ctype(self
, t
):
225 signed
= 'u' if not t
.signed
else ''
236 return '{}int{}_t'.format(signed
, sz
)
238 def _get_float_ctype(self
, t
):
239 if t
.exp_size
== 8 and t
.mant_size
== 24 and t
.align
== 32:
241 elif t
.exp_size
== 11 and t
.mant_size
== 53 and t
.align
== 64:
248 def _get_enum_ctype(self
, t
):
249 return self
._get
_int
_ctype
(t
.value_type
)
251 def _get_string_ctype(self
, t
):
252 return 'const char *'
254 def _get_type_ctype(self
, t
):
255 return self
._type
_to
_get
_ctype
_func
[type(t
)](t
)
257 def _generate_type_ctype(self
, t
):
258 ctype
= self
._get
_type
_ctype
(t
)
259 self
._cg
.append_to_last_line(ctype
)
261 def _generate_proto_param(self
, t
, name
):
262 self
._generate
_type
_ctype
(t
)
263 self
._cg
.append_to_last_line(' ')
264 self
._cg
.append_to_last_line(name
)
266 def _generate_proto_params(self
, t
, name_prefix
, exclude_list
):
269 for field_name
, field_type
in t
.fields
.items():
270 if field_name
in exclude_list
:
273 name
= name_prefix
+ field_name
274 self
._cg
.append_to_last_line(',')
275 self
._cg
.add_line('')
276 self
._generate
_proto
_param
(field_type
, name
)
280 def _generate_func_open_proto(self
, stream
):
281 tmpl
= templates
._FUNC
_OPEN
_PROTO
_BEGIN
282 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
,
284 trace_packet_header_type
= self
._cfg
.metadata
.trace
.packet_header_type
286 if trace_packet_header_type
is not None:
287 exclude_list
= ['magic', 'stream_id', 'uuid']
288 self
._generate
_proto
_params
(trace_packet_header_type
, _PREFIX_TPH
,
291 if stream
.packet_context_type
is not None:
299 self
._generate
_proto
_params
(stream
.packet_context_type
,
300 _PREFIX_SPC
, exclude_list
)
302 tmpl
= templates
._FUNC
_OPEN
_PROTO
_END
303 self
._cg
.add_lines(tmpl
)
305 def _generate_func_close_proto(self
, stream
):
306 tmpl
= templates
._FUNC
_CLOSE
_PROTO
307 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
,
310 def _generate_func_trace_proto_params(self
, stream
, event
):
311 if stream
.event_header_type
is not None:
316 self
._generate
_proto
_params
(stream
.event_header_type
,
317 _PREFIX_SEH
, exclude_list
)
319 if stream
.event_context_type
is not None:
320 self
._generate
_proto
_params
(stream
.event_context_type
,
323 if event
.context_type
is not None:
324 self
._generate
_proto
_params
(event
.context_type
,
327 if event
.payload_type
is not None:
328 self
._generate
_proto
_params
(event
.payload_type
,
331 def _generate_func_trace_proto(self
, stream
, event
):
332 tmpl
= templates
._FUNC
_TRACE
_PROTO
_BEGIN
333 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
,
334 sname
=stream
.name
, evname
=event
.name
))
335 self
._generate
_func
_trace
_proto
_params
(stream
, event
)
336 tmpl
= templates
._FUNC
_TRACE
_PROTO
_END
337 self
._cg
.add_lines(tmpl
)
339 def _punctuate_proto(self
):
340 self
._cg
.append_to_last_line(';')
342 def generate_header(self
):
344 dt
= datetime
.datetime
.now().isoformat()
345 bh_filename
= self
.get_bitfield_header_filename()
346 tmpl
= templates
._HEADER
_BEGIN
347 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
,
348 ucprefix
=self
._cfg
.prefix
.upper(),
349 bitfield_header_filename
=bh_filename
,
350 version
=barectf
.__version
__, date
=dt
))
351 self
._cg
.add_empty_line()
353 # platform callbacks structure
354 self
._generate
_platform
_callbacks
()
355 self
._cg
.add_empty_line()
358 self
._generate
_ctx
_parent
()
359 self
._cg
.add_empty_line()
362 self
._generate
_ctxs
()
363 self
._cg
.add_empty_line()
365 # initialization function prototype
366 self
._generate
_func
_init
_proto
()
367 self
._punctuate
_proto
()
368 self
._cg
.add_empty_line()
370 for stream
in self
._cfg
.metadata
.streams
.values():
371 self
._generate
_func
_open
_proto
(stream
)
372 self
._punctuate
_proto
()
373 self
._cg
.add_empty_line()
374 self
._generate
_func
_close
_proto
(stream
)
375 self
._punctuate
_proto
()
376 self
._cg
.add_empty_line()
378 for ev
in stream
.events
.values():
379 self
._generate
_func
_trace
_proto
(stream
, ev
)
380 self
._punctuate
_proto
()
381 self
._cg
.add_empty_line()
383 tmpl
= templates
._HEADER
_END
384 self
._cg
.add_lines(tmpl
.format(ucprefix
=self
._cfg
.prefix
.upper()))
388 def _get_call_event_param_list_from_struct(self
, t
, prefix
, exclude_list
):
391 for field_name
in t
.fields
:
392 if field_name
in exclude_list
:
395 lst
+= ', {}{}'.format(prefix
, field_name
)
399 def _get_call_event_param_list(self
, stream
, event
):
401 gcp_func
= self
._get
_call
_event
_param
_list
_from
_struct
403 if stream
.event_header_type
is not None:
408 lst
+= gcp_func(stream
.event_header_type
, _PREFIX_SEH
, exclude_list
)
410 if stream
.event_context_type
is not None:
411 lst
+= gcp_func(stream
.event_context_type
, _PREFIX_SEC
, [])
413 if event
.context_type
is not None:
414 lst
+= gcp_func(event
.context_type
, _PREFIX_EC
, [])
416 if event
.payload_type
is not None:
417 lst
+= gcp_func(event
.payload_type
, _PREFIX_EP
, [])
421 def _generate_align(self
, at
, align
):
422 self
._cg
.add_line('_ALIGN({}, {});'.format(at
, align
))
423 self
._sasa
.align(align
)
425 def _generate_align_type(self
, at
, t
):
429 self
._generate
_align
(at
, t
.align
)
431 def _generate_incr_pos(self
, var
, value
):
432 self
._cg
.add_line('{} += {};'.format(var
, value
))
434 def _generate_incr_pos_bytes(self
, var
, value
):
435 self
._generate
_incr
_pos
(var
, '_BYTES_TO_BITS({})'.format(value
))
437 def _generate_func_get_event_size_proto(self
, stream
, event
):
438 tmpl
= templates
._FUNC
_GET
_EVENT
_SIZE
_PROTO
_BEGIN
439 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
,
440 sname
=stream
.name
, evname
=event
.name
))
441 self
._generate
_func
_trace
_proto
_params
(stream
, event
)
442 tmpl
= templates
._FUNC
_GET
_EVENT
_SIZE
_PROTO
_END
443 self
._cg
.add_lines(tmpl
)
445 def _generate_func_get_event_size_from_entity(self
, prefix
, t
):
446 self
._cg
.add_line('{')
448 statically_aligned
= self
._pre
_size
_sasa
.add_type(t
)
450 if not statically_aligned
:
451 # increment current position if needed
452 if self
._last
_basic
_types
_size
> 0:
453 self
._generate
_incr
_pos
('at', self
._last
_basic
_types
_size
)
454 self
._last
_basic
_types
_size
= 0
456 self
._cg
.add_cc_line('align structure')
457 self
._generate
_align
_type
('at', t
)
459 for field_name
, field_type
in t
.fields
.items():
460 self
._cg
.add_empty_line()
461 self
._generate
_field
_name
_cc
_line
(field_name
)
463 if type(field_type
) is metadata
.String
:
464 # increment current position if needed
465 if self
._last
_basic
_types
_size
> 0:
466 self
._generate
_incr
_pos
('at', self
._last
_basic
_types
_size
)
467 self
._last
_basic
_types
_size
= 0
469 param
= prefix
+ field_name
470 self
._generate
_incr
_pos
_bytes
('at',
471 'strlen({}) + 1'.format(param
))
472 self
._pre
_size
_sasa
.reset(8)
474 statically_aligned
= self
._pre
_size
_sasa
.add_type(field_type
)
476 if not statically_aligned
:
477 # increment current position if needed
478 if self
._last
_basic
_types
_size
> 0:
479 self
._generate
_incr
_pos
('at', self
._last
_basic
_types
_size
)
481 # realign dynamically
482 self
._cg
.add_cc_line('align for field')
483 self
._generate
_align
_type
('at', field_type
)
485 fmt
= 'field size: {} (partial total so far: {})'
486 self
._cg
.add_cc_line(fmt
.format(field_type
.size
, self
._pre
_size
_sasa
.size
))
487 self
._last
_basic
_types
_size
= self
._pre
_size
_sasa
.size
490 self
._cg
.add_line('}')
491 self
._cg
.add_empty_line()
493 def _generate_func_get_event_size(self
, stream
, event
):
494 self
._reset
_per
_func
_state
()
495 self
._generate
_func
_get
_event
_size
_proto
(stream
, event
)
496 tmpl
= templates
._FUNC
_GET
_EVENT
_SIZE
_BODY
_BEGIN
497 self
._cg
.add_lines(tmpl
)
498 self
._cg
.add_empty_line()
500 func
= self
._generate
_func
_get
_event
_size
_from
_entity
501 self
._pre
_size
_sasa
= _StaticAlignSizeAutomatonPreSize()
502 self
._cg
.add_cc_line('byte-align entity')
503 self
._generate
_align
('at', 8)
504 self
._cg
.add_empty_line()
505 self
._pre
_size
_sasa
.reset(8)
506 self
._last
_basic
_types
_size
= 0
508 if stream
.event_header_type
is not None:
509 self
._cg
.add_cc_line('stream event header')
510 func(_PREFIX_SEH
, stream
.event_header_type
)
512 if stream
.event_context_type
is not None:
513 self
._cg
.add_cc_line('stream event context')
514 func(_PREFIX_SEC
, stream
.event_context_type
)
516 if event
.context_type
is not None:
517 self
._cg
.add_cc_line('event context')
518 func(_PREFIX_EC
, event
.context_type
)
520 if event
.payload_type
is not None:
521 self
._cg
.add_cc_line('event payload')
522 func(_PREFIX_EP
, event
.payload_type
)
524 # increment current position if needed
525 if self
._last
_basic
_types
_size
> 0:
526 self
._generate
_incr
_pos
('at', self
._last
_basic
_types
_size
)
527 self
._cg
.add_empty_line()
530 tmpl
= templates
._FUNC
_GET
_EVENT
_SIZE
_BODY
_END
531 self
._cg
.add_lines(tmpl
)
533 def _generate_func_serialize_event_proto(self
, stream
, event
):
534 tmpl
= templates
._FUNC
_SERIALIZE
_EVENT
_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
_SERIALIZE
_EVENT
_PROTO
_END
539 self
._cg
.add_lines(tmpl
)
541 def _generate_bitfield_write(self
, var
, ctx
, t
):
542 ptr
= '&{ctx}->buf[_BITS_TO_BYTES({ctx}->at)]'.format(ctx
=ctx
)
543 start
= self
._sasa
.byte_offset
544 suffix
= 'le' if t
.byte_order
is metadata
.ByteOrder
.LE
else 'be'
545 func
= '{}bt_bitfield_write_{}'.format(self
._cfg
.prefix
, suffix
)
546 call
= '{}({}, uint8_t, {}, {}, {});'.format(func
, ptr
, start
, t
.size
,
548 self
._cg
.add_line(call
)
550 def _generate_serialize_int(self
, var
, ctx
, t
):
551 self
._generate
_bitfield
_write
(var
, ctx
, t
)
552 self
._generate
_incr
_pos
('{}->at'.format(ctx
), t
.size
)
554 def _generate_serialize_float(self
, var
, ctx
, t
):
555 ctype
= self
._get
_type
_ctype
(t
)
557 if ctype
== 'float' or ctype
== 'double':
558 gen_union_var
= False
561 if not self
._uf
_written
:
562 self
._uf
_written
= True
566 elif ctype
== 'double':
567 if not self
._ud
_written
:
568 self
._ud
_written
= True
574 # union for reading the bytes of the floating point number
576 self
._cg
.add_line('union {name} {name};'.format(name
=union_name
))
577 self
._cg
.add_empty_line()
579 self
._cg
.add_line('{}.f = {};'.format(union_name
, var
))
580 bf_var
= '{}.u'.format(union_name
)
582 bf_var
= '({}) {}'.format(ctype
, var
)
584 self
._generate
_bitfield
_write
(bf_var
, ctx
, t
)
585 self
._generate
_incr
_pos
('{}->at'.format(ctx
), t
.size
)
587 def _generate_serialize_enum(self
, var
, ctx
, t
):
588 self
._generate
_serialize
_type
(var
, ctx
, t
.value_type
)
590 def _generate_serialize_string(self
, var
, ctx
, t
):
591 tmpl
= '_write_cstring({}, {});'.format(ctx
, var
)
592 self
._cg
.add_lines(tmpl
)
594 def _generate_serialize_type(self
, var
, ctx
, t
):
595 self
._type
_to
_generate
_serialize
_func
[type(t
)](var
, ctx
, t
)
596 self
._sasa
.write_type(t
)
598 def _generate_func_serialize_event_from_entity(self
, prefix
, t
,
600 self
._cg
.add_line('{')
602 self
._cg
.add_cc_line('align structure')
604 self
._generate
_align
_type
('ctx->at', t
)
606 for field_name
, field_type
in t
.fields
.items():
607 src
= prefix
+ field_name
609 if spec_src
is not None:
610 if field_name
in spec_src
:
611 src
= spec_src
[field_name
]
613 self
._cg
.add_empty_line()
614 self
._generate
_field
_name
_cc
_line
(field_name
)
615 self
._generate
_align
_type
('ctx->at', field_type
)
616 self
._generate
_serialize
_type
(src
, 'ctx', field_type
)
619 self
._cg
.add_line('}')
620 self
._cg
.add_empty_line()
622 def _generate_func_serialize_event(self
, stream
, event
):
623 self
._reset
_per
_func
_state
()
624 self
._generate
_func
_serialize
_event
_proto
(stream
, event
)
625 tmpl
= templates
._FUNC
_SERIALIZE
_EVENT
_BODY
_BEGIN
626 self
._cg
.add_lines(tmpl
)
629 if stream
.event_header_type
is not None:
630 t
= stream
.event_header_type
631 exclude_list
= ['timestamp', 'id']
632 params
= self
._get
_call
_event
_param
_list
_from
_struct
(t
, _PREFIX_SEH
,
634 tmpl
= '_serialize_stream_event_header_{sname}(ctx, {evid}{params});'
635 self
._cg
.add_cc_line('stream event header')
636 self
._cg
.add_line(tmpl
.format(sname
=stream
.name
, evid
=event
.id,
638 self
._cg
.add_empty_line()
640 if stream
.event_context_type
is not None:
641 t
= stream
.event_context_type
642 params
= self
._get
_call
_event
_param
_list
_from
_struct
(t
, _PREFIX_SEC
,
644 tmpl
= '_serialize_stream_event_context_{sname}(ctx{params});'
645 self
._cg
.add_cc_line('stream event context')
646 self
._cg
.add_line(tmpl
.format(sname
=stream
.name
, params
=params
))
647 self
._cg
.add_empty_line()
649 if event
.context_type
is not None:
650 self
._cg
.add_cc_line('event context')
651 self
._generate
_func
_serialize
_event
_from
_entity
(_PREFIX_EC
,
654 if event
.payload_type
is not None:
655 self
._cg
.add_cc_line('event payload')
656 self
._generate
_func
_serialize
_event
_from
_entity
(_PREFIX_EP
,
660 tmpl
= templates
._FUNC
_SERIALIZE
_EVENT
_BODY
_END
661 self
._cg
.add_lines(tmpl
)
663 def _generate_func_serialize_stream_event_header_proto(self
, stream
):
664 tmpl
= templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_HEADER
_PROTO
_BEGIN
665 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
,
668 if stream
.event_header_type
is not None:
673 self
._generate
_proto
_params
(stream
.event_header_type
,
674 _PREFIX_SEH
, exclude_list
)
676 tmpl
= templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_HEADER
_PROTO
_END
677 self
._cg
.add_lines(tmpl
)
679 def _generate_func_serialize_stream_event_context_proto(self
, stream
):
680 tmpl
= templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_CONTEXT
_PROTO
_BEGIN
681 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
,
684 if stream
.event_context_type
is not None:
685 self
._generate
_proto
_params
(stream
.event_context_type
,
688 tmpl
= templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_CONTEXT
_PROTO
_END
689 self
._cg
.add_lines(tmpl
)
691 def _generate_func_serialize_stream_event_header(self
, stream
):
692 self
._reset
_per
_func
_state
()
693 self
._generate
_func
_serialize
_stream
_event
_header
_proto
(stream
)
694 tmpl
= templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_HEADER
_BODY
_BEGIN
695 self
._cg
.add_lines(tmpl
)
698 if stream
.event_header_type
is not None:
699 if 'timestamp' in stream
.event_header_type
.fields
:
700 timestamp
= stream
.event_header_type
.fields
['timestamp']
701 ts_ctype
= self
._get
_int
_ctype
(timestamp
)
702 clock
= timestamp
.property_mappings
[0].object
703 clock_name
= clock
.name
704 clock_ctype
= clock
.return_ctype
705 tmpl
= '{} ts = ctx->cbs.{}_clock_get_value(ctx->data);'
706 self
._cg
.add_line(tmpl
.format(clock_ctype
, clock_name
))
708 self
._cg
.add_empty_line()
709 func
= self
._generate
_func
_serialize
_event
_from
_entity
711 if stream
.event_header_type
is not None:
714 if 'id' in stream
.event_header_type
.fields
:
715 id_t
= stream
.event_header_type
.fields
['id']
716 id_t_ctype
= self
._get
_int
_ctype
(id_t
)
717 spec_src
['id'] = '({}) event_id'.format(id_t_ctype
)
719 if 'timestamp' in stream
.event_header_type
.fields
:
720 spec_src
['timestamp'] = '({}) ts'.format(ts_ctype
)
722 func(_PREFIX_SEH
, stream
.event_header_type
, spec_src
)
725 tmpl
= templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_HEADER
_BODY
_END
726 self
._cg
.add_lines(tmpl
)
728 def _generate_func_serialize_stream_event_context(self
, stream
):
729 self
._reset
_per
_func
_state
()
730 self
._generate
_func
_serialize
_stream
_event
_context
_proto
(stream
)
731 tmpl
= templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_CONTEXT
_BODY
_BEGIN
732 self
._cg
.add_lines(tmpl
)
734 func
= self
._generate
_func
_serialize
_event
_from
_entity
736 if stream
.event_context_type
is not None:
737 func(_PREFIX_SEC
, stream
.event_context_type
)
740 tmpl
= templates
._FUNC
_SERIALIZE
_STREAM
_EVENT
_CONTEXT
_BODY
_END
741 self
._cg
.add_lines(tmpl
)
743 def _generate_func_trace(self
, stream
, event
):
744 self
._reset
_per
_func
_state
()
745 self
._generate
_func
_trace
_proto
(stream
, event
)
746 params
= self
._get
_call
_event
_param
_list
(stream
, event
)
747 tmpl
= templates
._FUNC
_TRACE
_BODY
748 self
._cg
.add_lines(tmpl
.format(sname
=stream
.name
, evname
=event
.name
,
751 def _generate_func_init(self
):
752 self
._reset
_per
_func
_state
()
753 self
._generate
_func
_init
_proto
()
754 tmpl
= templates
._FUNC
_INIT
_BODY
755 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
))
757 def _generate_field_name_cc_line(self
, field_name
):
758 self
._cg
.add_cc_line('"{}" field'.format(field_name
))
760 def _save_byte_offset(self
, name
):
761 self
._saved
_byte
_offsets
[name
] = self
._sasa
.byte_offset
763 def _restore_byte_offset(self
, name
):
764 self
._sasa
.byte_offset
= self
._saved
_byte
_offsets
[name
]
766 def _reset_per_func_state(self
):
767 self
._uf
_written
= False
768 self
._ud
_written
= False
770 def _generate_func_open(self
, stream
):
771 def generate_save_offset(name
):
772 tmpl
= 'ctx->off_spc_{} = ctx->parent.at;'.format(name
)
773 self
._cg
.add_line(tmpl
)
774 self
._save
_byte
_offset
(name
)
776 self
._reset
_per
_func
_state
()
777 self
._generate
_func
_open
_proto
(stream
)
778 tmpl
= templates
._FUNC
_OPEN
_BODY
_BEGIN
779 self
._cg
.add_lines(tmpl
)
781 tph_type
= self
._cfg
.metadata
.trace
.packet_header_type
782 spc_type
= stream
.packet_context_type
784 if spc_type
is not None and 'timestamp_begin' in spc_type
.fields
:
785 field
= spc_type
.fields
['timestamp_begin']
786 tmpl
= '{} ts = ctx->parent.cbs.{}_clock_get_value(ctx->parent.data);'
787 clock
= field
.property_mappings
[0].object
788 clock_ctype
= clock
.return_ctype
789 clock_name
= clock
.name
790 self
._cg
.add_line(tmpl
.format(clock_ctype
, clock_name
))
791 self
._cg
.add_empty_line()
793 self
._cg
.add_cc_line('do not open a packet that is already open')
794 self
._cg
.add_line('if (ctx->parent.packet_is_open) {')
796 self
._cg
.add_line('return;')
798 self
._cg
.add_line('}')
799 self
._cg
.add_empty_line()
800 self
._cg
.add_line('ctx->parent.at = 0;')
802 if tph_type
is not None:
803 self
._cg
.add_empty_line()
804 self
._cg
.add_cc_line('trace packet header')
805 self
._cg
.add_line('{')
807 self
._cg
.add_cc_line('align structure')
809 self
._generate
_align
_type
('ctx->parent.at', tph_type
)
811 for field_name
, field_type
in tph_type
.fields
.items():
812 src
= _PREFIX_TPH
+ field_name
814 if field_name
== 'magic':
816 elif field_name
== 'stream_id':
817 stream_id_ctype
= self
._get
_int
_ctype
(field_type
)
818 src
= '({}) {}'.format(stream_id_ctype
, stream
.id)
819 elif field_name
== 'uuid':
820 self
._cg
.add_empty_line()
821 self
._generate
_field
_name
_cc
_line
(field_name
)
822 self
._cg
.add_line('{')
824 self
._cg
.add_line('static uint8_t uuid[] = {')
827 for b
in self
._cfg
.metadata
.trace
.uuid
.bytes
:
828 self
._cg
.add_line('{},'.format(b
))
831 self
._cg
.add_line('};')
832 self
._cg
.add_empty_line()
833 self
._generate
_align
('ctx->parent.at', 8)
834 line
= 'memcpy(&ctx->parent.buf[_BITS_TO_BYTES(ctx->parent.at)], uuid, 16);'
835 self
._cg
.add_line(line
)
836 self
._generate
_incr
_pos
_bytes
('ctx->parent.at', 16)
838 self
._cg
.add_line('}')
842 self
._cg
.add_empty_line()
843 self
._generate
_field
_name
_cc
_line
(field_name
)
844 self
._generate
_align
_type
('ctx->parent.at', field_type
)
845 self
._generate
_serialize
_type
(src
, '(&ctx->parent)', field_type
)
848 self
._cg
.add_lines('}')
850 if spc_type
is not None:
851 self
._cg
.add_empty_line()
852 self
._cg
.add_cc_line('stream packet context')
853 self
._cg
.add_line('{')
855 self
._cg
.add_cc_line('align structure')
857 self
._generate
_align
_type
('ctx->parent.at', spc_type
)
858 tmpl_off
= 'off_spc_{fname}'
860 for field_name
, field_type
in spc_type
.fields
.items():
861 src
= _PREFIX_SPC
+ field_name
863 self
._cg
.add_empty_line()
864 self
._generate
_field
_name
_cc
_line
(field_name
)
866 if field_name
== 'timestamp_begin':
867 ctype
= self
._get
_type
_ctype
(field_type
)
868 src
= '({}) ts'.format(ctype
)
869 elif field_name
in ['timestamp_end', 'content_size',
872 elif field_name
== 'packet_size':
873 ctype
= self
._get
_type
_ctype
(field_type
)
874 src
= '({}) ctx->parent.packet_size'.format(ctype
)
876 self
._generate
_align
_type
('ctx->parent.at', field_type
)
879 generate_save_offset(field_name
)
880 self
._generate
_incr
_pos
('ctx->parent.at', field_type
.size
)
881 self
._sasa
.write_type(field_type
)
883 self
._generate
_serialize
_type
(src
, '(&ctx->parent)',
887 self
._cg
.add_lines('}')
890 tmpl
= templates
._FUNC
_OPEN
_BODY
_END
891 self
._cg
.add_lines(tmpl
)
893 def _generate_func_close(self
, stream
):
894 def generate_goto_offset(name
):
895 tmpl
= 'ctx->parent.at = ctx->off_spc_{};'.format(name
)
896 self
._cg
.add_line(tmpl
)
898 self
._reset
_per
_func
_state
()
899 self
._generate
_func
_close
_proto
(stream
)
900 tmpl
= templates
._FUNC
_CLOSE
_BODY
_BEGIN
901 self
._cg
.add_lines(tmpl
)
903 spc_type
= stream
.packet_context_type
905 if spc_type
is not None:
906 if 'timestamp_end' in spc_type
.fields
:
907 tmpl
= '{} ts = ctx->parent.cbs.{}_clock_get_value(ctx->parent.data);'
908 field
= spc_type
.fields
['timestamp_end']
909 clock
= field
.property_mappings
[0].object
910 clock_ctype
= clock
.return_ctype
911 clock_name
= clock
.name
912 self
._cg
.add_line(tmpl
.format(clock_ctype
, clock_name
))
913 self
._cg
.add_empty_line()
915 self
._cg
.add_cc_line('do not close a packet that is not open')
916 self
._cg
.add_line('if (!ctx->parent.packet_is_open) {')
918 self
._cg
.add_line('return;')
920 self
._cg
.add_line('}')
921 self
._cg
.add_empty_line()
922 self
._cg
.add_cc_line('save content size')
923 self
._cg
.add_line('ctx->parent.content_size = ctx->parent.at;')
925 if spc_type
is not None:
926 field_name
= 'timestamp_end'
928 if field_name
in spc_type
.fields
:
929 t
= spc_type
.fields
[field_name
]
930 ctype
= self
._get
_type
_ctype
(t
)
931 src
= '({}) ts'.format(ctype
)
932 self
._cg
.add_empty_line()
933 self
._generate
_field
_name
_cc
_line
(field_name
)
934 generate_goto_offset(field_name
)
935 self
._restore
_byte
_offset
(field_name
)
936 self
._generate
_serialize
_type
(src
, '(&ctx->parent)', t
)
938 field_name
= 'content_size'
940 if 'content_size' in spc_type
.fields
:
941 t
= spc_type
.fields
[field_name
]
942 ctype
= self
._get
_type
_ctype
(t
)
943 src
= '({}) ctx->parent.content_size'.format(ctype
)
944 self
._cg
.add_empty_line()
945 self
._generate
_field
_name
_cc
_line
(field_name
)
946 generate_goto_offset(field_name
)
947 self
._restore
_byte
_offset
(field_name
)
948 self
._generate
_serialize
_type
(src
, '(&ctx->parent)', t
)
950 field_name
= 'events_discarded'
952 if field_name
in spc_type
.fields
:
953 t
= spc_type
.fields
[field_name
]
954 ctype
= self
._get
_type
_ctype
(t
)
955 src
= '({}) ctx->parent.events_discarded'.format(ctype
)
956 self
._cg
.add_empty_line()
957 self
._generate
_field
_name
_cc
_line
(field_name
)
958 generate_goto_offset(field_name
)
959 self
._restore
_byte
_offset
(field_name
)
960 self
._generate
_serialize
_type
(src
, '(&ctx->parent)', t
)
963 tmpl
= templates
._FUNC
_CLOSE
_BODY
_END
964 self
._cg
.add_lines(tmpl
)
967 def generate_c_src(self
):
969 dt
= datetime
.datetime
.now().isoformat()
970 header_filename
= self
.get_header_filename()
971 tmpl
= templates
._C
_SRC
972 self
._cg
.add_lines(tmpl
.format(prefix
=self
._cfg
.prefix
,
973 header_filename
=header_filename
,
974 version
=barectf
.__version
__, date
=dt
))
975 self
._cg
.add_empty_line()
977 # initialization function
978 self
._generate
_func
_init
()
979 self
._cg
.add_empty_line()
981 for stream
in self
._cfg
.metadata
.streams
.values():
982 self
._generate
_func
_open
(stream
)
983 self
._cg
.add_empty_line()
984 self
._generate
_func
_close
(stream
)
985 self
._cg
.add_empty_line()
987 if stream
.event_header_type
is not None:
988 self
._generate
_func
_serialize
_stream
_event
_header
(stream
)
989 self
._cg
.add_empty_line()
991 if stream
.event_context_type
is not None:
992 self
._generate
_func
_serialize
_stream
_event
_context
(stream
)
993 self
._cg
.add_empty_line()
995 for ev
in stream
.events
.values():
996 self
._generate
_func
_get
_event
_size
(stream
, ev
)
997 self
._cg
.add_empty_line()
998 self
._generate
_func
_serialize
_event
(stream
, ev
)
999 self
._cg
.add_empty_line()
1000 self
._generate
_func
_trace
(stream
, ev
)
1001 self
._cg
.add_empty_line()
1004 return self
._cg
.code
1006 def get_header_filename(self
):
1007 return '{}.h'.format(self
._cfg
.prefix
.rstrip('_'))
1009 def get_bitfield_header_filename(self
):
1010 return '{}-bitfield.h'.format(self
._cfg
.prefix
.rstrip('_'))