gen: statically compute event field sizes when possible
[barectf.git] / barectf / gen.py
1 # The MIT License (MIT)
2 #
3 # Copyright (c) 2014-2016 Philippe Proulx <pproulx@efficios.com>
4 #
5 # Permission is hereby granted, free of charge, to any person obtaining a copy
6 # of this software and associated documentation files (the "Software"), to deal
7 # in the Software without restriction, including without limitation the rights
8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 # copies of the Software, and to permit persons to whom the Software is
10 # furnished to do so, subject to the following conditions:
11 #
12 # The above copyright notice and this permission notice shall be included in
13 # all copies or substantial portions of the Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 # THE SOFTWARE.
22
23 from barectf import templates
24 from barectf import metadata
25 import barectf.codegen
26 import collections
27 import argparse
28 import datetime
29 import barectf
30 import sys
31 import os
32 import re
33
34
35 def _align(v, align):
36 return (v + (align - 1)) & -align
37
38
39 class _StaticAlignSizeAutomatonByteOffset:
40 def __init__(self):
41 self._byte_offset = 0
42 self._type_to_update_byte_offset_func = {
43 metadata.Integer: self._write_static_size,
44 metadata.FloatingPoint: self._write_static_size,
45 metadata.Enum: self._write_static_size,
46 metadata.String: self._write_string_size,
47 }
48
49 @property
50 def byte_offset(self):
51 return self._byte_offset
52
53 @byte_offset.setter
54 def byte_offset(self, value):
55 self._byte_offset = value
56
57 def _wrap_byte_offset(self):
58 self._byte_offset %= 8
59
60 def align(self, align):
61 # align byte offset
62 self._byte_offset = _align(self._byte_offset, align)
63
64 # wrap on current byte
65 self._wrap_byte_offset()
66
67 def write_type(self, t):
68 self._type_to_update_byte_offset_func[type(t)](t)
69
70 def _write_string_size(self, t):
71 self.reset()
72
73 def _write_static_size(self, t):
74 # increment byte offset
75 self._byte_offset += t.size
76
77 # wrap on current byte
78 self._wrap_byte_offset()
79
80 def reset(self):
81 # reset byte offset
82 self._byte_offset = 0
83
84 def set_unknown(self):
85 self._byte_offset = None
86
87
88 class _StaticAlignSizeAutomatonPreSize:
89 def __init__(self):
90 self.reset(1)
91
92 def reset(self, initial_align):
93 self._max_align = initial_align
94 self._size = 0
95
96 def add_type(self, t):
97 if t.align > self._max_align:
98 # type alignment is greater than the maximum alignment we
99 # got so far since the last reset, so we don't know how many
100 # padding bits are needed between this type and the previous
101 # one, hence the static size is set to the type's size
102 # (since we're aligned) and our new alignment is saved
103 self._max_align = t.align
104
105 if type(t) is metadata.Struct:
106 self._size = 0
107 else:
108 self._size = t.size
109
110 return False
111 else:
112 # type alignment is lesser than or equal to the maximum
113 # alignment we got so far, so we just align the static size
114 # and add the type's size
115 self._size = _align(self._size, t.align)
116
117 if type(t) is not metadata.Struct:
118 self._size += t.size
119
120 return True
121
122 @property
123 def size(self):
124 return self._size
125
126
127 _PREFIX_TPH = 'tph_'
128 _PREFIX_SPC = 'spc_'
129 _PREFIX_SEH = 'seh_'
130 _PREFIX_SEC = 'sec_'
131 _PREFIX_EC = 'ec_'
132 _PREFIX_EP = 'ep_'
133
134
135 class CCodeGenerator:
136 def __init__(self, cfg):
137 self._cfg = cfg
138 self._cg = barectf.codegen.CodeGenerator('\t')
139 self._type_to_get_ctype_func = {
140 metadata.Integer: self._get_int_ctype,
141 metadata.FloatingPoint: self._get_float_ctype,
142 metadata.Enum: self._get_enum_ctype,
143 metadata.String: self._get_string_ctype,
144 }
145 self._type_to_generate_serialize_func = {
146 metadata.Integer: self._generate_serialize_int,
147 metadata.FloatingPoint: self._generate_serialize_float,
148 metadata.Enum: self._generate_serialize_enum,
149 metadata.String: self._generate_serialize_string,
150 }
151 self._saved_byte_offsets = {}
152 self._uf_written = False
153 self._ud_written = False
154 self._sasa = _StaticAlignSizeAutomatonByteOffset()
155
156 def _generate_ctx_parent(self):
157 tmpl = templates._CTX_PARENT
158 self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix))
159
160 def _generate_ctx(self, stream):
161 tmpl = templates._CTX_BEGIN
162 self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix,
163 sname=stream.name))
164 tmpl = 'uint32_t off_tph_{fname};'
165 self._cg.indent()
166 trace_packet_header_type = self._cfg.metadata.trace.packet_header_type
167
168 if trace_packet_header_type is not None:
169 for field_name in trace_packet_header_type.fields:
170 self._cg.add_lines(tmpl.format(fname=field_name))
171
172 tmpl = 'uint32_t off_spc_{fname};'
173
174 if stream.packet_context_type is not None:
175 for field_name in stream.packet_context_type.fields:
176 self._cg.add_lines(tmpl.format(fname=field_name))
177
178 self._cg.unindent()
179 tmpl = templates._CTX_END
180 self._cg.add_lines(tmpl)
181
182 def _generate_ctxs(self):
183 for stream in self._cfg.metadata.streams.values():
184 self._generate_ctx(stream)
185
186 def _generate_clock_cb(self, clock):
187 tmpl = templates._CLOCK_CB
188 self._cg.add_lines(tmpl.format(return_ctype=clock.return_ctype,
189 cname=clock.name))
190
191 def _generate_clock_cbs(self):
192 for clock in self._cfg.metadata.clocks.values():
193 self._generate_clock_cb(clock)
194
195 def _generate_platform_callbacks(self):
196 tmpl = templates._PLATFORM_CALLBACKS_BEGIN
197 self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix))
198 self._cg.indent()
199 self._generate_clock_cbs()
200 self._cg.unindent()
201 tmpl = templates._PLATFORM_CALLBACKS_END
202 self._cg.add_lines(tmpl)
203
204 def generate_bitfield_header(self):
205 self._cg.reset()
206 tmpl = templates._BITFIELD
207 tmpl = tmpl.replace('$prefix$', self._cfg.prefix)
208 tmpl = tmpl.replace('$PREFIX$', self._cfg.prefix.upper())
209
210 if self._cfg.metadata.trace.byte_order == metadata.ByteOrder.BE:
211 endian_def = 'BIG_ENDIAN'
212 else:
213 endian_def = 'LITTLE_ENDIAN'
214
215 tmpl = tmpl.replace('$ENDIAN_DEF$', endian_def)
216 self._cg.add_lines(tmpl)
217
218 return self._cg.code
219
220 def _generate_func_init_proto(self):
221 tmpl = templates._FUNC_INIT_PROTO
222 self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix))
223
224 def _get_int_ctype(self, t):
225 signed = 'u' if not t.signed else ''
226
227 if t.size <= 8:
228 sz = '8'
229 elif t.size <= 16:
230 sz = '16'
231 elif t.size <= 32:
232 sz = '32'
233 elif t.size == 64:
234 sz = '64'
235
236 return '{}int{}_t'.format(signed, sz)
237
238 def _get_float_ctype(self, t):
239 if t.exp_size == 8 and t.mant_size == 24 and t.align == 32:
240 ctype = 'float'
241 elif t.exp_size == 11 and t.mant_size == 53 and t.align == 64:
242 ctype = 'double'
243 else:
244 ctype = 'uint64_t'
245
246 return ctype
247
248 def _get_enum_ctype(self, t):
249 return self._get_int_ctype(t.value_type)
250
251 def _get_string_ctype(self, t):
252 return 'const char *'
253
254 def _get_type_ctype(self, t):
255 return self._type_to_get_ctype_func[type(t)](t)
256
257 def _generate_type_ctype(self, t):
258 ctype = self._get_type_ctype(t)
259 self._cg.append_to_last_line(ctype)
260
261 def _generate_proto_param(self, t, name):
262 self._generate_type_ctype(t)
263 self._cg.append_to_last_line(' ')
264 self._cg.append_to_last_line(name)
265
266 def _generate_proto_params(self, t, name_prefix, exclude_list):
267 self._cg.indent()
268
269 for field_name, field_type in t.fields.items():
270 if field_name in exclude_list:
271 continue
272
273 name = name_prefix + field_name
274 self._cg.append_to_last_line(',')
275 self._cg.add_line('')
276 self._generate_proto_param(field_type, name)
277
278 self._cg.unindent()
279
280 def _generate_func_open_proto(self, stream):
281 tmpl = templates._FUNC_OPEN_PROTO_BEGIN
282 self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix,
283 sname=stream.name))
284 trace_packet_header_type = self._cfg.metadata.trace.packet_header_type
285
286 if trace_packet_header_type is not None:
287 exclude_list = ['magic', 'stream_id', 'uuid']
288 self._generate_proto_params(trace_packet_header_type, _PREFIX_TPH,
289 exclude_list)
290
291 if stream.packet_context_type is not None:
292 exclude_list = [
293 'timestamp_begin',
294 'timestamp_end',
295 'packet_size',
296 'content_size',
297 'events_discarded',
298 ]
299 self._generate_proto_params(stream.packet_context_type,
300 _PREFIX_SPC, exclude_list)
301
302 tmpl = templates._FUNC_OPEN_PROTO_END
303 self._cg.add_lines(tmpl)
304
305 def _generate_func_close_proto(self, stream):
306 tmpl = templates._FUNC_CLOSE_PROTO
307 self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix,
308 sname=stream.name))
309
310 def _generate_func_trace_proto_params(self, stream, event):
311 if stream.event_header_type is not None:
312 exclude_list = [
313 'id',
314 'timestamp',
315 ]
316 self._generate_proto_params(stream.event_header_type,
317 _PREFIX_SEH, exclude_list)
318
319 if stream.event_context_type is not None:
320 self._generate_proto_params(stream.event_context_type,
321 _PREFIX_SEC, [])
322
323 if event.context_type is not None:
324 self._generate_proto_params(event.context_type,
325 _PREFIX_EC, [])
326
327 if event.payload_type is not None:
328 self._generate_proto_params(event.payload_type,
329 _PREFIX_EP, [])
330
331 def _generate_func_trace_proto(self, stream, event):
332 tmpl = templates._FUNC_TRACE_PROTO_BEGIN
333 self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix,
334 sname=stream.name, evname=event.name))
335 self._generate_func_trace_proto_params(stream, event)
336 tmpl = templates._FUNC_TRACE_PROTO_END
337 self._cg.add_lines(tmpl)
338
339 def _punctuate_proto(self):
340 self._cg.append_to_last_line(';')
341
342 def generate_header(self):
343 self._cg.reset()
344 dt = datetime.datetime.now().isoformat()
345 bh_filename = self.get_bitfield_header_filename()
346 tmpl = templates._HEADER_BEGIN
347 self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix,
348 ucprefix=self._cfg.prefix.upper(),
349 bitfield_header_filename=bh_filename,
350 version=barectf.__version__, date=dt))
351 self._cg.add_empty_line()
352
353 # platform callbacks structure
354 self._generate_platform_callbacks()
355 self._cg.add_empty_line()
356
357 # context parent
358 self._generate_ctx_parent()
359 self._cg.add_empty_line()
360
361 # stream contexts
362 self._generate_ctxs()
363 self._cg.add_empty_line()
364
365 # initialization function prototype
366 self._generate_func_init_proto()
367 self._punctuate_proto()
368 self._cg.add_empty_line()
369
370 for stream in self._cfg.metadata.streams.values():
371 self._generate_func_open_proto(stream)
372 self._punctuate_proto()
373 self._cg.add_empty_line()
374 self._generate_func_close_proto(stream)
375 self._punctuate_proto()
376 self._cg.add_empty_line()
377
378 for ev in stream.events.values():
379 self._generate_func_trace_proto(stream, ev)
380 self._punctuate_proto()
381 self._cg.add_empty_line()
382
383 tmpl = templates._HEADER_END
384 self._cg.add_lines(tmpl.format(ucprefix=self._cfg.prefix.upper()))
385
386 return self._cg.code
387
388 def _get_call_event_param_list_from_struct(self, t, prefix, exclude_list):
389 lst = ''
390
391 for field_name in t.fields:
392 if field_name in exclude_list:
393 continue
394
395 lst += ', {}{}'.format(prefix, field_name)
396
397 return lst
398
399 def _get_call_event_param_list(self, stream, event):
400 lst = ''
401 gcp_func = self._get_call_event_param_list_from_struct
402
403 if stream.event_header_type is not None:
404 exclude_list = [
405 'id',
406 'timestamp',
407 ]
408 lst += gcp_func(stream.event_header_type, _PREFIX_SEH, exclude_list)
409
410 if stream.event_context_type is not None:
411 lst += gcp_func(stream.event_context_type, _PREFIX_SEC, [])
412
413 if event.context_type is not None:
414 lst += gcp_func(event.context_type, _PREFIX_EC, [])
415
416 if event.payload_type is not None:
417 lst += gcp_func(event.payload_type, _PREFIX_EP, [])
418
419 return lst
420
421 def _generate_align(self, at, align):
422 self._cg.add_line('_ALIGN({}, {});'.format(at, align))
423 self._sasa.align(align)
424
425 def _generate_align_type(self, at, t):
426 if t.align == 1:
427 return
428
429 self._generate_align(at, t.align)
430
431 def _generate_incr_pos(self, var, value):
432 self._cg.add_line('{} += {};'.format(var, value))
433
434 def _generate_incr_pos_bytes(self, var, value):
435 self._generate_incr_pos(var, '_BYTES_TO_BITS({})'.format(value))
436
437 def _generate_func_get_event_size_proto(self, stream, event):
438 tmpl = templates._FUNC_GET_EVENT_SIZE_PROTO_BEGIN
439 self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix,
440 sname=stream.name, evname=event.name))
441 self._generate_func_trace_proto_params(stream, event)
442 tmpl = templates._FUNC_GET_EVENT_SIZE_PROTO_END
443 self._cg.add_lines(tmpl)
444
445 def _generate_func_get_event_size_from_entity(self, prefix, t):
446 self._cg.add_line('{')
447 self._cg.indent()
448 statically_aligned = self._pre_size_sasa.add_type(t)
449
450 if not statically_aligned:
451 # increment current position if needed
452 if self._last_basic_types_size > 0:
453 self._generate_incr_pos('at', self._last_basic_types_size)
454 self._last_basic_types_size = 0
455
456 self._cg.add_cc_line('align structure')
457 self._generate_align_type('at', t)
458
459 for field_name, field_type in t.fields.items():
460 self._cg.add_empty_line()
461 self._generate_field_name_cc_line(field_name)
462
463 if type(field_type) is metadata.String:
464 # increment current position if needed
465 if self._last_basic_types_size > 0:
466 self._generate_incr_pos('at', self._last_basic_types_size)
467 self._last_basic_types_size = 0
468
469 param = prefix + field_name
470 self._generate_incr_pos_bytes('at',
471 'strlen({}) + 1'.format(param))
472 self._pre_size_sasa.reset(8)
473 else:
474 statically_aligned = self._pre_size_sasa.add_type(field_type)
475
476 if not statically_aligned:
477 # increment current position if needed
478 if self._last_basic_types_size > 0:
479 self._generate_incr_pos('at', self._last_basic_types_size)
480
481 # realign dynamically
482 self._cg.add_cc_line('align for field')
483 self._generate_align_type('at', field_type)
484
485 fmt = 'field size: {} (partial total so far: {})'
486 self._cg.add_cc_line(fmt.format(field_type.size, self._pre_size_sasa.size))
487 self._last_basic_types_size = self._pre_size_sasa.size
488
489 self._cg.unindent()
490 self._cg.add_line('}')
491 self._cg.add_empty_line()
492
493 def _generate_func_get_event_size(self, stream, event):
494 self._reset_per_func_state()
495 self._generate_func_get_event_size_proto(stream, event)
496 tmpl = templates._FUNC_GET_EVENT_SIZE_BODY_BEGIN
497 self._cg.add_lines(tmpl)
498 self._cg.add_empty_line()
499 self._cg.indent()
500 func = self._generate_func_get_event_size_from_entity
501 self._pre_size_sasa = _StaticAlignSizeAutomatonPreSize()
502 self._cg.add_cc_line('byte-align entity')
503 self._generate_align('at', 8)
504 self._cg.add_empty_line()
505 self._pre_size_sasa.reset(8)
506 self._last_basic_types_size = 0
507
508 if stream.event_header_type is not None:
509 self._cg.add_cc_line('stream event header')
510 func(_PREFIX_SEH, stream.event_header_type)
511
512 if stream.event_context_type is not None:
513 self._cg.add_cc_line('stream event context')
514 func(_PREFIX_SEC, stream.event_context_type)
515
516 if event.context_type is not None:
517 self._cg.add_cc_line('event context')
518 func(_PREFIX_EC, event.context_type)
519
520 if event.payload_type is not None:
521 self._cg.add_cc_line('event payload')
522 func(_PREFIX_EP, event.payload_type)
523
524 # increment current position if needed
525 if self._last_basic_types_size > 0:
526 self._generate_incr_pos('at', self._last_basic_types_size)
527 self._cg.add_empty_line()
528
529 self._cg.unindent()
530 tmpl = templates._FUNC_GET_EVENT_SIZE_BODY_END
531 self._cg.add_lines(tmpl)
532
533 def _generate_func_serialize_event_proto(self, stream, event):
534 tmpl = templates._FUNC_SERIALIZE_EVENT_PROTO_BEGIN
535 self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix,
536 sname=stream.name, evname=event.name))
537 self._generate_func_trace_proto_params(stream, event)
538 tmpl = templates._FUNC_SERIALIZE_EVENT_PROTO_END
539 self._cg.add_lines(tmpl)
540
541 def _generate_bitfield_write(self, var, ctx, t):
542 ptr = '&{ctx}->buf[_BITS_TO_BYTES({ctx}->at)]'.format(ctx=ctx)
543 start = self._sasa.byte_offset
544 suffix = 'le' if t.byte_order is metadata.ByteOrder.LE else 'be'
545 func = '{}bt_bitfield_write_{}'.format(self._cfg.prefix, suffix)
546 call = '{}({}, uint8_t, {}, {}, {});'.format(func, ptr, start, t.size,
547 var)
548 self._cg.add_line(call)
549
550 def _generate_serialize_int(self, var, ctx, t):
551 self._generate_bitfield_write(var, ctx, t)
552 self._generate_incr_pos('{}->at'.format(ctx), t.size)
553
554 def _generate_serialize_float(self, var, ctx, t):
555 ctype = self._get_type_ctype(t)
556
557 if ctype == 'float' or ctype == 'double':
558 gen_union_var = False
559
560 if ctype == 'float':
561 if not self._uf_written:
562 self._uf_written = True
563 gen_union_var = True
564
565 union_name = 'f2u'
566 elif ctype == 'double':
567 if not self._ud_written:
568 self._ud_written = True
569 gen_union_var = True
570
571 union_name = 'd2u'
572
573 if gen_union_var:
574 # union for reading the bytes of the floating point number
575
576 self._cg.add_line('union {name} {name};'.format(name=union_name))
577 self._cg.add_empty_line()
578
579 self._cg.add_line('{}.f = {};'.format(union_name, var))
580 bf_var = '{}.u'.format(union_name)
581 else:
582 bf_var = '({}) {}'.format(ctype, var)
583
584 self._generate_bitfield_write(bf_var, ctx, t)
585 self._generate_incr_pos('{}->at'.format(ctx), t.size)
586
587 def _generate_serialize_enum(self, var, ctx, t):
588 self._generate_serialize_type(var, ctx, t.value_type)
589
590 def _generate_serialize_string(self, var, ctx, t):
591 tmpl = '_write_cstring({}, {});'.format(ctx, var)
592 self._cg.add_lines(tmpl)
593
594 def _generate_serialize_type(self, var, ctx, t):
595 self._type_to_generate_serialize_func[type(t)](var, ctx, t)
596 self._sasa.write_type(t)
597
598 def _generate_func_serialize_event_from_entity(self, prefix, t,
599 spec_src=None):
600 self._cg.add_line('{')
601 self._cg.indent()
602 self._cg.add_cc_line('align structure')
603 self._sasa.reset()
604 self._generate_align_type('ctx->at', t)
605
606 for field_name, field_type in t.fields.items():
607 src = prefix + field_name
608
609 if spec_src is not None:
610 if field_name in spec_src:
611 src = spec_src[field_name]
612
613 self._cg.add_empty_line()
614 self._generate_field_name_cc_line(field_name)
615 self._generate_align_type('ctx->at', field_type)
616 self._generate_serialize_type(src, 'ctx', field_type)
617
618 self._cg.unindent()
619 self._cg.add_line('}')
620 self._cg.add_empty_line()
621
622 def _generate_func_serialize_event(self, stream, event):
623 self._reset_per_func_state()
624 self._generate_func_serialize_event_proto(stream, event)
625 tmpl = templates._FUNC_SERIALIZE_EVENT_BODY_BEGIN
626 self._cg.add_lines(tmpl)
627 self._cg.indent()
628
629 if stream.event_header_type is not None:
630 t = stream.event_header_type
631 exclude_list = ['timestamp', 'id']
632 params = self._get_call_event_param_list_from_struct(t, _PREFIX_SEH,
633 exclude_list)
634 tmpl = '_serialize_stream_event_header_{sname}(ctx, {evid}{params});'
635 self._cg.add_cc_line('stream event header')
636 self._cg.add_line(tmpl.format(sname=stream.name, evid=event.id,
637 params=params))
638 self._cg.add_empty_line()
639
640 if stream.event_context_type is not None:
641 t = stream.event_context_type
642 params = self._get_call_event_param_list_from_struct(t, _PREFIX_SEC,
643 [])
644 tmpl = '_serialize_stream_event_context_{sname}(ctx{params});'
645 self._cg.add_cc_line('stream event context')
646 self._cg.add_line(tmpl.format(sname=stream.name, params=params))
647 self._cg.add_empty_line()
648
649 if event.context_type is not None:
650 self._cg.add_cc_line('event context')
651 self._generate_func_serialize_event_from_entity(_PREFIX_EC,
652 event.context_type)
653
654 if event.payload_type is not None:
655 self._cg.add_cc_line('event payload')
656 self._generate_func_serialize_event_from_entity(_PREFIX_EP,
657 event.payload_type)
658
659 self._cg.unindent()
660 tmpl = templates._FUNC_SERIALIZE_EVENT_BODY_END
661 self._cg.add_lines(tmpl)
662
663 def _generate_func_serialize_stream_event_header_proto(self, stream):
664 tmpl = templates._FUNC_SERIALIZE_STREAM_EVENT_HEADER_PROTO_BEGIN
665 self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix,
666 sname=stream.name))
667
668 if stream.event_header_type is not None:
669 exclude_list = [
670 'id',
671 'timestamp',
672 ]
673 self._generate_proto_params(stream.event_header_type,
674 _PREFIX_SEH, exclude_list)
675
676 tmpl = templates._FUNC_SERIALIZE_STREAM_EVENT_HEADER_PROTO_END
677 self._cg.add_lines(tmpl)
678
679 def _generate_func_serialize_stream_event_context_proto(self, stream):
680 tmpl = templates._FUNC_SERIALIZE_STREAM_EVENT_CONTEXT_PROTO_BEGIN
681 self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix,
682 sname=stream.name))
683
684 if stream.event_context_type is not None:
685 self._generate_proto_params(stream.event_context_type,
686 _PREFIX_SEC, [])
687
688 tmpl = templates._FUNC_SERIALIZE_STREAM_EVENT_CONTEXT_PROTO_END
689 self._cg.add_lines(tmpl)
690
691 def _generate_func_serialize_stream_event_header(self, stream):
692 self._reset_per_func_state()
693 self._generate_func_serialize_stream_event_header_proto(stream)
694 tmpl = templates._FUNC_SERIALIZE_STREAM_EVENT_HEADER_BODY_BEGIN
695 self._cg.add_lines(tmpl)
696 self._cg.indent()
697
698 if stream.event_header_type is not None:
699 if 'timestamp' in stream.event_header_type.fields:
700 timestamp = stream.event_header_type.fields['timestamp']
701 ts_ctype = self._get_int_ctype(timestamp)
702 clock = timestamp.property_mappings[0].object
703 clock_name = clock.name
704 clock_ctype = clock.return_ctype
705 tmpl = '{} ts = ctx->cbs.{}_clock_get_value(ctx->data);'
706 self._cg.add_line(tmpl.format(clock_ctype, clock_name))
707
708 self._cg.add_empty_line()
709 func = self._generate_func_serialize_event_from_entity
710
711 if stream.event_header_type is not None:
712 spec_src = {}
713
714 if 'id' in stream.event_header_type.fields:
715 id_t = stream.event_header_type.fields['id']
716 id_t_ctype = self._get_int_ctype(id_t)
717 spec_src['id'] = '({}) event_id'.format(id_t_ctype)
718
719 if 'timestamp' in stream.event_header_type.fields:
720 spec_src['timestamp'] = '({}) ts'.format(ts_ctype)
721
722 func(_PREFIX_SEH, stream.event_header_type, spec_src)
723
724 self._cg.unindent()
725 tmpl = templates._FUNC_SERIALIZE_STREAM_EVENT_HEADER_BODY_END
726 self._cg.add_lines(tmpl)
727
728 def _generate_func_serialize_stream_event_context(self, stream):
729 self._reset_per_func_state()
730 self._generate_func_serialize_stream_event_context_proto(stream)
731 tmpl = templates._FUNC_SERIALIZE_STREAM_EVENT_CONTEXT_BODY_BEGIN
732 self._cg.add_lines(tmpl)
733 self._cg.indent()
734 func = self._generate_func_serialize_event_from_entity
735
736 if stream.event_context_type is not None:
737 func(_PREFIX_SEC, stream.event_context_type)
738
739 self._cg.unindent()
740 tmpl = templates._FUNC_SERIALIZE_STREAM_EVENT_CONTEXT_BODY_END
741 self._cg.add_lines(tmpl)
742
743 def _generate_func_trace(self, stream, event):
744 self._reset_per_func_state()
745 self._generate_func_trace_proto(stream, event)
746 params = self._get_call_event_param_list(stream, event)
747 tmpl = templates._FUNC_TRACE_BODY
748 self._cg.add_lines(tmpl.format(sname=stream.name, evname=event.name,
749 params=params))
750
751 def _generate_func_init(self):
752 self._reset_per_func_state()
753 self._generate_func_init_proto()
754 tmpl = templates._FUNC_INIT_BODY
755 self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix))
756
757 def _generate_field_name_cc_line(self, field_name):
758 self._cg.add_cc_line('"{}" field'.format(field_name))
759
760 def _save_byte_offset(self, name):
761 self._saved_byte_offsets[name] = self._sasa.byte_offset
762
763 def _restore_byte_offset(self, name):
764 self._sasa.byte_offset = self._saved_byte_offsets[name]
765
766 def _reset_per_func_state(self):
767 self._uf_written = False
768 self._ud_written = False
769
770 def _generate_func_open(self, stream):
771 def generate_save_offset(name):
772 tmpl = 'ctx->off_spc_{} = ctx->parent.at;'.format(name)
773 self._cg.add_line(tmpl)
774 self._save_byte_offset(name)
775
776 self._reset_per_func_state()
777 self._generate_func_open_proto(stream)
778 tmpl = templates._FUNC_OPEN_BODY_BEGIN
779 self._cg.add_lines(tmpl)
780 self._cg.indent()
781 tph_type = self._cfg.metadata.trace.packet_header_type
782 spc_type = stream.packet_context_type
783
784 if spc_type is not None and 'timestamp_begin' in spc_type.fields:
785 field = spc_type.fields['timestamp_begin']
786 tmpl = '{} ts = ctx->parent.cbs.{}_clock_get_value(ctx->parent.data);'
787 clock = field.property_mappings[0].object
788 clock_ctype = clock.return_ctype
789 clock_name = clock.name
790 self._cg.add_line(tmpl.format(clock_ctype, clock_name))
791 self._cg.add_empty_line()
792
793 self._cg.add_cc_line('do not open a packet that is already open')
794 self._cg.add_line('if (ctx->parent.packet_is_open) {')
795 self._cg.indent()
796 self._cg.add_line('return;')
797 self._cg.unindent()
798 self._cg.add_line('}')
799 self._cg.add_empty_line()
800 self._cg.add_line('ctx->parent.at = 0;')
801
802 if tph_type is not None:
803 self._cg.add_empty_line()
804 self._cg.add_cc_line('trace packet header')
805 self._cg.add_line('{')
806 self._cg.indent()
807 self._cg.add_cc_line('align structure')
808 self._sasa.reset()
809 self._generate_align_type('ctx->parent.at', tph_type)
810
811 for field_name, field_type in tph_type.fields.items():
812 src = _PREFIX_TPH + field_name
813
814 if field_name == 'magic':
815 src = '0xc1fc1fc1UL'
816 elif field_name == 'stream_id':
817 stream_id_ctype = self._get_int_ctype(field_type)
818 src = '({}) {}'.format(stream_id_ctype, stream.id)
819 elif field_name == 'uuid':
820 self._cg.add_empty_line()
821 self._generate_field_name_cc_line(field_name)
822 self._cg.add_line('{')
823 self._cg.indent()
824 self._cg.add_line('static uint8_t uuid[] = {')
825 self._cg.indent()
826
827 for b in self._cfg.metadata.trace.uuid.bytes:
828 self._cg.add_line('{},'.format(b))
829
830 self._cg.unindent()
831 self._cg.add_line('};')
832 self._cg.add_empty_line()
833 self._generate_align('ctx->parent.at', 8)
834 line = 'memcpy(&ctx->parent.buf[_BITS_TO_BYTES(ctx->parent.at)], uuid, 16);'
835 self._cg.add_line(line)
836 self._generate_incr_pos_bytes('ctx->parent.at', 16)
837 self._cg.unindent()
838 self._cg.add_line('}')
839 self._sasa.reset()
840 continue
841
842 self._cg.add_empty_line()
843 self._generate_field_name_cc_line(field_name)
844 self._generate_align_type('ctx->parent.at', field_type)
845 self._generate_serialize_type(src, '(&ctx->parent)', field_type)
846
847 self._cg.unindent()
848 self._cg.add_lines('}')
849
850 if spc_type is not None:
851 self._cg.add_empty_line()
852 self._cg.add_cc_line('stream packet context')
853 self._cg.add_line('{')
854 self._cg.indent()
855 self._cg.add_cc_line('align structure')
856 self._sasa.reset()
857 self._generate_align_type('ctx->parent.at', spc_type)
858 tmpl_off = 'off_spc_{fname}'
859
860 for field_name, field_type in spc_type.fields.items():
861 src = _PREFIX_SPC + field_name
862 skip_int = False
863 self._cg.add_empty_line()
864 self._generate_field_name_cc_line(field_name)
865
866 if field_name == 'timestamp_begin':
867 ctype = self._get_type_ctype(field_type)
868 src = '({}) ts'.format(ctype)
869 elif field_name in ['timestamp_end', 'content_size',
870 'events_discarded']:
871 skip_int = True
872 elif field_name == 'packet_size':
873 ctype = self._get_type_ctype(field_type)
874 src = '({}) ctx->parent.packet_size'.format(ctype)
875
876 self._generate_align_type('ctx->parent.at', field_type)
877
878 if skip_int:
879 generate_save_offset(field_name)
880 self._generate_incr_pos('ctx->parent.at', field_type.size)
881 self._sasa.write_type(field_type)
882 else:
883 self._generate_serialize_type(src, '(&ctx->parent)',
884 field_type)
885
886 self._cg.unindent()
887 self._cg.add_lines('}')
888
889 self._cg.unindent()
890 tmpl = templates._FUNC_OPEN_BODY_END
891 self._cg.add_lines(tmpl)
892
893 def _generate_func_close(self, stream):
894 def generate_goto_offset(name):
895 tmpl = 'ctx->parent.at = ctx->off_spc_{};'.format(name)
896 self._cg.add_line(tmpl)
897
898 self._reset_per_func_state()
899 self._generate_func_close_proto(stream)
900 tmpl = templates._FUNC_CLOSE_BODY_BEGIN
901 self._cg.add_lines(tmpl)
902 self._cg.indent()
903 spc_type = stream.packet_context_type
904
905 if spc_type is not None:
906 if 'timestamp_end' in spc_type.fields:
907 tmpl = '{} ts = ctx->parent.cbs.{}_clock_get_value(ctx->parent.data);'
908 field = spc_type.fields['timestamp_end']
909 clock = field.property_mappings[0].object
910 clock_ctype = clock.return_ctype
911 clock_name = clock.name
912 self._cg.add_line(tmpl.format(clock_ctype, clock_name))
913 self._cg.add_empty_line()
914
915 self._cg.add_cc_line('do not close a packet that is not open')
916 self._cg.add_line('if (!ctx->parent.packet_is_open) {')
917 self._cg.indent()
918 self._cg.add_line('return;')
919 self._cg.unindent()
920 self._cg.add_line('}')
921 self._cg.add_empty_line()
922 self._cg.add_cc_line('save content size')
923 self._cg.add_line('ctx->parent.content_size = ctx->parent.at;')
924
925 if spc_type is not None:
926 field_name = 'timestamp_end'
927
928 if field_name in spc_type.fields:
929 t = spc_type.fields[field_name]
930 ctype = self._get_type_ctype(t)
931 src = '({}) ts'.format(ctype)
932 self._cg.add_empty_line()
933 self._generate_field_name_cc_line(field_name)
934 generate_goto_offset(field_name)
935 self._restore_byte_offset(field_name)
936 self._generate_serialize_type(src, '(&ctx->parent)', t)
937
938 field_name = 'content_size'
939
940 if 'content_size' in spc_type.fields:
941 t = spc_type.fields[field_name]
942 ctype = self._get_type_ctype(t)
943 src = '({}) ctx->parent.content_size'.format(ctype)
944 self._cg.add_empty_line()
945 self._generate_field_name_cc_line(field_name)
946 generate_goto_offset(field_name)
947 self._restore_byte_offset(field_name)
948 self._generate_serialize_type(src, '(&ctx->parent)', t)
949
950 field_name = 'events_discarded'
951
952 if field_name in spc_type.fields:
953 t = spc_type.fields[field_name]
954 ctype = self._get_type_ctype(t)
955 src = '({}) ctx->parent.events_discarded'.format(ctype)
956 self._cg.add_empty_line()
957 self._generate_field_name_cc_line(field_name)
958 generate_goto_offset(field_name)
959 self._restore_byte_offset(field_name)
960 self._generate_serialize_type(src, '(&ctx->parent)', t)
961
962 self._cg.unindent()
963 tmpl = templates._FUNC_CLOSE_BODY_END
964 self._cg.add_lines(tmpl)
965 self._sasa.reset()
966
967 def generate_c_src(self):
968 self._cg.reset()
969 dt = datetime.datetime.now().isoformat()
970 header_filename = self.get_header_filename()
971 tmpl = templates._C_SRC
972 self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix,
973 header_filename=header_filename,
974 version=barectf.__version__, date=dt))
975 self._cg.add_empty_line()
976
977 # initialization function
978 self._generate_func_init()
979 self._cg.add_empty_line()
980
981 for stream in self._cfg.metadata.streams.values():
982 self._generate_func_open(stream)
983 self._cg.add_empty_line()
984 self._generate_func_close(stream)
985 self._cg.add_empty_line()
986
987 if stream.event_header_type is not None:
988 self._generate_func_serialize_stream_event_header(stream)
989 self._cg.add_empty_line()
990
991 if stream.event_context_type is not None:
992 self._generate_func_serialize_stream_event_context(stream)
993 self._cg.add_empty_line()
994
995 for ev in stream.events.values():
996 self._generate_func_get_event_size(stream, ev)
997 self._cg.add_empty_line()
998 self._generate_func_serialize_event(stream, ev)
999 self._cg.add_empty_line()
1000 self._generate_func_trace(stream, ev)
1001 self._cg.add_empty_line()
1002
1003
1004 return self._cg.code
1005
1006 def get_header_filename(self):
1007 return '{}.h'.format(self._cfg.prefix.rstrip('_'))
1008
1009 def get_bitfield_header_filename(self):
1010 return '{}-bitfield.h'.format(self._cfg.prefix.rstrip('_'))
This page took 0.059672 seconds and 5 git commands to generate.