fb413cb9318d602177cdd013902c5c5b25335484
[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 import barectf.tsdl182gen as barectf_tsdl182gen
25 import barectf.templates as barectf_templates
26 import barectf.template as barectf_template
27 import barectf.codegen as barectf_codegen
28 import barectf.config as barectf_config
29 import barectf.version as barectf_version
30 import itertools
31 import datetime
32 import copy
33
34
35 class _GeneratedFile:
36 def __init__(self, name, contents):
37 self._name = name
38 self._contents = contents
39
40 @property
41 def name(self):
42 return self._name
43
44 @property
45 def contents(self):
46 return self._contents
47
48
49 class CodeGenerator:
50 def __init__(self, configuration):
51 self._config = configuration
52 self._file_name_prefix = configuration.options.code_generation_options.file_name_prefix
53 self._ccode_gen = _CCodeGenerator(configuration)
54 self._c_headers = None
55 self._c_sources = None
56 self._metadata_stream = None
57
58 @property
59 def _barectf_header_name(self):
60 return f'{self._file_name_prefix}.h'
61
62 @property
63 def _bitfield_header_name(self):
64 return f'{self._file_name_prefix}-bitfield.h'
65
66 def generate_c_headers(self):
67 if self._c_headers is None:
68 self._c_headers = [
69 _GeneratedFile(self._barectf_header_name, self._ccode_gen.generate_header()),
70 _GeneratedFile(self._bitfield_header_name, self._ccode_gen.generate_bitfield_header()),
71 ]
72
73 return self._c_headers
74
75 def generate_c_sources(self):
76 if self._c_sources is None:
77 bitfield_header_name = f'{self._file_name_prefix}-bitfield.h'
78 self._c_sources = [
79 _GeneratedFile(f'{self._file_name_prefix}.c',
80 self._ccode_gen.generate_c_src(self._barectf_header_name,
81 self._bitfield_header_name))
82 ]
83
84 return self._c_sources
85
86 def generate_metadata_stream(self):
87 if self._metadata_stream is None:
88 self._metadata_stream = _GeneratedFile('metadata',
89 barectf_tsdl182gen._from_config(self._config))
90
91 return self._metadata_stream
92
93
94 def _align(v, align):
95 return (v + (align - 1)) & -align
96
97
98 class _SerializationAction:
99 def __init__(self, offset_in_byte, ft, names):
100 assert(offset_in_byte >= 0 and offset_in_byte < 8)
101 self._offset_in_byte = offset_in_byte
102 self._ft = ft
103 self._names = copy.deepcopy(names)
104
105 @property
106 def offset_in_byte(self):
107 return self._offset_in_byte
108
109 @property
110 def ft(self):
111 return self._ft
112
113 @property
114 def names(self):
115 return self._names
116
117
118 class _AlignSerializationAction(_SerializationAction):
119 def __init__(self, offset_in_byte, ft, names, value):
120 super().__init__(offset_in_byte, ft, names)
121 self._value = value
122
123 @property
124 def value(self):
125 return self._value
126
127
128 class _SerializeSerializationAction(_SerializationAction):
129 pass
130
131
132 class _SerializationActions:
133 def __init__(self):
134 self.reset()
135
136 def reset(self):
137 self._last_alignment = None
138 self._last_bit_array_size = None
139 self._actions = []
140 self._names = []
141 self._offset_in_byte = 0
142
143 def append_root_scope_ft(self, ft, name):
144 if ft is None:
145 return
146
147 assert(type(ft) is barectf_config.StructureFieldType)
148 self._names = [name]
149 self._append_ft(ft)
150
151 @property
152 def actions(self):
153 return self._actions
154
155 def align(self, alignment):
156 do_align = self._must_align(alignment)
157 self._last_alignment = alignment
158 self._last_bit_array_size = alignment
159 self._try_append_align_action(alignment, do_align)
160
161 def _must_align(self, align_req):
162 return self._last_alignment != align_req or self._last_bit_array_size % align_req != 0
163
164 def _append_ft(self, ft):
165 if isinstance(ft, (barectf_config.StringFieldType, barectf_config._ArrayFieldType)):
166 assert(type(ft) is barectf_config.StringFieldType or self._names[-1] == 'uuid')
167 do_align = self._must_align(8)
168 self._last_alignment = 8
169 self._last_bit_array_size = 8
170 self._try_append_align_action(8, do_align, ft)
171 self._append_serialize_action(ft)
172 else:
173 do_align = self._must_align(ft.alignment)
174 self._last_alignment = ft.alignment
175
176 if type(ft) is barectf_config.StructureFieldType:
177 self._last_bit_array_size = ft.alignment
178 else:
179 self._last_bit_array_size = ft.size
180
181 self._try_append_align_action(ft.alignment, do_align, ft)
182
183 if type(ft) is barectf_config.StructureFieldType:
184 for member_name, member in ft.members.items():
185 self._names.append(member_name)
186 self._append_ft(member.field_type)
187 del self._names[-1]
188 else:
189 self._append_serialize_action(ft)
190
191 def _try_append_align_action(self, alignment, do_align, ft=None):
192 offset_in_byte = self._offset_in_byte
193 self._offset_in_byte = _align(self._offset_in_byte, alignment) % 8
194
195 if do_align and alignment > 1:
196 self._actions.append(_AlignSerializationAction(offset_in_byte, ft, self._names,
197 alignment))
198
199 def _append_serialize_action(self, ft):
200 assert(type(ft) is not barectf_config.StructureFieldType)
201 offset_in_byte = self._offset_in_byte
202
203 if isinstance(ft, barectf_config._BitArrayFieldType):
204 self._offset_in_byte += ft.size
205 self._offset_in_byte %= 8
206
207 self._actions.append(_SerializeSerializationAction(offset_in_byte, ft, self._names))
208
209
210 _PREFIX_TPH = 'tph_'
211 _PREFIX_SPC = 'spc_'
212 _PREFIX_SEH = 'seh_'
213 _PREFIX_SEC = 'sec_'
214 _PREFIX_EC = 'ec_'
215 _PREFIX_EP = 'ep_'
216 _PREFIX_TO_NAME = {
217 _PREFIX_TPH: 'trace packet header',
218 _PREFIX_SPC: 'stream packet context',
219 _PREFIX_SEH: 'stream event header',
220 _PREFIX_SEC: 'stream event context',
221 _PREFIX_EC: 'event context',
222 _PREFIX_EP: 'event payload',
223 }
224
225
226 class _CCodeGenerator:
227 def __init__(self, cfg):
228 self._cfg = cfg
229 code_gen_opts = cfg.options.code_generation_options
230 self._iden_prefix = code_gen_opts.identifier_prefix
231 self._cg = barectf_codegen._CodeGenerator('\t')
232 self._saved_serialization_actions = {}
233
234 def _create_template(self, name: str) -> barectf_template._Template:
235 return barectf_template._Template(name, cfg=self._cfg)
236
237 def _create_file_template(self, name: str) -> barectf_template._Template:
238 return barectf_template._Template(name, True, self._cfg)
239
240 @property
241 def _trace_type(self):
242 return self._cfg.trace.type
243
244 def _clk_type_c_type(self, clk_type):
245 return self._cfg.options.code_generation_options.clock_type_c_types[clk_type]
246
247 def _generate_ctx_parent(self):
248 tmpl = barectf_templates._CTX_PARENT
249 self._cg.add_lines(tmpl.format(prefix=self._iden_prefix))
250
251 def _generate_ctx(self, stream_type):
252 tmpl = barectf_templates._CTX_BEGIN
253 self._cg.add_lines(tmpl.format(prefix=self._iden_prefix, sname=stream_type.name))
254 self._cg.indent()
255 pkt_header_ft = self._trace_type._pkt_header_ft
256
257 if pkt_header_ft is not None:
258 for member_name in pkt_header_ft.members:
259 self._cg.add_lines(f'uint32_t off_tph_{member_name};')
260
261 for member_name in stream_type._pkt_ctx_ft.members:
262 self._cg.add_lines(f'uint32_t off_spc_{member_name};')
263
264 if stream_type.default_clock_type is not None:
265 self._cg.add_line(f'{self._clk_type_c_type(stream_type.default_clock_type)} cur_last_event_ts;')
266
267 self._cg.unindent()
268 tmpl = barectf_templates._CTX_END
269 self._cg.add_lines(tmpl)
270
271 def _generate_ctxs(self):
272 for stream_type in self._trace_type.stream_types:
273 self._generate_ctx(stream_type)
274
275 def _generate_clock_cb(self, clk_type):
276 tmpl = barectf_templates._CLOCK_CB
277 self._cg.add_lines(tmpl.format(return_ctype=self._clk_type_c_type(clk_type),
278 cname=clk_type.name))
279
280 def _generate_clock_cbs(self):
281 clk_names = set()
282
283 for stream_type in self._trace_type.stream_types:
284 def_clk_type = stream_type.default_clock_type
285
286 if def_clk_type is not None and def_clk_type not in clk_names:
287 self._generate_clock_cb(def_clk_type)
288 clk_names.add(def_clk_type)
289
290 def _generate_platform_callbacks(self):
291 tmpl = barectf_templates._PLATFORM_CALLBACKS_BEGIN
292 self._cg.add_lines(tmpl.format(prefix=self._iden_prefix))
293 self._cg.indent()
294 self._generate_clock_cbs()
295 self._cg.unindent()
296 tmpl = barectf_templates._PLATFORM_CALLBACKS_END
297 self._cg.add_lines(tmpl)
298
299 def generate_bitfield_header(self):
300 return self._create_file_template('bitfield.h.j2').render()
301
302 def _generate_func_init_proto(self):
303 tmpl = barectf_templates._FUNC_INIT_PROTO
304 self._cg.add_lines(tmpl.format(prefix=self._iden_prefix))
305
306 def _get_ft_c_type(self, ft):
307 if isinstance(ft, barectf_config._IntegerFieldType):
308 sign_prefix = 'u' if isinstance(ft, barectf_config.UnsignedIntegerFieldType) else ''
309
310 if ft.size <= 8:
311 sz = 8
312 elif ft.size <= 16:
313 sz = 16
314 elif ft.size <= 32:
315 sz = 32
316 else:
317 assert ft.size == 64
318 sz = 64
319
320 return f'{sign_prefix}int{sz}_t'
321 elif type(ft) is barectf_config.RealFieldType:
322 if ft.size == 32 and ft.alignment == 32:
323 return 'float'
324 elif ft.size == 64 and ft.alignment == 64:
325 return 'double'
326 else:
327 return 'uint64_t'
328 else:
329 assert type(ft) is barectf_config.StringFieldType
330 return 'const char *'
331
332 def _generate_ft_c_type(self, ft):
333 c_type = self._get_ft_c_type(ft)
334 self._cg.append_to_last_line(c_type)
335
336 def _generate_proto_param(self, ft, name):
337 self._generate_ft_c_type(ft)
338 self._cg.append_to_last_line(' ')
339 self._cg.append_to_last_line(name)
340
341 def _generate_proto_params(self, ft, name_prefix, exclude_set=None):
342 if exclude_set is None:
343 exclude_set = set()
344
345 self._cg.indent()
346
347 for member_name, member in ft.members.items():
348 if member_name in exclude_set:
349 continue
350
351 self._cg.append_to_last_line(',')
352 self._cg.add_line('')
353 self._generate_proto_param(member.field_type, name_prefix + member_name)
354
355 self._cg.unindent()
356
357 def _generate_func_open_proto(self, stream_type):
358 tmpl = barectf_templates._FUNC_OPEN_PROTO_BEGIN
359 self._cg.add_lines(tmpl.format(prefix=self._iden_prefix, sname=stream_type.name))
360
361 if self._trace_type._pkt_header_ft is not None:
362 self._generate_proto_params(self._trace_type._pkt_header_ft, _PREFIX_TPH,
363 {'magic', 'stream_id', 'uuid'})
364
365 exclude_set = {
366 'timestamp_begin',
367 'timestamp_end',
368 'packet_size',
369 'content_size',
370 'events_discarded',
371 }
372 self._generate_proto_params(stream_type._pkt_ctx_ft, _PREFIX_SPC, exclude_set)
373 tmpl = barectf_templates._FUNC_OPEN_PROTO_END
374 self._cg.add_lines(tmpl)
375
376 def _generate_func_close_proto(self, stream_type):
377 tmpl = barectf_templates._FUNC_CLOSE_PROTO
378 self._cg.add_lines(tmpl.format(prefix=self._iden_prefix, sname=stream_type.name))
379
380 def _generate_func_trace_proto_params(self, stream_type, ev_type):
381 if stream_type._ev_header_ft is not None:
382 self._generate_proto_params(stream_type._ev_header_ft, _PREFIX_SEH, {'id', 'timestamp'})
383
384 if stream_type.event_common_context_field_type is not None:
385 self._generate_proto_params(stream_type.event_common_context_field_type, _PREFIX_SEC)
386
387 if ev_type.specific_context_field_type is not None:
388 self._generate_proto_params(ev_type.specific_context_field_type, _PREFIX_EC)
389
390 if ev_type.payload_field_type is not None:
391 self._generate_proto_params(ev_type.payload_field_type, _PREFIX_EP)
392
393 def _generate_func_trace_proto(self, stream_type, ev_type):
394 tmpl = barectf_templates._FUNC_TRACE_PROTO_BEGIN
395 self._cg.add_lines(tmpl.format(prefix=self._iden_prefix, sname=stream_type.name,
396 evname=ev_type.name))
397 self._generate_func_trace_proto_params(stream_type, ev_type)
398 tmpl = barectf_templates._FUNC_TRACE_PROTO_END
399 self._cg.add_lines(tmpl)
400
401 def _punctuate_proto(self):
402 self._cg.append_to_last_line(';')
403
404 def generate_header(self):
405 self._cg.reset()
406 dt = datetime.datetime.now().isoformat()
407 prefix_def = ''
408 def_stream_type_name_def = ''
409 cg_opts = self._cfg.options.code_generation_options
410 header_opts = cg_opts.header_options
411
412 if header_opts.identifier_prefix_definition:
413 prefix_def = f'#define _BARECTF_PREFIX {self._iden_prefix}'
414
415 def_stream_type = cg_opts.default_stream_type
416
417 if header_opts.default_stream_type_name_definition and def_stream_type is not None:
418 def_stream_type_name_def = f'#define _BARECTF_DEFAULT_STREAM {def_stream_type.name}'
419
420 def_stream_type_trace_defs = ''
421
422 if def_stream_type is not None:
423 lines = []
424
425 for ev_type in def_stream_type.event_types:
426 tmpl = barectf_templates._DEFINE_DEFAULT_STREAM_TRACE
427 define = tmpl.format(prefix=self._iden_prefix, sname=def_stream_type.name,
428 evname=ev_type.name)
429 lines.append(define)
430
431 def_stream_type_trace_defs = '\n'.join(lines)
432
433 tmpl = barectf_templates._HEADER_BEGIN
434 self._cg.add_lines(tmpl.format(prefix=self._iden_prefix,
435 ucprefix=self._iden_prefix.upper(),
436 version=barectf_version.__version__, date=dt,
437 prefix_def=prefix_def,
438 default_stream_def=def_stream_type_name_def,
439 default_stream_trace_defs=def_stream_type_trace_defs))
440 self._cg.add_empty_line()
441
442 # platform callbacks structure
443 self._generate_platform_callbacks()
444 self._cg.add_empty_line()
445
446 # context parent
447 self._generate_ctx_parent()
448 self._cg.add_empty_line()
449
450 # stream contexts
451 self._generate_ctxs()
452 self._cg.add_empty_line()
453
454 # initialization function prototype
455 self._generate_func_init_proto()
456 self._punctuate_proto()
457 self._cg.add_empty_line()
458
459 for stream_type in self._trace_type.stream_types:
460 self._generate_func_open_proto(stream_type)
461 self._punctuate_proto()
462 self._cg.add_empty_line()
463 self._generate_func_close_proto(stream_type)
464 self._punctuate_proto()
465 self._cg.add_empty_line()
466
467 for ev_type in stream_type.event_types:
468 self._generate_func_trace_proto(stream_type, ev_type)
469 self._punctuate_proto()
470 self._cg.add_empty_line()
471
472 tmpl = barectf_templates._HEADER_END
473 self._cg.add_lines(tmpl.format(ucprefix=self._iden_prefix.upper()))
474 return self._cg.code
475
476 def _get_call_event_param_list_from_struct_ft(self, ft, prefix, exclude_set=None):
477 if exclude_set is None:
478 exclude_set = set()
479
480 lst = ''
481
482 for member_name in ft.members:
483 if member_name in exclude_set:
484 continue
485
486 lst += f', {prefix}{member_name}'
487
488 return lst
489
490 def _get_call_event_param_list(self, stream_type, ev_type):
491 lst = ''
492
493 if stream_type._ev_header_ft is not None:
494 lst += self._get_call_event_param_list_from_struct_ft(stream_type._ev_header_ft,
495 _PREFIX_SEH, {'id', 'timestamp'})
496
497 if stream_type.event_common_context_field_type is not None:
498 lst += self._get_call_event_param_list_from_struct_ft(stream_type.event_common_context_field_type,
499 _PREFIX_SEC)
500
501 if ev_type.specific_context_field_type is not None:
502 lst += self._get_call_event_param_list_from_struct_ft(ev_type.specific_context_field_type,
503 _PREFIX_EC)
504
505 if ev_type.payload_field_type is not None:
506 lst += self._get_call_event_param_list_from_struct_ft(ev_type.payload_field_type,
507 _PREFIX_EP)
508
509 return lst
510
511 def _generate_align(self, at, align):
512 self._cg.add_line(f'_ALIGN({at}, {align});')
513
514 def _generate_incr_pos(self, var, value):
515 self._cg.add_line(f'{var} += {value};')
516
517 def _generate_incr_pos_bytes(self, var, value):
518 self._generate_incr_pos(var, f'_BYTES_TO_BITS({value})')
519
520 def _generate_func_get_event_size_proto(self, stream_type, ev_type):
521 tmpl = barectf_templates._FUNC_GET_EVENT_SIZE_PROTO_BEGIN
522 self._cg.add_lines(tmpl.format(prefix=self._iden_prefix, sname=stream_type.name,
523 evname=ev_type.name))
524 self._generate_func_trace_proto_params(stream_type, ev_type)
525 tmpl = barectf_templates._FUNC_GET_EVENT_SIZE_PROTO_END
526 self._cg.add_lines(tmpl)
527
528 def _generate_func_get_event_size(self, stream_type, ev_type):
529 self._generate_func_get_event_size_proto(stream_type, ev_type)
530 tmpl = barectf_templates._FUNC_GET_EVENT_SIZE_BODY_BEGIN
531 lines = tmpl.format(prefix=self._iden_prefix)
532 self._cg.add_lines(lines)
533 self._cg.add_empty_line()
534 self._cg.indent()
535 ser_actions = _SerializationActions()
536 ser_actions.append_root_scope_ft(stream_type._ev_header_ft, _PREFIX_SEH)
537 ser_actions.append_root_scope_ft(stream_type.event_common_context_field_type, _PREFIX_SEC)
538 ser_actions.append_root_scope_ft(ev_type.specific_context_field_type, _PREFIX_EC)
539 ser_actions.append_root_scope_ft(ev_type.payload_field_type, _PREFIX_EP)
540
541 for action in ser_actions.actions:
542 if type(action) is _AlignSerializationAction:
543 if action.names:
544 if len(action.names) == 1:
545 line = f'align {_PREFIX_TO_NAME[action.names[0]]} structure'
546 else:
547 line = f'align field `{action.names[-1]}` ({_PREFIX_TO_NAME[action.names[0]]})'
548
549 self._cg.add_cc_line(line)
550
551 self._generate_align('at', action.value)
552 self._cg.add_empty_line()
553 else:
554 assert type(action) is _SerializeSerializationAction
555 assert(len(action.names) >= 2)
556 line = f'add size of field `{action.names[-1]}` ({_PREFIX_TO_NAME[action.names[0]]})'
557 self._cg.add_cc_line(line)
558
559 if type(action.ft) is barectf_config.StringFieldType:
560 param = ''.join(action.names)
561 self._generate_incr_pos_bytes('at', f'strlen({param}) + 1')
562 else:
563 self._generate_incr_pos('at', action.ft.size)
564
565 self._cg.add_empty_line()
566
567 self._cg.unindent()
568 tmpl = barectf_templates._FUNC_GET_EVENT_SIZE_BODY_END
569 self._cg.add_lines(tmpl)
570
571 def _generate_func_serialize_event_proto(self, stream_type, ev_type):
572 tmpl = barectf_templates._FUNC_SERIALIZE_EVENT_PROTO_BEGIN
573 self._cg.add_lines(tmpl.format(prefix=self._iden_prefix, sname=stream_type.name,
574 evname=ev_type.name))
575 self._generate_func_trace_proto_params(stream_type, ev_type)
576 tmpl = barectf_templates._FUNC_SERIALIZE_EVENT_PROTO_END
577 self._cg.add_lines(tmpl)
578
579 def _generate_serialize_from_action(self, var, ctx, action):
580 def gen_bitfield_write(c_type, var, ctx, action):
581 ptr = f'&{ctx}->buf[_BITS_TO_BYTES({ctx}->at)]'
582 start = action.offset_in_byte
583 suffix = 'le' if action.ft.byte_order is barectf_config.ByteOrder.LITTLE_ENDIAN else 'be'
584 func = f'{self._iden_prefix}bt_bitfield_write_{suffix}'
585 call = f'{func}({ptr}, uint8_t, {start}, {action.ft.size}, {c_type}, ({c_type}) {var});'
586 self._cg.add_line(call)
587
588 def gen_serialize_int(var, ctx, action):
589 c_type = self._get_ft_c_type(action.ft)
590 gen_bitfield_write(c_type, var, ctx, action)
591 self._generate_incr_pos(f'{ctx}->at', action.ft.size)
592
593 def gen_serialize_real(var, ctx, action):
594 c_type = self._get_ft_c_type(action.ft)
595 flt_dbl = False
596
597 if c_type == 'float' or c_type == 'double':
598 flt_dbl = True
599
600 if c_type == 'float':
601 union_name = 'f2u'
602 int_c_type = 'uint32_t'
603 else:
604 assert c_type == 'double'
605 union_name = 'd2u'
606 int_c_type = 'uint64_t'
607
608 # union for reading the bytes of the floating point number
609 self._cg.add_empty_line()
610 self._cg.add_line('{')
611 self._cg.indent()
612 self._cg.add_line(f'union {union_name} {union_name};')
613 self._cg.add_empty_line()
614 self._cg.add_line(f'{union_name}.f = {var};')
615 bf_var = f'{union_name}.u'
616 else:
617 bf_var = f'({c_type}) {var}'
618 int_c_type = c_type
619
620 gen_bitfield_write(int_c_type, bf_var, ctx, action)
621
622 if flt_dbl:
623 self._cg.unindent()
624 self._cg.add_line('}')
625 self._cg.add_empty_line()
626
627 self._generate_incr_pos(f'{ctx}->at', action.ft.size)
628
629 def gen_serialize_string(var, ctx, action):
630 self._cg.add_lines(f'_write_cstring({ctx}, {var});')
631
632 if isinstance(action.ft, barectf_config._IntegerFieldType):
633 return gen_serialize_int(var, ctx, action)
634 elif type(action.ft) is barectf_config.RealFieldType:
635 return gen_serialize_real(var, ctx, action)
636 else:
637 assert type(action.ft) is barectf_config.StringFieldType
638 return gen_serialize_string(var, ctx, action)
639
640 def _generate_serialize_statements_from_actions(self, prefix, action_iter, spec_src=None):
641 for action in action_iter:
642 if type(action) is _AlignSerializationAction:
643 if action.names:
644 if len(action.names) == 1:
645 line = f'align {_PREFIX_TO_NAME[action.names[0]]} structure'
646 else:
647 line = f'align field `{action.names[-1]}` ({_PREFIX_TO_NAME[action.names[0]]})'
648
649 self._cg.add_cc_line(line)
650
651 self._generate_align('ctx->at', action.value)
652 self._cg.add_empty_line()
653 else:
654 assert type(action) is _SerializeSerializationAction
655 assert(len(action.names) >= 2)
656 member_name = action.names[-1]
657 line = f'serialize field `{member_name}` ({_PREFIX_TO_NAME[action.names[0]]})'
658 self._cg.add_cc_line(line)
659 src = prefix + member_name
660
661 if spec_src is not None and member_name in spec_src:
662 src = spec_src[member_name]
663
664 self._generate_serialize_from_action(src, 'ctx', action)
665 self._cg.add_empty_line()
666
667 def _generate_func_serialize_event(self, stream_type, ev_type, orig_ser_actions):
668 self._generate_func_serialize_event_proto(stream_type, ev_type)
669 tmpl = barectf_templates._FUNC_SERIALIZE_EVENT_BODY_BEGIN
670 lines = tmpl.format(prefix=self._iden_prefix)
671 self._cg.add_lines(lines)
672 self._cg.indent()
673 self._cg.add_empty_line()
674
675 if stream_type._ev_header_ft is not None:
676 params = self._get_call_event_param_list_from_struct_ft(stream_type._ev_header_ft,
677 _PREFIX_SEH,
678 {'timestamp', 'id'})
679 self._cg.add_cc_line('stream event header')
680 line = f'_serialize_stream_event_header_{stream_type.name}(ctx, {ev_type.id}{params});'
681 self._cg.add_line(line)
682 self._cg.add_empty_line()
683
684 if stream_type.event_common_context_field_type is not None:
685 params = self._get_call_event_param_list_from_struct_ft(stream_type.event_common_context_field_type,
686 _PREFIX_SEC)
687 self._cg.add_cc_line('stream event context')
688 line = f'_serialize_stream_event_context_{stream_type.name}(ctx{params});'
689 self._cg.add_line(line)
690 self._cg.add_empty_line()
691
692 if ev_type.specific_context_field_type is not None or ev_type.payload_field_type is not None:
693 ser_actions = copy.deepcopy(orig_ser_actions)
694
695 if ev_type.specific_context_field_type is not None:
696 ser_action_index = len(ser_actions.actions)
697 ser_actions.append_root_scope_ft(ev_type.specific_context_field_type, _PREFIX_EC)
698 ser_action_iter = itertools.islice(ser_actions.actions, ser_action_index, None)
699 self._generate_serialize_statements_from_actions(_PREFIX_EC, ser_action_iter)
700
701 if ev_type.payload_field_type is not None:
702 ser_action_index = len(ser_actions.actions)
703 ser_actions.append_root_scope_ft(ev_type.payload_field_type, _PREFIX_EP)
704 ser_action_iter = itertools.islice(ser_actions.actions, ser_action_index, None)
705 self._generate_serialize_statements_from_actions(_PREFIX_EP, ser_action_iter)
706
707 self._cg.unindent()
708 tmpl = barectf_templates._FUNC_SERIALIZE_EVENT_BODY_END
709 self._cg.add_lines(tmpl)
710
711 def _generate_func_serialize_event_header_proto(self, stream_type):
712 tmpl = barectf_templates._FUNC_SERIALIZE_STREAM_EVENT_HEADER_PROTO_BEGIN
713 self._cg.add_lines(tmpl.format(prefix=self._iden_prefix, sname=stream_type.name))
714
715 if stream_type._ev_header_ft is not None:
716 self._generate_proto_params(stream_type._ev_header_ft, _PREFIX_SEH,
717 {'id', 'timestamp'})
718
719 tmpl = barectf_templates._FUNC_SERIALIZE_STREAM_EVENT_HEADER_PROTO_END
720 self._cg.add_lines(tmpl)
721
722 def _generate_func_serialize_event_common_context_proto(self, stream_type):
723 tmpl = barectf_templates._FUNC_SERIALIZE_STREAM_EVENT_CONTEXT_PROTO_BEGIN
724 self._cg.add_lines(tmpl.format(prefix=self._iden_prefix, sname=stream_type.name))
725
726 if stream_type.event_common_context_field_type is not None:
727 self._generate_proto_params(stream_type.event_common_context_field_type, _PREFIX_SEC)
728
729 tmpl = barectf_templates._FUNC_SERIALIZE_STREAM_EVENT_CONTEXT_PROTO_END
730 self._cg.add_lines(tmpl)
731
732 def _generate_func_serialize_event_header(self, stream_type, ser_action_iter):
733 self._generate_func_serialize_event_header_proto(stream_type)
734 tmpl = barectf_templates._FUNC_SERIALIZE_STREAM_EVENT_HEADER_BODY_BEGIN
735 lines = tmpl.format(prefix=self._iden_prefix, sname=stream_type.name)
736 self._cg.add_lines(lines)
737 self._cg.indent()
738
739 if stream_type.default_clock_type is not None:
740 line = f'struct {self._iden_prefix}{stream_type.name}_ctx *s_ctx = FROM_VOID_PTR(struct {self._iden_prefix}{stream_type.name}_ctx, vctx);'
741 self._cg.add_line(line)
742 line = f'const {self._clk_type_c_type(stream_type.default_clock_type)} ts = s_ctx->cur_last_event_ts;'
743 self._cg.add_line(line)
744
745 self._cg.add_empty_line()
746
747 if stream_type._ev_header_ft is not None:
748 spec_src = {}
749 member_name = 'id'
750 member = stream_type._ev_header_ft.members.get(member_name)
751
752 if member is not None:
753 spec_src[member_name] = f'({self._get_ft_c_type(member.field_type)}) event_id'
754
755 member_name = 'timestamp'
756 member = stream_type._ev_header_ft.members.get(member_name)
757
758 if member is not None:
759 spec_src[member_name] = f'({self._get_ft_c_type(member.field_type)}) ts'
760
761 self._generate_serialize_statements_from_actions(_PREFIX_SEH, ser_action_iter,
762 spec_src)
763
764 self._cg.unindent()
765 tmpl = barectf_templates._FUNC_SERIALIZE_STREAM_EVENT_HEADER_BODY_END
766 self._cg.add_lines(tmpl)
767
768 def _generate_func_serialize_event_common_context(self, stream_type, ser_action_iter):
769 self._generate_func_serialize_event_common_context_proto(stream_type)
770 tmpl = barectf_templates._FUNC_SERIALIZE_STREAM_EVENT_CONTEXT_BODY_BEGIN
771 lines = tmpl.format(prefix=self._iden_prefix)
772 self._cg.add_lines(lines)
773 self._cg.indent()
774
775 if stream_type.event_common_context_field_type is not None:
776 self._generate_serialize_statements_from_actions(_PREFIX_SEC, ser_action_iter)
777
778 self._cg.unindent()
779 tmpl = barectf_templates._FUNC_SERIALIZE_STREAM_EVENT_CONTEXT_BODY_END
780 self._cg.add_lines(tmpl)
781
782 def _generate_func_trace(self, stream_type, ev_type):
783 self._generate_func_trace_proto(stream_type, ev_type)
784 params = self._get_call_event_param_list(stream_type, ev_type)
785 def_clk_type = stream_type.default_clock_type
786
787 if def_clk_type is not None:
788 save_ts_line = f'ctx->cur_last_event_ts = ctx->parent.cbs.{def_clk_type.name}_clock_get_value(ctx->parent.data);'
789 else:
790 save_ts_line = '/* (no clock) */'
791
792 tmpl = barectf_templates._FUNC_TRACE_BODY
793 self._cg.add_lines(tmpl.format(sname=stream_type.name, evname=ev_type.name, params=params,
794 save_ts=save_ts_line))
795
796 def _generate_func_init(self):
797 self._generate_func_init_proto()
798 tmpl = barectf_templates._FUNC_INIT_BODY
799 self._cg.add_lines(tmpl.format(prefix=self._iden_prefix))
800
801 def _generate_member_name_cc_line(self, member_name):
802 self._cg.add_cc_line(f'`{member_name}` field')
803
804 def _save_serialization_action(self, name, action):
805 self._saved_serialization_actions[name] = action
806
807 def _get_open_close_ts_line(self, stream_type):
808 def_clk_type = stream_type.default_clock_type
809
810 if def_clk_type is None:
811 return ''
812
813 c_type = self._clk_type_c_type(def_clk_type)
814 return f'\tconst {c_type} ts = ctx->parent.use_cur_last_event_ts ? ctx->cur_last_event_ts : ctx->parent.cbs.{def_clk_type.name}_clock_get_value(ctx->parent.data);'
815
816 def _generate_func_open(self, stream_type):
817 def generate_save_offset(name, action):
818 self._cg.add_line(f'ctx->off_spc_{name} = ctx->parent.at;')
819 self._save_serialization_action(name, action)
820
821 self._generate_func_open_proto(stream_type)
822 tmpl = barectf_templates._FUNC_OPEN_BODY_BEGIN
823 pkt_ctx_ft = stream_type._pkt_ctx_ft
824 ts_line = self._get_open_close_ts_line(stream_type)
825 lines = tmpl.format(ts=ts_line)
826 self._cg.add_lines(lines)
827 self._cg.indent()
828 self._cg.add_cc_line('do not open a packet that is already open')
829 self._cg.add_line('if (ctx->parent.packet_is_open) {')
830 self._cg.indent()
831 self._cg.add_line('ctx->parent.in_tracing_section = saved_in_tracing_section;')
832 self._cg.add_line('return;')
833 self._cg.unindent()
834 self._cg.add_line('}')
835 self._cg.add_empty_line()
836 self._cg.add_line('ctx->parent.at = 0;')
837 pkt_header_ft = self._trace_type._pkt_header_ft
838 ser_actions = _SerializationActions()
839
840 if pkt_header_ft is not None:
841 self._cg.add_empty_line()
842 self._cg.add_cc_line('trace packet header')
843 self._cg.add_line('{')
844 self._cg.indent()
845 ser_actions.append_root_scope_ft(pkt_header_ft, _PREFIX_TPH)
846
847 for action in ser_actions.actions:
848 if type(action) is _AlignSerializationAction:
849 if action.names:
850 if len(action.names) == 1:
851 line = 'align trace packet header structure'
852 else:
853 line = f'align field `{action.names[-1]}`'
854
855 self._cg.add_cc_line(line)
856
857 self._generate_align('ctx->parent.at', action.value)
858 self._cg.add_empty_line()
859 else:
860 assert type(action) is _SerializeSerializationAction
861 assert(len(action.names) >= 2)
862 member_name = action.names[-1]
863 line = f'serialize field `{member_name}`'
864 self._cg.add_cc_line(line)
865 src = _PREFIX_TPH + member_name
866
867 if member_name == 'magic':
868 src = '0xc1fc1fc1UL'
869 elif member_name == 'stream_id':
870 src = f'({self._get_ft_c_type(action.ft)}) {stream_type.id}'
871 elif member_name == 'uuid':
872 self._cg.add_line('{')
873 self._cg.indent()
874 self._cg.add_line('static uint8_t uuid[] = {')
875 self._cg.indent()
876
877 for b in self._trace_type.uuid.bytes:
878 self._cg.add_line(f'{b},')
879
880 self._cg.unindent()
881 self._cg.add_line('};')
882 self._cg.add_empty_line()
883 self._generate_align('ctx->parent.at', 8)
884 line = 'memcpy(&ctx->parent.buf[_BITS_TO_BYTES(ctx->parent.at)], uuid, 16);'
885 self._cg.add_line(line)
886 self._generate_incr_pos_bytes('ctx->parent.at', 16)
887 self._cg.unindent()
888 self._cg.add_line('}')
889 self._cg.add_empty_line()
890 continue
891
892 self._generate_serialize_from_action(src, '(&ctx->parent)', action)
893 self._cg.add_empty_line()
894
895 self._cg.unindent()
896 self._cg.add_lines('}')
897
898 spc_action_index = len(ser_actions.actions)
899 self._cg.add_empty_line()
900 self._cg.add_cc_line('stream packet context')
901 self._cg.add_line('{')
902 self._cg.indent()
903 ser_actions.append_root_scope_ft(pkt_ctx_ft, _PREFIX_SPC)
904
905 for action in itertools.islice(ser_actions.actions, spc_action_index, None):
906 if type(action) is _AlignSerializationAction:
907 if action.names:
908 if len(action.names) == 1:
909 line = 'align stream packet context structure'
910 else:
911 line = f'align field `{action.names[-1]}`'
912
913 self._cg.add_cc_line(line)
914
915 self._generate_align('ctx->parent.at', action.value)
916 self._cg.add_empty_line()
917 else:
918 assert type(action) is _SerializeSerializationAction
919 assert(len(action.names) >= 2)
920 member_name = action.names[-1]
921 line = f'serialize field `{member_name}`'
922 self._cg.add_cc_line(line)
923 src = _PREFIX_SPC + member_name
924 skip_int = False
925
926 if member_name == 'timestamp_begin':
927 src = f'({self._get_ft_c_type(action.ft)}) ts'
928 elif member_name in {'timestamp_end', 'content_size', 'events_discarded'}:
929 skip_int = True
930 elif member_name == 'packet_size':
931 src = f'({self._get_ft_c_type(action.ft)}) ctx->parent.packet_size'
932
933 if skip_int:
934 generate_save_offset(member_name, action)
935 self._generate_incr_pos('ctx->parent.at', action.ft.size)
936 else:
937 self._generate_serialize_from_action(src, '(&ctx->parent)', action)
938
939 self._cg.add_empty_line()
940
941 self._cg.unindent()
942 self._cg.add_lines('}')
943 self._cg.unindent()
944 tmpl = barectf_templates._FUNC_OPEN_BODY_END
945 self._cg.add_lines(tmpl)
946
947 def _generate_func_close(self, stream_type):
948 def generate_goto_offset(name):
949 self._cg.add_line(f'ctx->parent.at = ctx->off_spc_{name};')
950
951 self._generate_func_close_proto(stream_type)
952 tmpl = barectf_templates._FUNC_CLOSE_BODY_BEGIN
953 pkt_ctx_ft = stream_type._pkt_ctx_ft
954 ts_line = self._get_open_close_ts_line(stream_type)
955 lines = tmpl.format(ts=ts_line)
956 self._cg.add_lines(lines)
957 self._cg.indent()
958 self._cg.add_cc_line('do not close a packet that is not open')
959 self._cg.add_line('if (!ctx->parent.packet_is_open) {')
960 self._cg.indent()
961 self._cg.add_line('ctx->parent.in_tracing_section = saved_in_tracing_section;')
962 self._cg.add_line('return;')
963 self._cg.unindent()
964 self._cg.add_line('}')
965 self._cg.add_empty_line()
966 self._cg.add_cc_line('save content size')
967 self._cg.add_line('ctx->parent.content_size = ctx->parent.at;')
968 member_name = 'timestamp_end'
969 member = pkt_ctx_ft.members.get(member_name)
970
971 if member is not None:
972 self._cg.add_empty_line()
973 self._generate_member_name_cc_line(member_name)
974 generate_goto_offset(member_name)
975 action = self._saved_serialization_actions[member_name]
976 c_type = self._get_ft_c_type(member.field_type)
977 self._generate_serialize_from_action(f'({c_type}) ts', '(&ctx->parent)', action)
978
979 member_name = 'content_size'
980 member = pkt_ctx_ft.members.get(member_name)
981
982 if member is not None:
983 self._cg.add_empty_line()
984 self._generate_member_name_cc_line(member_name)
985 generate_goto_offset(member_name)
986 action = self._saved_serialization_actions[member_name]
987 c_type = self._get_ft_c_type(member.field_type)
988 self._generate_serialize_from_action(f'({c_type}) ctx->parent.content_size',
989 '(&ctx->parent)', action)
990
991 member_name = 'events_discarded'
992 member = pkt_ctx_ft.members.get(member_name)
993
994 if member is not None:
995 self._cg.add_empty_line()
996 self._generate_member_name_cc_line(member_name)
997 generate_goto_offset(member_name)
998 action = self._saved_serialization_actions[member_name]
999 c_type = self._get_ft_c_type(member.field_type)
1000 self._generate_serialize_from_action(f'({c_type}) ctx->parent.events_discarded',
1001 '(&ctx->parent)', action)
1002
1003 self._cg.unindent()
1004 tmpl = barectf_templates._FUNC_CLOSE_BODY_END
1005 self._cg.add_lines(tmpl)
1006
1007 def generate_c_src(self, header_name, bitfield_header_name):
1008 self._cg.reset()
1009 dt = datetime.datetime.now().isoformat()
1010 tmpl = barectf_templates._C_SRC
1011 self._cg.add_lines(tmpl.format(prefix=self._iden_prefix, header_filename=header_name,
1012 bitfield_header_filename=bitfield_header_name,
1013 version=barectf_version.__version__, date=dt))
1014 self._cg.add_empty_line()
1015
1016 # initialization function
1017 self._generate_func_init()
1018 self._cg.add_empty_line()
1019
1020 for stream_type in self._trace_type.stream_types:
1021 self._generate_func_open(stream_type)
1022 self._cg.add_empty_line()
1023 self._generate_func_close(stream_type)
1024 self._cg.add_empty_line()
1025 ser_actions = _SerializationActions()
1026
1027 if stream_type._ev_header_ft is not None:
1028 ser_actions.append_root_scope_ft(stream_type._ev_header_ft, _PREFIX_SEH)
1029 self._generate_func_serialize_event_header(stream_type, iter(ser_actions.actions))
1030 self._cg.add_empty_line()
1031
1032 if stream_type.event_common_context_field_type is not None:
1033 ser_action_index = len(ser_actions.actions)
1034 ser_actions.append_root_scope_ft(stream_type.event_common_context_field_type,
1035 _PREFIX_SEC)
1036 ser_action_iter = itertools.islice(ser_actions.actions, ser_action_index, None)
1037 self._generate_func_serialize_event_common_context(stream_type, ser_action_iter)
1038 self._cg.add_empty_line()
1039
1040 for ev_type in stream_type.event_types:
1041 self._generate_func_get_event_size(stream_type, ev_type)
1042 self._cg.add_empty_line()
1043 self._generate_func_serialize_event(stream_type, ev_type, ser_actions)
1044 self._cg.add_empty_line()
1045 self._generate_func_trace(stream_type, ev_type)
1046 self._cg.add_empty_line()
1047
1048 return self._cg.code
This page took 0.051027 seconds and 3 git commands to generate.