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