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