_CCodeGenerator.generate_c_src(): use Jinja 2 templates
[deliverable/barectf.git] / barectf / gen.py
CommitLineData
e5aa0be3
PP
1# The MIT License (MIT)
2#
4a90140d 3# Copyright (c) 2014-2020 Philippe Proulx <pproulx@efficios.com>
e5aa0be3 4#
1378f213
PP
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:
e5aa0be3 12#
1378f213
PP
13# The above copyright notice and this permission notice shall be
14# included in all copies or substantial portions of the Software.
e5aa0be3 15#
1378f213
PP
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.
e5aa0be3 23
4810b707 24import barectf.tsdl182gen as barectf_tsdl182gen
8c7c6ed2 25import barectf.template as barectf_template
4810b707
PP
26import barectf.config as barectf_config
27import barectf.version as barectf_version
acfb8213 28import itertools
e5aa0be3 29import datetime
d6483c83 30import collections
acfb8213 31import copy
4810b707
PP
32
33
d6483c83
PP
34# A file generated by a `CodeGenerator` object.
35#
36# A generated file has a name (influenced by the configuration's
37# file name prefix option) and contents.
4810b707
PP
38class _GeneratedFile:
39 def __init__(self, name, contents):
40 self._name = name
41 self._contents = contents
42
43 @property
44 def name(self):
45 return self._name
46
47 @property
48 def contents(self):
49 return self._contents
50
51
d6483c83
PP
52# A barectf code generator.
53#
54# Build a code generator with a barectf configuration.
55#
56# A code generator can generate the TSDL `metadata` file and C source
57# and header files.
4810b707
PP
58class CodeGenerator:
59 def __init__(self, configuration):
60 self._config = configuration
61 self._file_name_prefix = configuration.options.code_generation_options.file_name_prefix
62 self._ccode_gen = _CCodeGenerator(configuration)
63 self._c_headers = None
64 self._c_sources = None
65 self._metadata_stream = None
66
67 @property
68 def _barectf_header_name(self):
69 return f'{self._file_name_prefix}.h'
70
7db1a1f5
PP
71 @property
72 def _bitfield_header_name(self):
73 return f'{self._file_name_prefix}-bitfield.h'
74
4810b707
PP
75 def generate_c_headers(self):
76 if self._c_headers is None:
4810b707 77 self._c_headers = [
7db1a1f5
PP
78 _GeneratedFile(self._barectf_header_name, self._ccode_gen.generate_header()),
79 _GeneratedFile(self._bitfield_header_name, self._ccode_gen.generate_bitfield_header()),
4810b707
PP
80 ]
81
82 return self._c_headers
83
84 def generate_c_sources(self):
85 if self._c_sources is None:
86 self._c_sources = [
87 _GeneratedFile(f'{self._file_name_prefix}.c',
7db1a1f5
PP
88 self._ccode_gen.generate_c_src(self._barectf_header_name,
89 self._bitfield_header_name))
4810b707
PP
90 ]
91
92 return self._c_sources
93
94 def generate_metadata_stream(self):
95 if self._metadata_stream is None:
96 self._metadata_stream = _GeneratedFile('metadata',
97 barectf_tsdl182gen._from_config(self._config))
98
99 return self._metadata_stream
e5aa0be3
PP
100
101
d6483c83
PP
102# A tuple containing serialization and size computation function
103# templates for a given operation.
104_OpTemplates = collections.namedtuple('_OpTemplates', ['serialize', 'size'])
70e191bd
PP
105
106
d6483c83
PP
107# Base class of any operation within source code.
108#
109# Any operation has:
110#
111# * An offset at which to start to write within the current byte.
112#
113# * A field type.
114#
115# * A list of names which, when joined with `_`, form the generic C
116# source variable name.
117#
118# * Serialization and size computation templates to generate the
119# operation's source code for those functions.
120class _Op:
121 def __init__(self, offset_in_byte, ft, names, templates):
acfb8213
PP
122 assert(offset_in_byte >= 0 and offset_in_byte < 8)
123 self._offset_in_byte = offset_in_byte
4810b707 124 self._ft = ft
d6483c83
PP
125 self._names = copy.copy(names)
126 self._templates = templates
e5aa0be3
PP
127
128 @property
acfb8213
PP
129 def offset_in_byte(self):
130 return self._offset_in_byte
e5aa0be3 131
acfb8213 132 @property
4810b707
PP
133 def ft(self):
134 return self._ft
acfb8213
PP
135
136 @property
137 def names(self):
138 return self._names
e5aa0be3 139
d6483c83
PP
140 @property
141 def top_name(self):
142 return self._names[-1]
e5aa0be3 143
d6483c83
PP
144 def _render_template(self, templ, **kwargs):
145 return templ.render(op=self, root_ft_prefixes=_RootFtPrefixes,
146 root_ft_prefix_names=_ROOT_FT_PREFIX_NAMES, **kwargs)
147
148 def serialize_str(self, **kwargs):
149 return self._render_template(self._templates.serialize, **kwargs)
150
151 def size_str(self, **kwargs):
152 return self._render_template(self._templates.size, **kwargs)
153
154
155# An "align" operation.
156class _AlignOp(_Op):
157 def __init__(self, offset_in_byte, ft, names, templates, value):
158 super().__init__(offset_in_byte, ft, names, templates)
acfb8213 159 self._value = value
e5aa0be3 160
acfb8213
PP
161 @property
162 def value(self):
163 return self._value
e5aa0be3 164
e5aa0be3 165
d6483c83
PP
166# A "write" operation.
167class _WriteOp(_Op):
4810b707 168 pass
70e191bd 169
e5aa0be3 170
d6483c83
PP
171# A builder of a chain of operations.
172#
173# Such a builder is closely connected to a `_CCodeGenerator` object
174# using it to find generic templates.
175#
176# Call append_root_ft() to make an operation builder append operations
177# to itself for each member, recursively, of the structure field type.
178#
179# Get an operation builder's operations with its `ops` property.
180class _OpsBuilder:
181 def __init__(self, cg):
acfb8213
PP
182 self._last_alignment = None
183 self._last_bit_array_size = None
d6483c83 184 self._ops = []
acfb8213
PP
185 self._names = []
186 self._offset_in_byte = 0
d6483c83 187 self._cg = cg
acfb8213 188
d6483c83
PP
189 @property
190 def ops(self):
191 return self._ops
192
193 # Creates and appends the operations for the members, recursively,
194 # of the root structure field type `ft` named `name`.
195 #
196 # `spec_serialize_write_templates` is a mapping of first level
197 # member names to specialized serialization "write" templates.
198 def append_root_ft(self, ft, name, spec_serialize_write_templates=None):
4810b707 199 if ft is None:
acfb8213 200 return
e5aa0be3 201
d6483c83
PP
202 if spec_serialize_write_templates is None:
203 spec_serialize_write_templates = {}
204
205 assert type(ft) is barectf_config.StructureFieldType
206 assert len(self._names) == 0
207 self._append_ft(ft, name, spec_serialize_write_templates)
208
209 # Creates and appends the operations of a given field type `ft`
210 # named `name`.
211 #
212 # See append_root_ft() for `spec_serialize_write_templates`.
213 def _append_ft(self, ft, name, spec_serialize_write_templates):
214 def top_name():
215 return self._names[-1]
216
217 # Appends a "write" operation for the field type `ft`.
218 #
219 # This function considers `spec_serialize_write_templates` to
220 # override generic templates.
221 def append_write_op(ft):
222 assert type(ft) is not barectf_config.StructureFieldType
223 offset_in_byte = self._offset_in_byte
224
225 if isinstance(ft, barectf_config._BitArrayFieldType):
226 self._offset_in_byte += ft.size
227 self._offset_in_byte %= 8
228
229 serialize_write_templ = None
230
231 if len(self._names) == 2:
232 serialize_write_templ = spec_serialize_write_templates.get(top_name())
233
234 if serialize_write_templ is None:
235 if isinstance(ft, barectf_config._IntegerFieldType):
236 serialize_write_templ = self._cg._serialize_write_int_statements_templ
237 elif type(ft) is barectf_config.RealFieldType:
238 serialize_write_templ = self._cg._serialize_write_real_statements_templ
239 else:
240 assert type(ft) is barectf_config.StringFieldType
241 serialize_write_templ = self._cg._serialize_write_string_statements_templ
242
243 size_write_templ = None
e5aa0be3 244
d6483c83
PP
245 if isinstance(ft, barectf_config._BitArrayFieldType):
246 size_write_templ = self._cg._size_write_bit_array_statements_templ
247 elif type(ft) is barectf_config.StringFieldType:
248 size_write_templ = self._cg._size_write_string_statements_templ
249
250 self._ops.append(_WriteOp(offset_in_byte, ft, self._names,
251 _OpTemplates(serialize_write_templ, size_write_templ)))
252
253 # Creates and appends an "align" operation for the field type
254 # `ft` if needed.
255 #
256 # This function updates the builder's state.
257 def try_append_align_op(alignment, do_align, ft):
258 def align(v, alignment):
259 return (v + (alignment - 1)) & -alignment
260
261 offset_in_byte = self._offset_in_byte
262 self._offset_in_byte = align(self._offset_in_byte, alignment) % 8
263
264 if do_align and alignment > 1:
265 self._ops.append(_AlignOp(offset_in_byte, ft, self._names,
266 _OpTemplates(self._cg._serialize_align_statements_templ,
267 self._cg._size_align_statements_templ),
268 alignment))
acfb8213 269
d6483c83
PP
270 # Returns whether or not, considering the alignment requirement
271 # `align_req` and the builder's current state, we must create
272 # and append an "align" operation.
273 def must_align(align_req):
274 return self._last_alignment != align_req or self._last_bit_array_size % align_req != 0
acfb8213 275
d6483c83
PP
276 # push field type's name to the builder's name stack initially
277 self._names.append(name)
acfb8213 278
4810b707 279 if isinstance(ft, (barectf_config.StringFieldType, barectf_config._ArrayFieldType)):
d6483c83
PP
280 assert type(ft) is barectf_config.StringFieldType or top_name() == 'uuid'
281
282 # strings and arrays are always byte-aligned
283 do_align = must_align(8)
acfb8213
PP
284 self._last_alignment = 8
285 self._last_bit_array_size = 8
d6483c83
PP
286 try_append_align_op(8, do_align, ft)
287 append_write_op(ft)
4810b707 288 else:
d6483c83 289 do_align = must_align(ft.alignment)
4810b707
PP
290 self._last_alignment = ft.alignment
291
292 if type(ft) is barectf_config.StructureFieldType:
293 self._last_bit_array_size = ft.alignment
acfb8213 294 else:
4810b707 295 self._last_bit_array_size = ft.size
70e191bd 296
d6483c83 297 try_append_align_op(ft.alignment, do_align, ft)
70e191bd 298
4810b707
PP
299 if type(ft) is barectf_config.StructureFieldType:
300 for member_name, member in ft.members.items():
d6483c83 301 self._append_ft(member.field_type, member_name, spec_serialize_write_templates)
70e191bd 302 else:
d6483c83
PP
303 append_write_op(ft)
304
305 # exiting for this field type: pop its name
306 del self._names[-1]
70e191bd 307
70e191bd 308
d6483c83
PP
309# The operations for an event.
310#
311# The available operations are:
312#
313# * Specific context operations.
314# * Payload operations.
315class _EventOps:
316 def __init__(self, spec_ctx_ops, payload_ops):
317 self._spec_ctx_ops = copy.copy(spec_ctx_ops)
318 self._payload_ops = copy.copy(payload_ops)
70e191bd 319
d6483c83
PP
320 @property
321 def spec_ctx_ops(self):
322 return self._spec_ctx_ops
acfb8213 323
d6483c83
PP
324 @property
325 def payload_ops(self):
326 return self._payload_ops
acfb8213 327
70e191bd 328
d6483c83
PP
329# The operations for a stream.
330#
331# The available operations are:
332#
333# * Packet header operations.
334# * Packet context operations.
335# * Event header operations.
336# * Event common context operations.
337# * Event operations (`_EventOps`).
338class _StreamOps:
339 def __init__(self, pkt_header_ops, pkt_ctx_ops, ev_header_ops,
340 ev_common_ctx_ops, ev_ops):
341 self._pkt_header_ops = copy.copy(pkt_header_ops)
342 self._pkt_ctx_ops = copy.copy(pkt_ctx_ops)
343 self._ev_header_ops = copy.copy(ev_header_ops)
344 self._ev_common_ctx_ops = copy.copy(ev_common_ctx_ops)
345 self._ev_ops = copy.copy(ev_ops)
70e191bd 346
d6483c83
PP
347 @property
348 def pkt_header_ops(self):
349 return self._pkt_header_ops
350
351 @property
352 def pkt_ctx_ops(self):
353 return self._pkt_ctx_ops
354
355 @property
356 def ev_header_ops(self):
357 return self._ev_header_ops
358
359 @property
360 def ev_common_ctx_ops(self):
361 return self._ev_common_ctx_ops
362
363 @property
364 def ev_ops(self):
365 return self._ev_ops
366
367
368# The C variable name prefixes for the six kinds of root field types.
1b49c7b8 369class _RootFtPrefixes:
d6483c83
PP
370 TPH = 'tph'
371 SPC = 'spc'
372 SEH = 'seh'
373 SEC = 'sec'
374 EC = 'ec'
375 EP = 'ep'
376
377
378# The human-readable names of the `_RootFtPrefixes` members.
379_ROOT_FT_PREFIX_NAMES = {
380 _RootFtPrefixes.TPH: 'packet header',
381 _RootFtPrefixes.SPC: 'packet context',
382 _RootFtPrefixes.SEH: 'event header',
383 _RootFtPrefixes.SEC: 'event common context',
384 _RootFtPrefixes.EC: 'specific context',
385 _RootFtPrefixes.EP: 'payload',
acfb8213 386}
e5aa0be3
PP
387
388
d6483c83
PP
389# A named function parameter for a given field type.
390_FtParam = collections.namedtuple('_FtParam', ['ft', 'name'])
391
392
393# A C code generator.
394#
395# Such a code generator can generate:
396#
397# * The bitfield header (generate_bitfield_header()).
398# * The public header (generate_header()).
399# * The source code (generate_c_src()).
4810b707 400class _CCodeGenerator:
e5aa0be3
PP
401 def __init__(self, cfg):
402 self._cfg = cfg
d6483c83
PP
403 self._iden_prefix = cfg.options.code_generation_options.identifier_prefix
404 self._saved_serialization_ops = {}
405 self._templ_filters = {
406 'ft_c_type': self._ft_c_type,
407 'open_func_params_str': self._open_func_params_str,
408 'trace_func_params_str': self._trace_func_params_str,
409 'serialize_ev_common_ctx_func_params_str': self._serialize_ev_common_ctx_func_params_str,
1b49c7b8 410 }
d6483c83
PP
411 self._func_proto_params_templ = self._create_template('func-proto-params.j2')
412 self._serialize_align_statements_templ = self._create_template('serialize-align-statements.j2')
413 self._serialize_write_int_statements_templ = self._create_template('serialize-write-int-statements.j2')
414 self._serialize_write_real_statements_templ = self._create_template('serialize-write-real-statements.j2')
415 self._serialize_write_string_statements_templ = self._create_template('serialize-write-string-statements.j2')
416 self._serialize_write_magic_statements_templ = self._create_template('serialize-write-magic-statements.j2')
417 self._serialize_write_uuid_statements_templ = self._create_template('serialize-write-uuid-statements.j2')
418 self._serialize_write_stream_type_id_statements_templ = self._create_template('serialize-write-stream-type-id-statements.j2')
419 self._serialize_write_time_statements_templ = self._create_template('serialize-write-time-statements.j2')
420 self._serialize_write_packet_size_statements_templ = self._create_template('serialize-write-packet-size-statements.j2')
421 self._serialize_write_skip_save_statements_templ = self._create_template('serialize-write-skip-save-statements.j2')
422 self._serialize_write_ev_type_id_statements_templ = self._create_template('serialize-write-ev-type-id-statements.j2')
423 self._size_align_statements_templ = self._create_template('size-align-statements.j2')
424 self._size_write_bit_array_statements_templ = self._create_template('size-write-bit-array-statements.j2')
425 self._size_write_string_statements_templ = self._create_template('size-write-string-statements.j2')
426
427 # Creates and returns a template named `name` which is a file
428 # template if `is_file_template` is `True`.
429 #
430 # `name` is the file name, including the `.j2` extension, within the
431 # `c` directory.
432 #
433 # Such a template has the filters custom filters
434 # `self._templ_filters`.
435 def _create_template_base(self, name: str, is_file_template: bool):
436 return barectf_template._Template(f'c/{name}', is_file_template, self._cfg,
437 self._templ_filters)
438
439 # Creates and returns a non-file template named `name`.
440 #
441 # See _create_template_base() for `name`.
8c7c6ed2 442 def _create_template(self, name: str) -> barectf_template._Template:
d6483c83 443 return self._create_template_base(name, False)
8c7c6ed2 444
d6483c83
PP
445 # Creates and returns a file template named `name`.
446 #
447 # See _create_template_base() for `name`.
8c7c6ed2 448 def _create_file_template(self, name: str) -> barectf_template._Template:
d6483c83 449 return self._create_template_base(name, True)
8c7c6ed2 450
d6483c83 451 # Trace type of this code generator's barectf configuration.
4810b707
PP
452 @property
453 def _trace_type(self):
454 return self._cfg.trace.type
27bc6f1e 455
d6483c83
PP
456 # Returns the C type for the field type `ft`.
457 def _ft_c_type(self, ft):
4810b707
PP
458 if isinstance(ft, barectf_config._IntegerFieldType):
459 sign_prefix = 'u' if isinstance(ft, barectf_config.UnsignedIntegerFieldType) else ''
460
461 if ft.size <= 8:
462 sz = 8
463 elif ft.size <= 16:
464 sz = 16
465 elif ft.size <= 32:
466 sz = 32
467 else:
d6483c83 468 assert ft.size <= 64
4810b707
PP
469 sz = 64
470
471 return f'{sign_prefix}int{sz}_t'
472 elif type(ft) is barectf_config.RealFieldType:
473 if ft.size == 32 and ft.alignment == 32:
474 return 'float'
475 elif ft.size == 64 and ft.alignment == 64:
476 return 'double'
477 else:
478 return 'uint64_t'
e5aa0be3 479 else:
4810b707
PP
480 assert type(ft) is barectf_config.StringFieldType
481 return 'const char *'
e5aa0be3 482
d6483c83
PP
483 # Returns the function prototype parameters for the members of the
484 # root structure field type `root_ft`.
485 #
486 # Each parameter has the prefix `name_prefix` followed with `_`.
487 #
488 # Members of which the name is in `exclude_set` are excluded.
489 def _proto_params_str(self, root_ft, name_prefix, exclude_set=None):
490 if root_ft is None:
491 return
e5aa0be3 492
4810b707
PP
493 if exclude_set is None:
494 exclude_set = set()
495
d6483c83 496 params = []
e5aa0be3 497
d6483c83 498 for member_name, member in root_ft.members.items():
4810b707 499 if member_name in exclude_set:
e5aa0be3
PP
500 continue
501
d6483c83 502 params.append(_FtParam(member.field_type, member_name))
e5aa0be3 503
d6483c83 504 return self._func_proto_params_templ.render(params=params, prefix=name_prefix)
4810b707 505
d6483c83
PP
506 # Returns the packet opening function prototype parameters for the
507 # stream type `stream_type`.
508 def _open_func_params_str(self, stream_type):
509 parts = []
510 parts.append(self._proto_params_str(self._trace_type._pkt_header_ft, _RootFtPrefixes.TPH,
511 {'magic', 'stream_id', 'uuid'}))
e5aa0be3 512
4810b707
PP
513 exclude_set = {
514 'timestamp_begin',
515 'timestamp_end',
516 'packet_size',
517 'content_size',
518 'events_discarded',
519 }
d6483c83
PP
520 parts.append(self._proto_params_str(stream_type._pkt_ctx_ft, _RootFtPrefixes.SPC,
521 exclude_set))
522 return ''.join(parts)
e5aa0be3 523
d6483c83
PP
524 # Returns the tracing function prototype parameters for the stream
525 # and event types `stream_ev_types`.
526 def _trace_func_params_str(self, stream_ev_types):
527 stream_type = stream_ev_types[0]
528 ev_type = stream_ev_types[1]
529 parts = []
e5aa0be3 530
4810b707 531 if stream_type._ev_header_ft is not None:
d6483c83
PP
532 parts.append(self._proto_params_str(stream_type._ev_header_ft, _RootFtPrefixes.SEH,
533 {'id', 'timestamp'}))
4810b707
PP
534
535 if stream_type.event_common_context_field_type is not None:
d6483c83
PP
536 parts.append(self._proto_params_str(stream_type.event_common_context_field_type,
537 _RootFtPrefixes.SEC))
4810b707
PP
538
539 if ev_type.specific_context_field_type is not None:
d6483c83
PP
540 parts.append(self._proto_params_str(ev_type.specific_context_field_type,
541 _RootFtPrefixes.EC))
4810b707
PP
542
543 if ev_type.payload_field_type is not None:
d6483c83 544 parts.append(self._proto_params_str(ev_type.payload_field_type, _RootFtPrefixes.EP))
e5aa0be3 545
d6483c83 546 return ''.join(parts)
4810b707 547
d6483c83
PP
548 # Returns the event header serialization function prototype
549 # parameters for the stream type `stream_type`.
550 def _serialize_ev_common_ctx_func_params_str(self, stream_type):
551 return self._proto_params_str(stream_type.event_common_context_field_type,
552 _RootFtPrefixes.SEC);
e5aa0be3 553
d6483c83
PP
554 # Generates the bitfield header file contents.
555 def generate_bitfield_header(self):
556 return self._create_file_template('bitfield.h.j2').render()
e5aa0be3 557
d6483c83
PP
558 # Generates the public header file contents.
559 def generate_header(self):
560 return self._create_file_template('barectf.h.j2').render(root_ft_prefixes=_RootFtPrefixes)
3cb793a1 561
d6483c83
PP
562 # Generates the source code file contents.
563 def generate_c_src(self, header_file_name, bitfield_header_file_name):
564 # Creates and returns the operations for all the stream and for
565 # all their events.
566 def create_stream_ops():
567 stream_ser_ops = {}
568
569 for stream_type in self._trace_type.stream_types:
570 pkt_header_ser_ops = []
571 builder = _OpsBuilder(self)
572 pkt_header_ft = self._trace_type._pkt_header_ft
573
574 # packet header serialization operations
575 if pkt_header_ft is not None:
576 spec_serialize_write_templates = {
577 'magic': self._serialize_write_magic_statements_templ,
578 'uuid': self._serialize_write_uuid_statements_templ,
579 'stream_id': self._serialize_write_stream_type_id_statements_templ,
580 }
581 builder.append_root_ft(pkt_header_ft, _RootFtPrefixes.TPH,
582 spec_serialize_write_templates)
583 pkt_header_ser_ops = copy.copy(builder.ops)
584
585 # packet context serialization operations
586 first_op_index = len(builder.ops)
587 spec_serialize_write_templates = {
588 'timestamp_begin': self._serialize_write_time_statements_templ,
589 'packet_size': self._serialize_write_packet_size_statements_templ,
590 'timestamp_end': self._serialize_write_skip_save_statements_templ,
591 'events_discarded': self._serialize_write_skip_save_statements_templ,
592 'content_size': self._serialize_write_skip_save_statements_templ,
593 }
594 builder.append_root_ft(stream_type._pkt_ctx_ft, _RootFtPrefixes.SPC,
595 spec_serialize_write_templates)
596 pkt_ctx_ser_ops = copy.copy(builder.ops[first_op_index:])
597
598 # event header serialization operations
599 builder = _OpsBuilder(self)
600 ev_header_ser_ops = []
601
602 if stream_type._ev_header_ft is not None:
603 spec_serialize_write_templates = {
604 'timestamp': self._serialize_write_time_statements_templ,
605 'id': self._serialize_write_ev_type_id_statements_templ,
606 }
607 builder.append_root_ft(stream_type._ev_header_ft, _RootFtPrefixes.SEH,
608 spec_serialize_write_templates)
609 ev_header_ser_ops = copy.copy(builder.ops)
610
611 # event common context serialization operations
612 ev_common_ctx_ser_ops = []
613
614 if stream_type.event_common_context_field_type is not None:
615 first_op_index = len(builder.ops)
616 builder.append_root_ft(stream_type.event_common_context_field_type,
617 _RootFtPrefixes.SEC)
618 ev_common_ctx_ser_ops = copy.copy(builder.ops[first_op_index:])
619
620 # serialization operations specific to each event type
621 ev_ser_ops = {}
622
623 for ev_type in stream_type.event_types:
624 ev_builder = copy.copy(builder)
625
626 # specific context serialization operations
627 spec_ctx_ser_ops = []
628
629 if ev_type.specific_context_field_type is not None:
630 first_op_index = len(ev_builder.ops)
631 ev_builder.append_root_ft(ev_type.specific_context_field_type,
632 _RootFtPrefixes.EC)
633 spec_ctx_ser_ops = copy.copy(ev_builder.ops[first_op_index:])
634
635 # payload serialization operations
636 payload_ser_ops = []
637
638 if ev_type.payload_field_type is not None:
639 first_op_index = len(ev_builder.ops)
640 ev_builder.append_root_ft(ev_type.payload_field_type, _RootFtPrefixes.EP)
641 payload_ser_ops = copy.copy(ev_builder.ops[first_op_index:])
642
643 ev_ser_ops[ev_type] = _EventOps(spec_ctx_ser_ops, payload_ser_ops)
644
645 stream_ser_ops[stream_type] = _StreamOps(pkt_header_ser_ops, pkt_ctx_ser_ops,
646 ev_header_ser_ops, ev_common_ctx_ser_ops,
647 ev_ser_ops)
648
649 return stream_ser_ops
650
651 # Returns the "write" operation for the packet context member
652 # named `member_name` within the stream type `stream_type`.
653 def stream_op_pkt_ctx_op(stream_type, member_name):
654 for op in stream_ops[stream_type].pkt_ctx_ops:
655 if op.top_name == member_name and type(op) is _WriteOp:
656 return op
657
658 stream_ops = create_stream_ops()
659 return self._create_file_template('barectf.c.j2').render(header_file_name=header_file_name,
660 bitfield_header_file_name=bitfield_header_file_name,
661 root_ft_prefixes=_RootFtPrefixes,
662 root_ft_prefix_names=_ROOT_FT_PREFIX_NAMES,
663 stream_ops=stream_ops,
664 stream_op_pkt_ctx_op=stream_op_pkt_ctx_op)
This page took 0.054844 seconds and 4 git commands to generate.