Commit | Line | Data |
---|---|---|
e5aa0be3 PP |
1 | # The MIT License (MIT) |
2 | # | |
3 | # Copyright (c) 2014-2015 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 | class _StaticAlignSizeAutomaton: | |
36 | def __init__(self): | |
37 | self._byte_offset = 0 | |
38 | self._type_to_update_byte_offset_func = { | |
39 | metadata.Integer: self.write_static_size, | |
40 | metadata.FloatingPoint: self.write_static_size, | |
41 | metadata.Enum: self.write_static_size, | |
42 | metadata.String: self.reset, | |
43 | } | |
44 | ||
45 | @property | |
46 | def byte_offset(self): | |
47 | return self._byte_offset | |
48 | ||
49 | @byte_offset.setter | |
50 | def byte_offset(self, value): | |
51 | self._byte_offset = value | |
52 | ||
53 | def _wrap_byte_offset(self): | |
54 | self._byte_offset %= 8 | |
55 | ||
56 | def align(self, align): | |
57 | # align byte offset | |
58 | self._byte_offset = (self._byte_offset + (align - 1)) & -align | |
59 | ||
60 | # wrap on current byte | |
61 | self._wrap_byte_offset() | |
62 | ||
63 | def write_type(self, t): | |
64 | self._type_to_update_byte_offset_func[type(t)](t) | |
65 | ||
66 | def write_static_size(self, t): | |
67 | # increment byte offset | |
68 | self._byte_offset += t.size | |
69 | ||
70 | # wrap on current byte | |
71 | self._wrap_byte_offset() | |
72 | ||
73 | def reset(self, t=None): | |
74 | # reset byte offset (strings are always byte-aligned) | |
75 | self._byte_offset = 0 | |
76 | ||
77 | def set_unknown(self): | |
78 | self._byte_offset = None | |
79 | ||
80 | ||
81 | _PREFIX_TPH = 'tph_' | |
82 | _PREFIX_SPC = 'spc_' | |
83 | _PREFIX_SEH = 'seh_' | |
84 | _PREFIX_SEC = 'sec_' | |
85 | _PREFIX_EC = 'ec_' | |
86 | _PREFIX_EP = 'ep_' | |
87 | ||
88 | ||
89 | class CCodeGenerator: | |
90 | def __init__(self, cfg): | |
91 | self._cfg = cfg | |
92 | self._cg = barectf.codegen.CodeGenerator('\t') | |
93 | self._type_to_get_ctype_func = { | |
94 | metadata.Integer: self._get_int_ctype, | |
95 | metadata.FloatingPoint: self._get_float_ctype, | |
96 | metadata.Enum: self._get_enum_ctype, | |
97 | metadata.String: self._get_string_ctype, | |
98 | } | |
99 | self._type_to_generate_serialize_func = { | |
100 | metadata.Integer: self._generate_serialize_int, | |
101 | metadata.FloatingPoint: self._generate_serialize_float, | |
102 | metadata.Enum: self._generate_serialize_enum, | |
103 | metadata.String: self._generate_serialize_string, | |
104 | } | |
105 | self._saved_byte_offsets = {} | |
106 | self._sasa = _StaticAlignSizeAutomaton() | |
107 | ||
108 | def _generate_ctx_parent(self): | |
109 | tmpl = templates._CTX_PARENT | |
110 | self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix)) | |
111 | ||
112 | def _generate_ctx(self, stream): | |
113 | tmpl = templates._CTX_BEGIN | |
114 | self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix, | |
115 | sname=stream.name)) | |
116 | tmpl = 'uint32_t off_tph_{fname};' | |
117 | self._cg.indent() | |
118 | trace_packet_header_type = self._cfg.metadata.trace.packet_header_type | |
119 | ||
120 | if trace_packet_header_type is not None: | |
121 | for field_name in trace_packet_header_type.fields: | |
122 | self._cg.add_lines(tmpl.format(fname=field_name)) | |
123 | ||
124 | tmpl = 'uint32_t off_spc_{fname};' | |
125 | ||
126 | if stream.packet_context_type is not None: | |
127 | for field_name in stream.packet_context_type.fields: | |
128 | self._cg.add_lines(tmpl.format(fname=field_name)) | |
129 | ||
130 | self._cg.unindent() | |
131 | tmpl = templates._CTX_END | |
132 | self._cg.add_lines(tmpl) | |
133 | ||
134 | def _generate_ctxs(self): | |
135 | for stream in self._cfg.metadata.streams.values(): | |
136 | self._generate_ctx(stream) | |
137 | ||
138 | def _generate_clock_cb(self, clock): | |
139 | tmpl = templates._CLOCK_CB | |
140 | self._cg.add_lines(tmpl.format(return_ctype=clock.return_ctype, | |
141 | cname=clock.name)) | |
142 | ||
143 | def _generate_clock_cbs(self): | |
144 | for clock in self._cfg.metadata.clocks.values(): | |
145 | self._generate_clock_cb(clock) | |
146 | ||
147 | def _generate_platform_callbacks(self): | |
148 | tmpl = templates._PLATFORM_CALLBACKS_BEGIN | |
149 | self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix)) | |
150 | self._cg.indent() | |
151 | self._generate_clock_cbs() | |
152 | self._cg.unindent() | |
153 | tmpl = templates._PLATFORM_CALLBACKS_END | |
154 | self._cg.add_lines(tmpl) | |
155 | ||
156 | def generate_bitfield_header(self): | |
157 | self._cg.reset() | |
158 | tmpl = templates._BITFIELD | |
159 | tmpl = tmpl.replace('$prefix$', self._cfg.prefix) | |
160 | tmpl = tmpl.replace('$PREFIX$', self._cfg.prefix.upper()) | |
161 | ||
162 | if self._cfg.metadata.trace.byte_order == metadata.ByteOrder.BE: | |
163 | endian_def = 'BIG_ENDIAN' | |
164 | else: | |
165 | endian_def = 'LITTLE_ENDIAN' | |
166 | ||
167 | tmpl = tmpl.replace('$ENDIAN_DEF$', endian_def) | |
168 | self._cg.add_lines(tmpl) | |
169 | ||
170 | return self._cg.code | |
171 | ||
172 | def _generate_func_init_proto(self): | |
173 | tmpl = templates._FUNC_INIT_PROTO | |
174 | self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix)) | |
175 | ||
176 | def _get_int_ctype(self, t): | |
177 | signed = 'u' if not t.signed else '' | |
178 | ||
179 | if t.size <= 8: | |
180 | sz = '8' | |
181 | elif t.size <= 16: | |
182 | sz = '16' | |
183 | elif t.size <= 32: | |
184 | sz = '32' | |
185 | elif t.size == 64: | |
186 | sz = '64' | |
187 | ||
188 | return '{}int{}_t'.format(signed, sz) | |
189 | ||
190 | def _get_float_ctype(self, t): | |
191 | if t.exp_size == 8 and t.mant_size == 24 and t.align == 32: | |
192 | ctype = 'float' | |
193 | elif t.exp_size == 11 and t.mant_size == 53 and t.align == 64: | |
194 | ctype = 'double' | |
195 | else: | |
196 | ctype = 'uint64_t' | |
197 | ||
198 | return ctype | |
199 | ||
200 | def _get_enum_ctype(self, t): | |
201 | return self._get_int_ctype(t.value_type) | |
202 | ||
203 | def _get_string_ctype(self, t): | |
204 | return 'const char *' | |
205 | ||
206 | def _get_type_ctype(self, t): | |
207 | return self._type_to_get_ctype_func[type(t)](t) | |
208 | ||
209 | def _generate_type_ctype(self, t): | |
210 | ctype = self._get_type_ctype(t) | |
211 | self._cg.append_to_last_line(ctype) | |
212 | ||
213 | def _generate_proto_param(self, t, name): | |
214 | self._generate_type_ctype(t) | |
215 | self._cg.append_to_last_line(' ') | |
216 | self._cg.append_to_last_line(name) | |
217 | ||
218 | def _generate_proto_params(self, t, name_prefix, exclude_list): | |
219 | self._cg.indent() | |
220 | ||
221 | for field_name, field_type in t.fields.items(): | |
222 | if field_name in exclude_list: | |
223 | continue | |
224 | ||
225 | name = name_prefix + field_name | |
226 | self._cg.append_to_last_line(',') | |
227 | self._cg.add_line('') | |
228 | self._generate_proto_param(field_type, name) | |
229 | ||
230 | self._cg.unindent() | |
231 | ||
232 | def _generate_func_open_proto(self, stream): | |
233 | tmpl = templates._FUNC_OPEN_PROTO_BEGIN | |
234 | self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix, | |
235 | sname=stream.name)) | |
236 | trace_packet_header_type = self._cfg.metadata.trace.packet_header_type | |
237 | ||
238 | if trace_packet_header_type is not None: | |
239 | exclude_list = ['magic', 'stream_id', 'uuid'] | |
240 | self._generate_proto_params(trace_packet_header_type, _PREFIX_TPH, | |
241 | exclude_list) | |
242 | ||
243 | if stream.packet_context_type is not None: | |
244 | exclude_list = [ | |
245 | 'timestamp_begin', | |
246 | 'timestamp_end', | |
247 | 'packet_size', | |
248 | 'content_size', | |
249 | 'events_discarded', | |
250 | ] | |
251 | self._generate_proto_params(stream.packet_context_type, | |
252 | _PREFIX_SPC, exclude_list) | |
253 | ||
254 | tmpl = templates._FUNC_OPEN_PROTO_END | |
255 | self._cg.add_lines(tmpl) | |
256 | ||
257 | def _generate_func_close_proto(self, stream): | |
258 | tmpl = templates._FUNC_CLOSE_PROTO | |
259 | self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix, | |
260 | sname=stream.name)) | |
261 | ||
262 | def _generate_func_trace_proto_params(self, stream, event): | |
263 | if stream.event_header_type is not None: | |
264 | exclude_list = [ | |
265 | 'id', | |
266 | 'timestamp', | |
267 | ] | |
268 | self._generate_proto_params(stream.event_header_type, | |
269 | _PREFIX_SEH, exclude_list) | |
270 | ||
271 | if stream.event_context_type is not None: | |
272 | self._generate_proto_params(stream.event_context_type, | |
273 | _PREFIX_SEC, []) | |
274 | ||
275 | if event.context_type is not None: | |
276 | self._generate_proto_params(event.context_type, | |
277 | _PREFIX_EC, []) | |
278 | ||
279 | if event.payload_type is not None: | |
280 | self._generate_proto_params(event.payload_type, | |
281 | _PREFIX_EP, []) | |
282 | ||
283 | def _generate_func_trace_proto(self, stream, event): | |
284 | tmpl = templates._FUNC_TRACE_PROTO_BEGIN | |
285 | self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix, | |
286 | sname=stream.name, evname=event.name)) | |
287 | self._generate_func_trace_proto_params(stream, event) | |
288 | tmpl = templates._FUNC_TRACE_PROTO_END | |
289 | self._cg.add_lines(tmpl) | |
290 | ||
291 | def _punctuate_proto(self): | |
292 | self._cg.append_to_last_line(';') | |
293 | ||
294 | def generate_header(self): | |
295 | self._cg.reset() | |
296 | dt = datetime.datetime.now().isoformat() | |
297 | bh_filename = self.get_bitfield_header_filename() | |
298 | tmpl = templates._HEADER_BEGIN | |
299 | self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix, | |
300 | ucprefix=self._cfg.prefix.upper(), | |
301 | bitfield_header_filename=bh_filename, | |
302 | version=barectf.__version__, date=dt)) | |
303 | self._cg.add_empty_line() | |
304 | ||
305 | # platform callbacks structure | |
306 | self._generate_platform_callbacks() | |
307 | self._cg.add_empty_line() | |
308 | ||
309 | # context parent | |
310 | self._generate_ctx_parent() | |
311 | self._cg.add_empty_line() | |
312 | ||
313 | # stream contexts | |
314 | self._generate_ctxs() | |
315 | self._cg.add_empty_line() | |
316 | ||
317 | # initialization function prototype | |
318 | self._generate_func_init_proto() | |
319 | self._punctuate_proto() | |
320 | self._cg.add_empty_line() | |
321 | ||
322 | for stream in self._cfg.metadata.streams.values(): | |
323 | self._generate_func_open_proto(stream) | |
324 | self._punctuate_proto() | |
325 | self._cg.add_empty_line() | |
326 | self._generate_func_close_proto(stream) | |
327 | self._punctuate_proto() | |
328 | self._cg.add_empty_line() | |
329 | ||
330 | for ev in stream.events.values(): | |
331 | self._generate_func_trace_proto(stream, ev) | |
332 | self._punctuate_proto() | |
333 | self._cg.add_empty_line() | |
334 | ||
335 | tmpl = templates._HEADER_END | |
336 | self._cg.add_lines(tmpl.format(ucprefix=self._cfg.prefix.upper())) | |
337 | ||
338 | return self._cg.code | |
339 | ||
340 | def _get_call_event_param_list_from_struct(self, t, prefix, exclude_list): | |
341 | lst = '' | |
342 | ||
343 | for field_name in t.fields: | |
344 | if field_name in exclude_list: | |
345 | continue | |
346 | ||
347 | lst += ', {}{}'.format(prefix, field_name) | |
348 | ||
349 | return lst | |
350 | ||
351 | def _get_call_event_param_list(self, stream, event): | |
352 | lst = '' | |
353 | gcp_func = self._get_call_event_param_list_from_struct | |
354 | ||
355 | if stream.event_header_type is not None: | |
356 | exclude_list = [ | |
357 | 'id', | |
358 | 'timestamp', | |
359 | ] | |
360 | lst += gcp_func(stream.event_header_type, _PREFIX_SEH, exclude_list) | |
361 | ||
362 | if stream.event_context_type is not None: | |
363 | lst += gcp_func(stream.event_context_type, _PREFIX_SEC, []) | |
364 | ||
365 | if event.context_type is not None: | |
366 | lst += gcp_func(event.context_type, _PREFIX_EC, []) | |
367 | ||
368 | if event.payload_type is not None: | |
369 | lst += gcp_func(event.payload_type, _PREFIX_EP, []) | |
370 | ||
371 | return lst | |
372 | ||
373 | def _generate_align(self, at, align): | |
374 | self._cg.add_line('_ALIGN({}, {});'.format(at, align)) | |
375 | self._sasa.align(align) | |
376 | ||
377 | def _generate_align_type(self, at, t): | |
378 | if t.align == 1: | |
379 | return | |
380 | ||
381 | self._generate_align(at, t.align) | |
382 | ||
383 | def _generate_incr_pos(self, var, value): | |
384 | self._cg.add_line('{} += {};'.format(var, value)) | |
385 | ||
386 | def _generate_incr_pos_bytes(self, var, value): | |
387 | self._generate_incr_pos(var, '_BYTES_TO_BITS({})'.format(value)) | |
388 | ||
389 | def _generate_func_get_event_size_proto(self, stream, event): | |
390 | tmpl = templates._FUNC_GET_EVENT_SIZE_PROTO_BEGIN | |
391 | self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix, | |
392 | sname=stream.name, evname=event.name)) | |
393 | self._generate_func_trace_proto_params(stream, event) | |
394 | tmpl = templates._FUNC_GET_EVENT_SIZE_PROTO_END | |
395 | self._cg.add_lines(tmpl) | |
396 | ||
397 | def _generate_func_get_event_size_from_entity(self, prefix, t): | |
398 | self._cg.add_line('{') | |
399 | self._cg.indent() | |
400 | self._cg.add_cc_line('align structure') | |
401 | self._generate_align_type('at', t) | |
402 | ||
403 | for field_name, field_type in t.fields.items(): | |
404 | self._cg.add_empty_line() | |
405 | self._generate_field_name_cc_line(field_name) | |
406 | self._generate_align_type('at', field_type) | |
407 | ||
408 | if type(field_type) is metadata.String: | |
409 | param = prefix + field_name | |
410 | self._generate_incr_pos_bytes('at', | |
411 | 'strlen({}) + 1'.format(param)) | |
412 | else: | |
413 | self._generate_incr_pos('at', field_type.size) | |
414 | ||
415 | self._cg.unindent() | |
416 | self._cg.add_line('}') | |
417 | self._cg.add_empty_line() | |
418 | ||
419 | def _generate_func_get_event_size(self, stream, event): | |
420 | self._generate_func_get_event_size_proto(stream, event) | |
421 | tmpl = templates._FUNC_GET_EVENT_SIZE_BODY_BEGIN | |
422 | self._cg.add_lines(tmpl) | |
423 | self._cg.add_empty_line() | |
424 | self._cg.indent() | |
425 | func = self._generate_func_get_event_size_from_entity | |
426 | ||
427 | if stream.event_header_type is not None: | |
428 | self._cg.add_cc_line('stream event header') | |
429 | func(_PREFIX_SEH, stream.event_header_type) | |
430 | ||
431 | if stream.event_context_type is not None: | |
432 | self._cg.add_cc_line('stream event context') | |
433 | func(_PREFIX_SEC, stream.event_context_type) | |
434 | ||
435 | if event.context_type is not None: | |
436 | self._cg.add_cc_line('event context') | |
437 | func(_PREFIX_EC, event.context_type) | |
438 | ||
439 | if event.payload_type is not None: | |
440 | self._cg.add_cc_line('event payload') | |
441 | func(_PREFIX_EP, event.payload_type) | |
442 | ||
443 | self._cg.unindent() | |
444 | tmpl = templates._FUNC_GET_EVENT_SIZE_BODY_END | |
445 | self._cg.add_lines(tmpl) | |
446 | ||
447 | def _generate_func_serialize_event_proto(self, stream, event): | |
448 | tmpl = templates._FUNC_SERIALIZE_EVENT_PROTO_BEGIN | |
449 | self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix, | |
450 | sname=stream.name, evname=event.name)) | |
451 | self._generate_func_trace_proto_params(stream, event) | |
452 | tmpl = templates._FUNC_SERIALIZE_EVENT_PROTO_END | |
453 | self._cg.add_lines(tmpl) | |
454 | ||
455 | def _generate_bitfield_write(self, var, ctx, t): | |
456 | ptr = '&{ctx}->buf[_BITS_TO_BYTES({ctx}->at)]'.format(ctx=ctx) | |
457 | start = self._sasa.byte_offset | |
458 | suffix = 'le' if t.byte_order is metadata.ByteOrder.LE else 'be' | |
459 | func = '{}bt_bitfield_write_{}'.format(self._cfg.prefix, suffix) | |
460 | call = '{}({}, uint8_t, {}, {}, {});'.format(func, ptr, start, t.size, | |
461 | var) | |
462 | self._cg.add_line(call) | |
463 | ||
464 | def _generate_serialize_int(self, var, ctx, t): | |
465 | self._generate_bitfield_write(var, ctx, t) | |
466 | self._generate_incr_pos('{}->at'.format(ctx), t.size) | |
467 | ||
468 | def _generate_serialize_float(self, var, ctx, t): | |
469 | ctype = self._get_type_ctype(t) | |
470 | ||
471 | if ctype == 'float': | |
472 | ctype = 'uint32_t' | |
473 | elif ctype == 'double': | |
474 | ctype = 'uint64_t' | |
475 | ||
476 | var_casted = '*(({}*) &{})'.format(ctype, var) | |
477 | self._generate_bitfield_write(var_casted, ctx, t) | |
478 | self._generate_incr_pos('{}->at'.format(ctx), t.size) | |
479 | ||
480 | def _generate_serialize_enum(self, var, ctx, t): | |
481 | self._generate_serialize_type(var, ctx, t.value_type) | |
482 | ||
483 | def _generate_serialize_string(self, var, ctx, t): | |
484 | tmpl = '_write_cstring({}, {});'.format(ctx, var) | |
485 | self._cg.add_lines(tmpl) | |
486 | ||
487 | def _generate_serialize_type(self, var, ctx, t): | |
488 | self._type_to_generate_serialize_func[type(t)](var, ctx, t) | |
489 | self._sasa.write_type(t) | |
490 | ||
491 | def _generate_func_serialize_event_from_entity(self, prefix, t, | |
492 | spec_src=None): | |
493 | self._cg.add_line('{') | |
494 | self._cg.indent() | |
495 | self._cg.add_cc_line('align structure') | |
496 | self._sasa.reset() | |
497 | self._generate_align_type('ctx->at', t) | |
498 | ||
499 | for field_name, field_type in t.fields.items(): | |
500 | src = prefix + field_name | |
501 | ||
502 | if spec_src is not None: | |
503 | if field_name in spec_src: | |
504 | src = spec_src[field_name] | |
505 | ||
506 | self._cg.add_empty_line() | |
507 | self._generate_field_name_cc_line(field_name) | |
508 | self._generate_align_type('ctx->at', field_type) | |
509 | self._generate_serialize_type(src, 'ctx', field_type) | |
510 | ||
511 | self._cg.unindent() | |
512 | self._cg.add_line('}') | |
513 | self._cg.add_empty_line() | |
514 | ||
515 | def _generate_func_serialize_event(self, stream, event): | |
516 | self._generate_func_serialize_event_proto(stream, event) | |
517 | tmpl = templates._FUNC_SERIALIZE_EVENT_BODY_BEGIN | |
518 | self._cg.add_lines(tmpl) | |
519 | self._cg.indent() | |
520 | ||
521 | if stream.event_header_type is not None: | |
522 | t = stream.event_header_type | |
523 | exclude_list = ['timestamp', 'id'] | |
524 | params = self._get_call_event_param_list_from_struct(t, _PREFIX_SEH, | |
525 | exclude_list) | |
526 | tmpl = '_serialize_stream_event_header_{sname}(ctx, {evid}{params});' | |
527 | self._cg.add_cc_line('stream event header') | |
528 | self._cg.add_line(tmpl.format(sname=stream.name, evid=event.id, | |
529 | params=params)) | |
530 | self._cg.add_empty_line() | |
531 | ||
532 | if stream.event_context_type is not None: | |
533 | t = stream.event_context_type | |
534 | params = self._get_call_event_param_list_from_struct(t, _PREFIX_SEH, | |
535 | exclude_list) | |
536 | tmpl = '_serialize_stream_event_context_{sname}(ctx{params});' | |
537 | self._cg.add_cc_line('stream event context') | |
538 | self._cg.add_line(tmpl.format(sname=stream.name, params=params)) | |
539 | self._cg.add_empty_line() | |
540 | ||
541 | if event.context_type is not None: | |
542 | self._cg.add_cc_line('event context') | |
543 | self._generate_func_serialize_event_from_entity(_PREFIX_EC, | |
544 | event.context_type) | |
545 | ||
546 | if event.payload_type is not None: | |
547 | self._cg.add_cc_line('event payload') | |
548 | self._generate_func_serialize_event_from_entity(_PREFIX_EP, | |
549 | event.payload_type) | |
550 | ||
551 | self._cg.unindent() | |
552 | tmpl = templates._FUNC_SERIALIZE_EVENT_BODY_END | |
553 | self._cg.add_lines(tmpl) | |
554 | ||
555 | def _generate_func_serialize_stream_event_header_proto(self, stream): | |
556 | tmpl = templates._FUNC_SERIALIZE_STREAM_EVENT_HEADER_PROTO_BEGIN | |
557 | self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix, | |
558 | sname=stream.name)) | |
559 | ||
560 | if stream.event_header_type is not None: | |
561 | exclude_list = [ | |
562 | 'id', | |
563 | 'timestamp', | |
564 | ] | |
565 | self._generate_proto_params(stream.event_header_type, | |
566 | _PREFIX_SEH, exclude_list) | |
567 | ||
568 | tmpl = templates._FUNC_SERIALIZE_STREAM_EVENT_HEADER_PROTO_END | |
569 | self._cg.add_lines(tmpl) | |
570 | ||
571 | def _generate_func_serialize_stream_event_context_proto(self, stream): | |
572 | tmpl = templates._FUNC_SERIALIZE_STREAM_EVENT_CONTEXT_PROTO_BEGIN | |
573 | self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix, | |
574 | sname=stream.name)) | |
575 | ||
576 | if stream.event_context_type is not None: | |
577 | self._generate_proto_params(stream.event_context_type, | |
578 | _PREFIX_SEC, []) | |
579 | ||
580 | tmpl = templates._FUNC_SERIALIZE_STREAM_EVENT_CONTEXT_PROTO_END | |
581 | self._cg.add_lines(tmpl) | |
582 | ||
583 | def _generate_func_serialize_stream_event_header(self, stream): | |
584 | self._generate_func_serialize_stream_event_header_proto(stream) | |
585 | tmpl = templates._FUNC_SERIALIZE_STREAM_EVENT_HEADER_BODY_BEGIN | |
586 | self._cg.add_lines(tmpl) | |
587 | self._cg.indent() | |
588 | ||
589 | if stream.event_header_type is not None: | |
590 | if 'timestamp' in stream.event_header_type.fields: | |
591 | timestamp = stream.event_header_type.fields['timestamp'] | |
592 | ts_ctype = self._get_int_ctype(timestamp) | |
593 | clock = timestamp.property_mappings[0].object | |
594 | clock_name = clock.name | |
595 | clock_ctype = clock.return_ctype | |
596 | tmpl = '{} ts = ctx->cbs.{}_clock_get_value(ctx->data);' | |
597 | self._cg.add_line(tmpl.format(clock_ctype, clock_name)) | |
598 | ||
599 | self._cg.add_empty_line() | |
600 | func = self._generate_func_serialize_event_from_entity | |
601 | ||
602 | if stream.event_header_type is not None: | |
603 | spec_src = {} | |
604 | ||
605 | if 'id' in stream.event_header_type.fields: | |
606 | id_t = stream.event_header_type.fields['id'] | |
607 | id_t_ctype = self._get_int_ctype(id_t) | |
608 | spec_src['id'] = '({}) event_id'.format(id_t_ctype) | |
609 | ||
610 | if 'timestamp' in stream.event_header_type.fields: | |
611 | spec_src['timestamp'] = '({}) ts'.format(ts_ctype) | |
612 | ||
613 | func(_PREFIX_SEH, stream.event_header_type, spec_src) | |
614 | ||
615 | self._cg.unindent() | |
616 | tmpl = templates._FUNC_SERIALIZE_STREAM_EVENT_HEADER_BODY_END | |
617 | self._cg.add_lines(tmpl) | |
618 | ||
619 | def _generate_func_serialize_stream_event_context(self, stream): | |
620 | self._generate_func_serialize_stream_event_context_proto(stream) | |
621 | tmpl = templates._FUNC_SERIALIZE_STREAM_EVENT_CONTEXT_BODY_BEGIN | |
622 | self._cg.add_lines(tmpl) | |
623 | self._cg.indent() | |
624 | func = self._generate_func_serialize_event_from_entity | |
625 | ||
626 | if stream.event_context_type is not None: | |
627 | func(_PREFIX_SEC, stream.event_context_type) | |
628 | ||
629 | self._cg.unindent() | |
630 | tmpl = templates._FUNC_SERIALIZE_STREAM_EVENT_CONTEXT_BODY_END | |
631 | self._cg.add_lines(tmpl) | |
632 | ||
633 | def _generate_func_trace(self, stream, event): | |
634 | self._generate_func_trace_proto(stream, event) | |
635 | params = self._get_call_event_param_list(stream, event) | |
636 | tmpl = templates._FUNC_TRACE_BODY | |
637 | self._cg.add_lines(tmpl.format(sname=stream.name, evname=event.name, | |
638 | params=params)) | |
639 | ||
640 | def _generate_func_init(self): | |
641 | self._generate_func_init_proto() | |
642 | tmpl = templates._FUNC_INIT_BODY | |
643 | self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix)) | |
644 | ||
645 | def _generate_field_name_cc_line(self, field_name): | |
646 | self._cg.add_cc_line('"{}" field'.format(field_name)) | |
647 | ||
648 | def _save_byte_offset(self, name): | |
649 | self._saved_byte_offsets[name] = self._sasa.byte_offset | |
650 | ||
651 | def _restore_byte_offset(self, name): | |
652 | self._sasa.byte_offset = self._saved_byte_offsets[name] | |
653 | ||
654 | def _generate_func_open(self, stream): | |
655 | def generate_save_offset(name): | |
656 | tmpl = 'ctx->off_spc_{} = ctx->parent.at;'.format(name) | |
657 | self._cg.add_line(tmpl) | |
658 | self._save_byte_offset(name) | |
659 | ||
660 | self._generate_func_open_proto(stream) | |
661 | tmpl = templates._FUNC_OPEN_BODY_BEGIN | |
662 | self._cg.add_lines(tmpl) | |
663 | self._cg.indent() | |
664 | tph_type = self._cfg.metadata.trace.packet_header_type | |
665 | spc_type = stream.packet_context_type | |
666 | ||
667 | if spc_type is not None and 'timestamp_begin' in spc_type.fields: | |
668 | field = spc_type.fields['timestamp_begin'] | |
669 | tmpl = '{} ts = ctx->parent.cbs.{}_clock_get_value(ctx->parent.data);' | |
670 | clock = field.property_mappings[0].object | |
671 | clock_ctype = clock.return_ctype | |
672 | clock_name = clock.name | |
673 | self._cg.add_line(tmpl.format(clock_ctype, clock_name)) | |
674 | self._cg.add_empty_line() | |
675 | ||
676 | self._cg.add_cc_line('do not open a packet that is already open') | |
677 | self._cg.add_line('if (ctx->parent.packet_is_open) {') | |
678 | self._cg.indent() | |
679 | self._cg.add_line('return;') | |
680 | self._cg.unindent() | |
681 | self._cg.add_line('}') | |
682 | self._cg.add_empty_line() | |
683 | self._cg.add_line('ctx->parent.at = 0;') | |
684 | ||
685 | if tph_type is not None: | |
686 | self._cg.add_empty_line() | |
687 | self._cg.add_cc_line('trace packet header') | |
688 | self._cg.add_line('{') | |
689 | self._cg.indent() | |
690 | self._cg.add_cc_line('align structure') | |
691 | self._sasa.reset() | |
692 | self._generate_align_type('ctx->parent.at', tph_type) | |
693 | ||
694 | for field_name, field_type in tph_type.fields.items(): | |
695 | src = _PREFIX_TPH + field_name | |
696 | ||
697 | if field_name == 'magic': | |
698 | src = '0xc1fc1fc1UL' | |
699 | elif field_name == 'stream_id': | |
700 | stream_id_ctype = self._get_int_ctype(field_type) | |
701 | src = '({}) {}'.format(stream_id_ctype, stream.id) | |
702 | elif field_name == 'uuid': | |
703 | self._cg.add_empty_line() | |
704 | self._generate_field_name_cc_line(field_name) | |
705 | self._cg.add_line('{') | |
706 | self._cg.indent() | |
707 | self._cg.add_line('static uint8_t uuid[] = {') | |
708 | self._cg.indent() | |
709 | ||
710 | for b in self._cfg.metadata.trace.uuid.bytes: | |
711 | self._cg.add_line('{},'.format(b)) | |
712 | ||
713 | self._cg.unindent() | |
714 | self._cg.add_line('};') | |
715 | self._cg.add_empty_line() | |
716 | self._generate_align('ctx->parent.at', 8) | |
717 | line = 'memcpy(&ctx->parent.buf[_BITS_TO_BYTES(ctx->parent.at)], uuid, 16);' | |
718 | self._cg.add_line(line) | |
719 | self._generate_incr_pos_bytes('ctx->parent.at', 16) | |
720 | self._cg.unindent() | |
721 | self._cg.add_line('}') | |
722 | self._sasa.reset() | |
723 | continue | |
724 | ||
725 | self._cg.add_empty_line() | |
726 | self._generate_field_name_cc_line(field_name) | |
727 | self._generate_align_type('ctx->parent.at', field_type) | |
728 | self._generate_serialize_type(src, '(&ctx->parent)', field_type) | |
729 | ||
730 | self._cg.unindent() | |
731 | self._cg.add_lines('}') | |
732 | ||
733 | if spc_type is not None: | |
734 | self._cg.add_empty_line() | |
735 | self._cg.add_cc_line('stream packet context') | |
736 | self._cg.add_line('{') | |
737 | self._cg.indent() | |
738 | self._cg.add_cc_line('align structure') | |
739 | self._sasa.reset() | |
740 | self._generate_align_type('ctx->parent.at', spc_type) | |
741 | tmpl_off = 'off_spc_{fname}' | |
742 | ||
743 | for field_name, field_type in spc_type.fields.items(): | |
744 | src = _PREFIX_SPC + field_name | |
745 | skip_int = False | |
746 | self._cg.add_empty_line() | |
747 | self._generate_field_name_cc_line(field_name) | |
748 | ||
749 | if field_name == 'timestamp_begin': | |
750 | ctype = self._get_type_ctype(field_type) | |
751 | src = '({}) ts'.format(ctype) | |
752 | elif field_name in ['timestamp_end', 'content_size', | |
753 | 'events_discarded']: | |
754 | skip_int = True | |
755 | elif field_name == 'packet_size': | |
756 | ctype = self._get_type_ctype(field_type) | |
757 | src = '({}) ctx->parent.packet_size'.format(ctype) | |
758 | ||
759 | self._generate_align_type('ctx->parent.at', field_type) | |
760 | ||
761 | if skip_int: | |
762 | generate_save_offset(field_name) | |
763 | self._generate_incr_pos('ctx->parent.at', field_type.size) | |
764 | self._sasa.write_type(field_type) | |
765 | else: | |
766 | self._generate_serialize_type(src, '(&ctx->parent)', | |
767 | field_type) | |
768 | ||
769 | self._cg.unindent() | |
770 | self._cg.add_lines('}') | |
771 | ||
772 | self._cg.unindent() | |
773 | tmpl = templates._FUNC_OPEN_BODY_END | |
774 | self._cg.add_lines(tmpl) | |
775 | ||
776 | def _generate_func_close(self, stream): | |
777 | def generate_goto_offset(name): | |
778 | tmpl = 'ctx->parent.at = ctx->off_spc_{};'.format(name) | |
779 | self._cg.add_line(tmpl) | |
780 | ||
781 | self._generate_func_close_proto(stream) | |
782 | tmpl = templates._FUNC_CLOSE_BODY_BEGIN | |
783 | self._cg.add_lines(tmpl) | |
784 | self._cg.indent() | |
785 | spc_type = stream.packet_context_type | |
786 | ||
787 | if spc_type is not None: | |
788 | if 'timestamp_end' in spc_type.fields: | |
789 | tmpl = '{} ts = ctx->parent.cbs.{}_clock_get_value(ctx->parent.data);' | |
790 | field = spc_type.fields['timestamp_end'] | |
791 | clock = field.property_mappings[0].object | |
792 | clock_ctype = clock.return_ctype | |
793 | clock_name = clock.name | |
794 | self._cg.add_line(tmpl.format(clock_ctype, clock_name)) | |
795 | self._cg.add_empty_line() | |
796 | ||
797 | self._cg.add_cc_line('do not close a packet that is not open') | |
798 | self._cg.add_line('if (!ctx->parent.packet_is_open) {') | |
799 | self._cg.indent() | |
800 | self._cg.add_line('return;') | |
801 | self._cg.unindent() | |
802 | self._cg.add_line('}') | |
803 | self._cg.add_empty_line() | |
804 | self._cg.add_cc_line('save content size') | |
805 | self._cg.add_line('ctx->parent.content_size = ctx->parent.at;') | |
806 | ||
807 | if spc_type is not None: | |
808 | field_name = 'timestamp_end' | |
809 | ||
810 | if field_name in spc_type.fields: | |
811 | t = spc_type.fields[field_name] | |
812 | ctype = self._get_type_ctype(t) | |
813 | src = '({}) ts'.format(ctype) | |
814 | self._cg.add_empty_line() | |
815 | self._generate_field_name_cc_line(field_name) | |
816 | generate_goto_offset(field_name) | |
817 | self._restore_byte_offset(field_name) | |
818 | self._generate_serialize_type(src, '(&ctx->parent)', t) | |
819 | ||
820 | field_name = 'content_size' | |
821 | ||
822 | if 'content_size' in spc_type.fields: | |
823 | t = spc_type.fields[field_name] | |
824 | ctype = self._get_type_ctype(t) | |
825 | src = '({}) ctx->parent.content_size'.format(ctype) | |
826 | self._cg.add_empty_line() | |
827 | self._generate_field_name_cc_line(field_name) | |
828 | generate_goto_offset(field_name) | |
829 | self._restore_byte_offset(field_name) | |
830 | self._generate_serialize_type(src, '(&ctx->parent)', t) | |
831 | ||
832 | field_name = 'events_discarded' | |
833 | ||
834 | if field_name in spc_type.fields: | |
835 | t = spc_type.fields[field_name] | |
836 | ctype = self._get_type_ctype(t) | |
837 | src = '({}) ctx->parent.events_discarded'.format(ctype) | |
838 | self._cg.add_empty_line() | |
839 | self._generate_field_name_cc_line(field_name) | |
840 | generate_goto_offset(field_name) | |
841 | self._restore_byte_offset(field_name) | |
842 | self._generate_serialize_type(src, '(&ctx->parent)', t) | |
843 | ||
844 | self._cg.unindent() | |
845 | tmpl = templates._FUNC_CLOSE_BODY_END | |
846 | self._cg.add_lines(tmpl) | |
847 | self._sasa.reset() | |
848 | ||
849 | def generate_c_src(self): | |
850 | self._cg.reset() | |
851 | dt = datetime.datetime.now().isoformat() | |
852 | header_filename = self.get_header_filename() | |
853 | tmpl = templates._C_SRC | |
854 | self._cg.add_lines(tmpl.format(prefix=self._cfg.prefix, | |
855 | header_filename=header_filename, | |
856 | version=barectf.__version__, date=dt)) | |
857 | self._cg.add_empty_line() | |
858 | ||
859 | # initialization function | |
860 | self._generate_func_init() | |
861 | self._cg.add_empty_line() | |
862 | ||
863 | for stream in self._cfg.metadata.streams.values(): | |
864 | self._generate_func_open(stream) | |
865 | self._cg.add_empty_line() | |
866 | self._generate_func_close(stream) | |
867 | self._cg.add_empty_line() | |
868 | ||
869 | if stream.event_header_type is not None: | |
870 | self._generate_func_serialize_stream_event_header(stream) | |
871 | self._cg.add_empty_line() | |
872 | ||
873 | if stream.event_context_type is not None: | |
874 | self._generate_func_serialize_stream_event_context(stream) | |
875 | self._cg.add_empty_line() | |
876 | ||
877 | for ev in stream.events.values(): | |
878 | self._generate_func_get_event_size(stream, ev) | |
879 | self._cg.add_empty_line() | |
880 | self._generate_func_serialize_event(stream, ev) | |
881 | self._cg.add_empty_line() | |
882 | self._generate_func_trace(stream, ev) | |
883 | self._cg.add_empty_line() | |
884 | ||
885 | ||
886 | return self._cg.code | |
887 | ||
888 | def get_header_filename(self): | |
889 | return '{}.h'.format(self._cfg.prefix.rstrip('_')) | |
890 | ||
891 | def get_bitfield_header_filename(self): | |
892 | return '{}-bitfield.h'.format(self._cfg.prefix.rstrip('_')) |