config_parse.py: replace `'...'.format()` with f-strings
[deliverable/barectf.git] / barectf / gen.py
1 # The MIT License (MIT)
2 #
3 # Copyright (c) 2014-2020 Philippe Proulx <pproulx@efficios.com>
4 #
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:
12 #
13 # The above copyright notice and this permission notice shall be
14 # included in all copies or substantial portions of the Software.
15 #
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.
23
24 from barectf import templates
25 from barectf import metadata
26 import barectf.codegen
27 import collections
28 import itertools
29 import argparse
30 import datetime
31 import barectf
32 import copy
33 import sys
34 import os
35 import re
36
37
38 def _align(v, align):
39 return (v + (align - 1)) & -align
40
41
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
46 self._type = type
47 self._names = copy.deepcopy(names)
48
49 @property
50 def offset_in_byte(self):
51 return self._offset_in_byte
52
53 @property
54 def type(self):
55 return self._type
56
57 @property
58 def names(self):
59 return self._names
60
61
62 class _AlignSerializationAction(_SerializationAction):
63 def __init__(self, offset_in_byte, type, names, value):
64 super().__init__(offset_in_byte, type, names)
65 self._value = value
66
67 @property
68 def value(self):
69 return self._value
70
71
72 class _SerializeSerializationAction(_SerializationAction):
73 def __init__(self, offset_in_byte, type, names):
74 super().__init__(offset_in_byte, type, names)
75
76
77 class _SerializationActions:
78 def __init__(self):
79 self.reset()
80
81 def reset(self):
82 self._last_alignment = None
83 self._last_bit_array_size = None
84 self._actions = []
85 self._names = []
86 self._offset_in_byte = 0
87
88 def append_root_scope_type(self, t, name):
89 if t is None:
90 return
91
92 assert(type(t) is metadata.Struct)
93 self._names = [name]
94 self._append_type(t)
95
96 @property
97 def actions(self):
98 return self._actions
99
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)
105
106 def _must_align(self, align_req):
107 return self._last_alignment != align_req or self._last_bit_array_size % align_req != 0
108
109 def _append_type(self, t):
110 assert(type(t) in (metadata.Struct, metadata.String, metadata.Integer,
111 metadata.FloatingPoint, metadata.Enum,
112 metadata.Array))
113
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
125
126 if type(t) is metadata.Struct:
127 self._last_bit_array_size = t.align
128 else:
129 self._last_bit_array_size = t.size
130
131 self._try_append_align_action(t.align, do_align, t)
132
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)
137 del self._names[-1]
138 else:
139 self._append_serialize_action(t, t.size)
140
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
144
145 if do_align and alignment > 1:
146 self._actions.append(_AlignSerializationAction(offset_in_byte,
147 t, self._names,
148 alignment))
149
150 def _append_serialize_action(self, t, size=None):
151 assert(type(t) in (metadata.Integer, metadata.FloatingPoint,
152 metadata.Enum, metadata.String,
153 metadata.Array))
154
155 offset_in_byte = self._offset_in_byte
156
157 if t.size is not None:
158 self._offset_in_byte += t.size
159 self._offset_in_byte %= 8
160
161 self._actions.append(_SerializeSerializationAction(offset_in_byte,
162 t, self._names))
163
164
165 _PREFIX_TPH = 'tph_'
166 _PREFIX_SPC = 'spc_'
167 _PREFIX_SEH = 'seh_'
168 _PREFIX_SEC = 'sec_'
169 _PREFIX_EC = 'ec_'
170 _PREFIX_EP = 'ep_'
171 _PREFIX_TO_NAME = {
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',
178 }
179
180
181 class CCodeGenerator:
182 def __init__(self, cfg):
183 self._cfg = 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,
190 }
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,
196 }
197 self._saved_serialization_actions = {}
198
199 def _get_stream_clock(self, stream):
200 field = None
201
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']
205
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']
209
210 if field is None and 'timestamp_end' in stream.packet_context_type.fields:
211 field = stream.packet_context_type['timestamp_end']
212
213 if field is None:
214 return
215
216 if field.property_mappings:
217 return field.property_mappings[0].object
218
219 def _generate_ctx_parent(self):
220 tmpl = templates._CTX_PARENT
221 self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix))
222
223 def _generate_ctx(self, stream):
224 tmpl = templates._CTX_BEGIN
225 self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix,
226 sname=stream.name))
227 tmpl = 'uint32_t off_tph_{fname};'
228 self._cg.indent()
229 trace_packet_header_type = self._cfg.metadata.trace.packet_header_type
230
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))
234
235 tmpl = 'uint32_t off_spc_{fname};'
236
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))
240
241 clock = self._get_stream_clock(stream)
242
243 if clock is not None:
244 line = '{} cur_last_event_ts;'.format(clock.return_ctype)
245 self._cg.add_line(line)
246
247 self._cg.unindent()
248 tmpl = templates._CTX_END
249 self._cg.add_lines(tmpl)
250
251 def _generate_ctxs(self):
252 for stream in self._cfg.metadata.streams.values():
253 self._generate_ctx(stream)
254
255 def _generate_clock_cb(self, clock):
256 tmpl = templates._CLOCK_CB
257 self._cg.add_lines(tmpl.format(return_ctype=clock.return_ctype,
258 cname=clock.name))
259
260 def _generate_clock_cbs(self):
261 for clock in self._cfg.metadata.clocks.values():
262 self._generate_clock_cb(clock)
263
264 def _generate_platform_callbacks(self):
265 tmpl = templates._PLATFORM_CALLBACKS_BEGIN
266 self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix))
267 self._cg.indent()
268 self._generate_clock_cbs()
269 self._cg.unindent()
270 tmpl = templates._PLATFORM_CALLBACKS_END
271 self._cg.add_lines(tmpl)
272
273 def generate_bitfield_header(self):
274 self._cg.reset()
275 tmpl = templates._BITFIELD
276 tmpl = tmpl.replace('$prefix$', self._cfg.prefix)
277 tmpl = tmpl.replace('$PREFIX$', self._cfg.prefix.upper())
278
279 if self._cfg.metadata.trace.byte_order == metadata.ByteOrder.BE:
280 endian_def = 'BIG_ENDIAN'
281 else:
282 endian_def = 'LITTLE_ENDIAN'
283
284 tmpl = tmpl.replace('$ENDIAN_DEF$', endian_def)
285 self._cg.add_lines(tmpl)
286
287 return self._cg.code
288
289 def _generate_func_init_proto(self):
290 tmpl = templates._FUNC_INIT_PROTO
291 self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix))
292
293 def _get_int_ctype(self, t):
294 signed = 'u' if not t.signed else ''
295
296 if t.size <= 8:
297 sz = '8'
298 elif t.size <= 16:
299 sz = '16'
300 elif t.size <= 32:
301 sz = '32'
302 elif t.size == 64:
303 sz = '64'
304
305 return '{}int{}_t'.format(signed, sz)
306
307 def _get_float_ctype(self, t):
308 if t.exp_size == 8 and t.mant_size == 24 and t.align == 32:
309 ctype = 'float'
310 elif t.exp_size == 11 and t.mant_size == 53 and t.align == 64:
311 ctype = 'double'
312 else:
313 ctype = 'uint64_t'
314
315 return ctype
316
317 def _get_enum_ctype(self, t):
318 return self._get_int_ctype(t.value_type)
319
320 def _get_string_ctype(self, t):
321 return 'const char *'
322
323 def _get_type_ctype(self, t):
324 return self._type_to_get_ctype_func[type(t)](t)
325
326 def _generate_type_ctype(self, t):
327 ctype = self._get_type_ctype(t)
328 self._cg.append_to_last_line(ctype)
329
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)
334
335 def _generate_proto_params(self, t, name_prefix, exclude_list):
336 self._cg.indent()
337
338 for field_name, field_type in t.fields.items():
339 if field_name in exclude_list:
340 continue
341
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)
346
347 self._cg.unindent()
348
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,
352 sname=stream.name))
353 trace_packet_header_type = self._cfg.metadata.trace.packet_header_type
354
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,
358 exclude_list)
359
360 if stream.packet_context_type is not None:
361 exclude_list = [
362 'timestamp_begin',
363 'timestamp_end',
364 'packet_size',
365 'content_size',
366 'events_discarded',
367 ]
368 self._generate_proto_params(stream.packet_context_type,
369 _PREFIX_SPC, exclude_list)
370
371 tmpl = templates._FUNC_OPEN_PROTO_END
372 self._cg.add_lines(tmpl)
373
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,
377 sname=stream.name))
378
379 def _generate_func_trace_proto_params(self, stream, event):
380 if stream.event_header_type is not None:
381 exclude_list = [
382 'id',
383 'timestamp',
384 ]
385 self._generate_proto_params(stream.event_header_type,
386 _PREFIX_SEH, exclude_list)
387
388 if stream.event_context_type is not None:
389 self._generate_proto_params(stream.event_context_type,
390 _PREFIX_SEC, [])
391
392 if event.context_type is not None:
393 self._generate_proto_params(event.context_type,
394 _PREFIX_EC, [])
395
396 if event.payload_type is not None:
397 self._generate_proto_params(event.payload_type,
398 _PREFIX_EP, [])
399
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)
407
408 def _punctuate_proto(self):
409 self._cg.append_to_last_line(';')
410
411 def generate_header(self):
412 self._cg.reset()
413 dt = datetime.datetime.now().isoformat()
414 bh_filename = self.get_bitfield_header_filename()
415 prefix_def = ''
416 default_stream_def = ''
417
418 if self._cfg.options.gen_prefix_def:
419 prefix_def = '#define _BARECTF_PREFIX {}'.format(self._cfg.prefix)
420
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)
423
424 default_stream_trace_defs = ''
425 default_stream_name = self._cfg.metadata.default_stream_name
426
427 if default_stream_name is not None:
428 default_stream = self._cfg.metadata.streams[default_stream_name]
429 lines = []
430
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,
435 evname=ev_name)
436 lines.append(define)
437
438 default_stream_trace_defs = '\n'.join(lines)
439
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()
449
450 # platform callbacks structure
451 self._generate_platform_callbacks()
452 self._cg.add_empty_line()
453
454 # context parent
455 self._generate_ctx_parent()
456 self._cg.add_empty_line()
457
458 # stream contexts
459 self._generate_ctxs()
460 self._cg.add_empty_line()
461
462 # initialization function prototype
463 self._generate_func_init_proto()
464 self._punctuate_proto()
465 self._cg.add_empty_line()
466
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()
474
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()
479
480 tmpl = templates._HEADER_END
481 self._cg.add_lines(tmpl.format(ucprefix=self._cfg.prefix.upper()))
482
483 return self._cg.code
484
485 def _get_call_event_param_list_from_struct(self, t, prefix, exclude_list):
486 lst = ''
487
488 for field_name in t.fields:
489 if field_name in exclude_list:
490 continue
491
492 lst += ', {}{}'.format(prefix, field_name)
493
494 return lst
495
496 def _get_call_event_param_list(self, stream, event):
497 lst = ''
498 gcp_func = self._get_call_event_param_list_from_struct
499
500 if stream.event_header_type is not None:
501 exclude_list = [
502 'id',
503 'timestamp',
504 ]
505 lst += gcp_func(stream.event_header_type, _PREFIX_SEH, exclude_list)
506
507 if stream.event_context_type is not None:
508 lst += gcp_func(stream.event_context_type, _PREFIX_SEC, [])
509
510 if event.context_type is not None:
511 lst += gcp_func(event.context_type, _PREFIX_EC, [])
512
513 if event.payload_type is not None:
514 lst += gcp_func(event.payload_type, _PREFIX_EP, [])
515
516 return lst
517
518 def _generate_align(self, at, align):
519 self._cg.add_line('_ALIGN({}, {});'.format(at, align))
520
521 def _generate_align_type(self, at, t):
522 if t.align == 1:
523 return
524
525 self._generate_align(at, t.align)
526
527 def _generate_incr_pos(self, var, value):
528 self._cg.add_line('{} += {};'.format(var, value))
529
530 def _generate_incr_pos_bytes(self, var, value):
531 self._generate_incr_pos(var, '_BYTES_TO_BITS({})'.format(value))
532
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)
540
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()
547 self._cg.indent()
548 ser_actions = _SerializationActions()
549 ser_actions.append_root_scope_type(stream.event_header_type,
550 _PREFIX_SEH)
551 ser_actions.append_root_scope_type(stream.event_context_type,
552 _PREFIX_SEC)
553 ser_actions.append_root_scope_type(event.context_type, _PREFIX_EC)
554 ser_actions.append_root_scope_type(event.payload_type, _PREFIX_EP)
555
556 for action in ser_actions.actions:
557 if type(action) is _AlignSerializationAction:
558 if action.names:
559 if len(action.names) == 1:
560 line = 'align {} structure'.format(_PREFIX_TO_NAME[action.names[0]])
561 else:
562 fmt = 'align field `{}` ({})'
563 line = fmt.format(action.names[-1],
564 _PREFIX_TO_NAME[action.names[0]])
565
566 self._cg.add_cc_line(line)
567
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)
575
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))
580 else:
581 self._generate_incr_pos('at', action.type.size)
582
583 self._cg.add_empty_line()
584
585 self._cg.unindent()
586 tmpl = templates._FUNC_GET_EVENT_SIZE_BODY_END
587 self._cg.add_lines(tmpl)
588
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)
596
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)
606
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)
611
612 def _generate_serialize_float(self, var, ctx, action):
613 ctype = self._get_type_ctype(action.type)
614 flt_dbl = False
615
616 if ctype == 'float' or ctype == 'double':
617 flt_dbl = True
618
619 if ctype == 'float':
620 union_name = 'f2u'
621 int_ctype = 'uint32_t'
622 elif ctype == 'double':
623 union_name = 'd2u'
624 int_ctype = 'uint64_t'
625
626 # union for reading the bytes of the floating point number
627 self._cg.add_empty_line()
628 self._cg.add_line('{')
629 self._cg.indent()
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)
634 else:
635 bf_var = '({}) {}'.format(ctype, var)
636 int_ctype = ctype
637
638 self._generate_bitfield_write(int_ctype, bf_var, ctx, action)
639
640 if flt_dbl:
641 self._cg.unindent()
642 self._cg.add_line('}')
643 self._cg.add_empty_line()
644
645 self._generate_incr_pos('{}->at'.format(ctx), action.type.size)
646
647 def _generate_serialize_enum(self, var, ctx, action):
648 sub_action = _SerializeSerializationAction(action.offset_in_byte,
649 action.type.value_type,
650 action.names)
651 self._generate_serialize_from_action(var, ctx, sub_action)
652
653 def _generate_serialize_string(self, var, ctx, action):
654 tmpl = '_write_cstring({}, {});'.format(ctx, var)
655 self._cg.add_lines(tmpl)
656
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)
660
661 def _generate_serialize_statements_from_actions(self, prefix, action_iter,
662 spec_src=None):
663 for action in action_iter:
664 if type(action) is _AlignSerializationAction:
665 if action.names:
666 if len(action.names) == 1:
667 line = 'align {} structure'.format(_PREFIX_TO_NAME[action.names[0]])
668 else:
669 fmt = 'align field `{}` ({})'
670 line = fmt.format(action.names[-1],
671 _PREFIX_TO_NAME[action.names[0]])
672
673 self._cg.add_cc_line(line)
674
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
685
686 if spec_src is not None and field_name in spec_src:
687 src = spec_src[field_name]
688
689 self._generate_serialize_from_action(src, 'ctx', action)
690 self._cg.add_empty_line()
691
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)
697 self._cg.indent()
698 self._cg.add_empty_line()
699
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,
704 exclude_list)
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,
708 params=params))
709 self._cg.add_empty_line()
710
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,
714 [])
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()
719
720 if event.context_type is not None or event.payload_type is not None:
721 ser_actions = copy.deepcopy(orig_ser_actions)
722
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,
729 ser_action_iter)
730
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,
737 ser_action_iter)
738
739 self._cg.unindent()
740 tmpl = templates._FUNC_SERIALIZE_EVENT_BODY_END
741 self._cg.add_lines(tmpl)
742
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,
747 sname=stream.name))
748
749 if stream.event_header_type is not None:
750 exclude_list = [
751 'id',
752 'timestamp',
753 ]
754 self._generate_proto_params(stream.event_header_type,
755 _PREFIX_SEH, exclude_list)
756
757 tmpl = templates._FUNC_SERIALIZE_STREAM_EVENT_HEADER_PROTO_END
758 self._cg.add_lines(tmpl)
759
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,
763 sname=stream.name))
764
765 if stream.event_context_type is not None:
766 self._generate_proto_params(stream.event_context_type,
767 _PREFIX_SEC, [])
768
769 tmpl = templates._FUNC_SERIALIZE_STREAM_EVENT_CONTEXT_PROTO_END
770 self._cg.add_lines(tmpl)
771
772 def _generate_func_serialize_stream_event_header(self, stream,
773 ser_action_iter):
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)
778 self._cg.indent()
779 clock = self._get_stream_clock(stream)
780
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,
784 sname=stream.name)
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)
789
790 self._cg.add_empty_line()
791
792 if stream.event_header_type is not None:
793 spec_src = {}
794
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)
799
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)
804
805 self._generate_serialize_statements_from_actions(_PREFIX_SEH,
806 ser_action_iter,
807 spec_src)
808
809 self._cg.unindent()
810 tmpl = templates._FUNC_SERIALIZE_STREAM_EVENT_HEADER_BODY_END
811 self._cg.add_lines(tmpl)
812
813 def _generate_func_serialize_stream_event_context(self, stream,
814 ser_action_iter):
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)
819 self._cg.indent()
820
821 if stream.event_context_type is not None:
822 self._generate_serialize_statements_from_actions(_PREFIX_SEC,
823 ser_action_iter)
824
825 self._cg.unindent()
826 tmpl = templates._FUNC_SERIALIZE_STREAM_EVENT_CONTEXT_BODY_END
827 self._cg.add_lines(tmpl)
828
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)
833
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)
837 else:
838 save_ts_line = '/* (no clock) */'
839
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))
843
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))
848
849 def _generate_field_name_cc_line(self, field_name):
850 self._cg.add_cc_line('`{}` field'.format(field_name))
851
852 def _save_serialization_action(self, name, action):
853 self._saved_serialization_actions[name] = action
854
855 def _get_open_close_ts_line(self, stream):
856 clock = self._get_stream_clock(stream)
857
858 if clock is None:
859 return ''
860
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)
863 return line
864
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)
870
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)
877 self._cg.indent()
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) {')
880 self._cg.indent()
881 self._cg.add_line('ctx->parent.in_tracing_section = saved_in_tracing_section;')
882 self._cg.add_line('return;')
883 self._cg.unindent()
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()
889
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('{')
894 self._cg.indent()
895 ser_actions.append_root_scope_type(tph_type, _PREFIX_TPH)
896
897 for action in ser_actions.actions:
898 if type(action) is _AlignSerializationAction:
899 if action.names:
900 if len(action.names) == 1:
901 line = 'align trace packet header structure'
902 else:
903 line = 'align field `{}`'.format(action.names[-1])
904
905 self._cg.add_cc_line(line)
906
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
916
917 if field_name == 'magic':
918 src = '0xc1fc1fc1UL'
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('{')
924 self._cg.indent()
925 self._cg.add_line('static uint8_t uuid[] = {')
926 self._cg.indent()
927
928 for b in self._cfg.metadata.trace.uuid.bytes:
929 self._cg.add_line('{},'.format(b))
930
931 self._cg.unindent()
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)
938 self._cg.unindent()
939 self._cg.add_line('}')
940 self._cg.add_empty_line()
941 continue
942
943 self._generate_serialize_from_action(src, '(&ctx->parent)', action)
944 self._cg.add_empty_line()
945
946 self._cg.unindent()
947 self._cg.add_lines('}')
948
949 spc_action_index = len(ser_actions.actions)
950
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('{')
955 self._cg.indent()
956 ser_actions.append_root_scope_type(spc_type, _PREFIX_SPC)
957 tmpl_off = 'off_spc_{fname}'
958
959 for action in itertools.islice(ser_actions.actions, spc_action_index, None):
960 if type(action) is _AlignSerializationAction:
961 if action.names:
962 if len(action.names) == 1:
963 line = 'align stream packet context structure'
964 else:
965 line = 'align field `{}`'.format(action.names[-1])
966
967 self._cg.add_cc_line(line)
968
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
978 skip_int = False
979
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',
984 'events_discarded']:
985 skip_int = True
986 elif field_name == 'packet_size':
987 ctype = self._get_type_ctype(action.type)
988 src = '({}) ctx->parent.packet_size'.format(ctype)
989
990 if skip_int:
991 generate_save_offset(field_name, action)
992 self._generate_incr_pos('ctx->parent.at',
993 action.type.size)
994 else:
995 self._generate_serialize_from_action(src, '(&ctx->parent)',
996 action)
997
998 self._cg.add_empty_line()
999
1000 self._cg.unindent()
1001 self._cg.add_lines('}')
1002
1003 self._cg.unindent()
1004 tmpl = templates._FUNC_OPEN_BODY_END
1005 self._cg.add_lines(tmpl)
1006
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)
1011
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)
1018 self._cg.indent()
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) {')
1021 self._cg.indent()
1022 self._cg.add_line('ctx->parent.in_tracing_section = saved_in_tracing_section;')
1023 self._cg.add_line('return;')
1024 self._cg.unindent()
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;')
1029
1030 if spc_type is not None:
1031 field_name = 'timestamp_end'
1032
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)
1042
1043 field_name = 'content_size'
1044
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)
1054
1055 field_name = 'events_discarded'
1056
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)
1066
1067 self._cg.unindent()
1068 tmpl = templates._FUNC_CLOSE_BODY_END
1069 self._cg.add_lines(tmpl)
1070
1071 def generate_c_src(self):
1072 self._cg.reset()
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()
1080
1081 # initialization function
1082 self._generate_func_init()
1083 self._cg.add_empty_line()
1084
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()
1091
1092 if stream.event_header_type is not None:
1093 ser_actions.append_root_scope_type(stream.event_header_type,
1094 _PREFIX_SEH)
1095 self._generate_func_serialize_stream_event_header(stream,
1096 iter(ser_actions.actions))
1097 self._cg.add_empty_line()
1098
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,
1102 _PREFIX_SEC)
1103 ser_action_iter = itertools.islice(ser_actions.actions,
1104 ser_action_index, None)
1105 self._generate_func_serialize_stream_event_context(stream,
1106 ser_action_iter)
1107 self._cg.add_empty_line()
1108
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()
1116
1117 return self._cg.code
1118
1119 def get_header_filename(self):
1120 return '{}.h'.format(self._cfg.prefix.rstrip('_'))
1121
1122 def get_bitfield_header_filename(self):
1123 return '{}-bitfield.h'.format(self._cfg.prefix.rstrip('_'))
This page took 0.055366 seconds and 4 git commands to generate.