1 # The MIT License (MIT)
3 # Copyright (c) 2015-2020 Philippe Proulx <pproulx@efficios.com>
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:
13 # The above copyright notice and this permission notice shall be
14 # included in all copies or substantial portions of the Software.
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.
24 import barectf
.version
as barectf_version
25 import collections
.abc
32 class ByteOrder(enum
.Enum
):
40 raise NotImplementedError
43 class _BitArrayFieldType(_FieldType
):
44 def __init__(self
, size
, byte_order
=None, alignment
=1):
46 self
._byte
_order
= byte_order
47 self
._alignment
= alignment
55 return self
._byte
_order
59 return self
._alignment
62 class DisplayBase(enum
.Enum
):
69 class _IntegerFieldType(_BitArrayFieldType
):
70 def __init__(self
, size
, byte_order
=None, alignment
=None,
71 preferred_display_base
=DisplayBase
.DECIMAL
):
72 effective_alignment
= 1
74 if alignment
is None and size
% 8 == 0:
75 effective_alignment
= 8
77 super().__init
__(size
, byte_order
, effective_alignment
)
78 self
._preferred
_display
_base
= preferred_display_base
81 def preferred_display_base(self
):
82 return self
._preferred
_display
_base
85 class UnsignedIntegerFieldType(_IntegerFieldType
):
86 def __init__(self
, *args
):
87 super().__init
__(*args
)
88 self
._mapped
_clk
_type
_name
= None
91 class SignedIntegerFieldType(_IntegerFieldType
):
95 class EnumerationFieldTypeMappingRange
:
96 def __init__(self
, lower
, upper
):
108 def __eq__(self
, other
):
109 if type(other
) is not type(self
):
112 return (self
._lower
, self
._upper
) == (other
._lower
, other
._upper
)
115 return hash((self
._lower
, self
._upper
))
117 def contains(self
, value
):
118 return self
._lower
<= value
<= self
._upper
121 class EnumerationFieldTypeMapping
:
122 def __init__(self
, ranges
):
123 self
._ranges
= frozenset(ranges
)
129 def ranges_contain_value(self
, value
):
130 return any([rg
.contains(value
) for rg
in self
._ranges
])
133 class EnumerationFieldTypeMappings(collections
.abc
.Mapping
):
134 def __init__(self
, mappings
):
135 self
._mappings
= {label
: mapping
for label
, mapping
in mappings
.items()}
137 def __getitem__(self
, key
):
138 return self
._mappings
[key
]
141 return iter(self
._mappings
)
144 return len(self
._mappings
)
147 class _EnumerationFieldType(_IntegerFieldType
):
148 def __init__(self
, size
, byte_order
=None, alignment
=None,
149 preferred_display_base
=DisplayBase
.DECIMAL
, mappings
=None):
150 super().__init
__(size
, byte_order
, alignment
, preferred_display_base
)
151 self
._mappings
= EnumerationFieldTypeMappings({})
153 if mappings
is not None:
154 self
._mappings
= EnumerationFieldTypeMappings(mappings
)
158 return self
._mappings
160 def labels_for_value(self
, value
):
163 for label
, mapping
in self
._mappings
.items():
164 if mapping
.ranges_contain_value(value
):
170 class UnsignedEnumerationFieldType(_EnumerationFieldType
, UnsignedIntegerFieldType
):
174 class SignedEnumerationFieldType(_EnumerationFieldType
, SignedIntegerFieldType
):
178 class RealFieldType(_BitArrayFieldType
):
182 class StringFieldType(_FieldType
):
188 class _ArrayFieldType(_FieldType
):
189 def __init__(self
, element_field_type
):
190 self
._element
_field
_type
= element_field_type
193 def element_field_type(self
):
194 return self
._element
_field
_type
198 return self
._element
_field
_type
.alignment
201 class StaticArrayFieldType(_ArrayFieldType
):
202 def __init__(self
, length
, element_field_type
):
203 super().__init
__(element_field_type
)
204 self
._length
= length
211 class StructureFieldTypeMember
:
212 def __init__(self
, field_type
):
213 self
._field
_type
= field_type
216 def field_type(self
):
217 return self
._field
_type
220 class StructureFieldTypeMembers(collections
.abc
.Mapping
):
221 def __init__(self
, members
):
222 self
._members
= collections
.OrderedDict()
224 for name
, member
in members
.items():
225 assert type(member
) is StructureFieldTypeMember
226 self
._members
[name
] = member
228 def __getitem__(self
, key
):
229 return self
._members
[key
]
232 return iter(self
._members
)
235 return len(self
._members
)
238 class StructureFieldType(_FieldType
):
239 def __init__(self
, minimum_alignment
=1, members
=None):
240 self
._minimum
_alignment
= minimum_alignment
241 self
._members
= StructureFieldTypeMembers({})
243 if members
is not None:
244 self
._members
= StructureFieldTypeMembers(members
)
246 self
._set
_alignment
()
248 def _set_alignment(self
):
249 self
._alignment
= self
._minimum
_alignment
251 for member
in self
._members
.values():
252 if member
.field_type
.alignment
> self
._alignment
:
253 self
._alignment
= member
.field_type
.alignment
256 def minimum_alignment(self
):
257 return self
._minimum
_alignment
261 return self
._alignment
269 def __eq__(self
, other
):
270 if type(other
) is not type(self
):
273 return self
._name
== other
._name
275 def __lt__(self
, other
):
276 assert type(self
) is type(other
)
277 return self
._name
< other
._name
280 return hash(self
._name
)
283 class EventType(_UniqueByName
):
284 def __init__(self
, name
, log_level
=None, specific_context_field_type
=None,
285 payload_field_type
=None):
288 self
._log
_level
= log_level
289 self
._specific
_context
_field
_type
= specific_context_field_type
290 self
._payload
_field
_type
= payload_field_type
302 return self
._log
_level
305 def specific_context_field_type(self
):
306 return self
._specific
_context
_field
_type
309 def payload_field_type(self
):
310 return self
._payload
_field
_type
313 class ClockTypeOffset
:
314 def __init__(self
, seconds
=0, cycles
=0):
315 self
._seconds
= seconds
316 self
._cycles
= cycles
327 class ClockType(_UniqueByName
):
328 def __init__(self
, name
, frequency
=int(1e9
), uuid
=None, description
=None, precision
=0,
329 offset
=None, origin_is_unix_epoch
=False):
331 self
._frequency
= frequency
333 self
._description
= description
334 self
._precision
= precision
335 self
._offset
= ClockTypeOffset()
337 if offset
is not None:
338 self
._offset
= offset
340 self
._origin
_is
_unix
_epoch
= origin_is_unix_epoch
348 return self
._frequency
355 def description(self
):
356 return self
._description
360 return self
._precision
367 def origin_is_unix_epoch(self
):
368 return self
._origin
_is
_unix
_epoch
371 DEFAULT_FIELD_TYPE
= 'default'
374 class StreamTypePacketFeatures
:
375 def __init__(self
, total_size_field_type
=DEFAULT_FIELD_TYPE
,
376 content_size_field_type
=DEFAULT_FIELD_TYPE
, beginning_time_field_type
=None,
377 end_time_field_type
=None, discarded_events_counter_field_type
=None):
379 if user_ft
== DEFAULT_FIELD_TYPE
:
380 return UnsignedIntegerFieldType(64)
384 self
._total
_size
_field
_type
= get_ft(total_size_field_type
)
385 self
._content
_size
_field
_type
= get_ft(content_size_field_type
)
386 self
._beginning
_time
_field
_type
= get_ft(beginning_time_field_type
)
387 self
._end
_time
_field
_type
= get_ft(end_time_field_type
)
388 self
._discarded
_events
_counter
_field
_type
= get_ft(discarded_events_counter_field_type
)
391 def total_size_field_type(self
):
392 return self
._total
_size
_field
_type
395 def content_size_field_type(self
):
396 return self
._content
_size
_field
_type
399 def beginning_time_field_type(self
):
400 return self
._beginning
_time
_field
_type
403 def end_time_field_type(self
):
404 return self
._end
_time
_field
_type
407 def discarded_events_counter_field_type(self
):
408 return self
._discarded
_events
_counter
_field
_type
411 class StreamTypeEventFeatures
:
412 def __init__(self
, type_id_field_type
=DEFAULT_FIELD_TYPE
, time_field_type
=None):
413 def get_ft(user_field_type
):
414 if user_field_type
== DEFAULT_FIELD_TYPE
:
415 return UnsignedIntegerFieldType(64)
417 return user_field_type
419 self
._type
_id
_field
_type
= get_ft(type_id_field_type
)
420 self
._time
_field
_type
= get_ft(time_field_type
)
423 def type_id_field_type(self
):
424 return self
._type
_id
_field
_type
427 def time_field_type(self
):
428 return self
._time
_field
_type
431 class StreamTypeFeatures
:
432 def __init__(self
, packet_features
=None, event_features
=None):
433 self
._packet
_features
= StreamTypePacketFeatures()
435 if packet_features
is not None:
436 self
._packet
_features
= packet_features
438 self
._event
_features
= StreamTypeEventFeatures()
440 if event_features
is not None:
441 self
._event
_features
= event_features
444 def packet_features(self
):
445 return self
._packet
_features
448 def event_features(self
):
449 return self
._event
_features
452 class StreamType(_UniqueByName
):
453 def __init__(self
, name
, event_types
, default_clock_type
=None, features
=None,
454 packet_context_field_type_extra_members
=None,
455 event_common_context_field_type
=None):
458 self
._default
_clock
_type
= default_clock_type
459 self
._event
_common
_context
_field
_type
= event_common_context_field_type
460 self
._event
_types
= frozenset(event_types
)
463 for index
, ev_type
in enumerate(sorted(self
._event
_types
, key
=lambda evt
: evt
.name
)):
464 assert ev_type
._id
is None
467 self
._set
_features
(features
)
468 self
._packet
_context
_field
_type
_extra
_members
= StructureFieldTypeMembers({})
470 if packet_context_field_type_extra_members
is not None:
471 self
._packet
_context
_field
_type
_extra
_members
= StructureFieldTypeMembers(packet_context_field_type_extra_members
)
473 self
._set
_pkt
_ctx
_ft
()
474 self
._set
_ev
_header
_ft
()
476 def _set_features(self
, features
):
477 if features
is not None:
478 self
._features
= features
482 pkt_beginning_time_ft
= None
483 pkt_end_time_ft
= None
485 if self
._default
_clock
_type
is not None:
486 # Automatic time field types because the stream type has a
487 # default clock type.
488 ev_time_ft
= DEFAULT_FIELD_TYPE
489 pkt_beginning_time_ft
= DEFAULT_FIELD_TYPE
490 pkt_end_time_ft
= DEFAULT_FIELD_TYPE
492 self
._features
= StreamTypeFeatures(StreamTypePacketFeatures(beginning_time_field_type
=pkt_beginning_time_ft
,
493 end_time_field_type
=pkt_end_time_ft
),
494 StreamTypeEventFeatures(time_field_type
=ev_time_ft
))
496 def _set_ft_mapped_clk_type_name(self
, ft
):
500 if self
._default
_clock
_type
is not None:
501 assert isinstance(ft
, UnsignedIntegerFieldType
)
502 ft
._mapped
_clk
_type
_name
= self
._default
_clock
_type
.name
504 def _set_pkt_ctx_ft(self
):
505 def add_member_if_exists(name
, ft
, set_mapped_clk_type_name
=False):
509 if set_mapped_clk_type_name
:
510 self
._set
_ft
_mapped
_clk
_type
_name
(ft
)
512 members
[name
] = StructureFieldTypeMember(ft
)
514 members
= collections
.OrderedDict([
517 StructureFieldTypeMember(self
._features
.packet_features
.total_size_field_type
)
521 StructureFieldTypeMember(self
._features
.packet_features
.content_size_field_type
)
525 add_member_if_exists('timestamp_begin',
526 self
._features
.packet_features
.beginning_time_field_type
, True)
527 add_member_if_exists('timestamp_end', self
._features
.packet_features
.end_time_field_type
,
529 add_member_if_exists('events_discarded',
530 self
._features
.packet_features
.discarded_events_counter_field_type
)
532 if self
._packet
_context
_field
_type
_extra
_members
is not None:
533 for name
, field_type
in self
._packet
_context
_field
_type
_extra
_members
.items():
534 assert name
not in members
535 members
[name
] = field_type
537 self
._pkt
_ctx
_ft
= StructureFieldType(8, members
)
539 def _set_ev_header_ft(self
):
540 members
= collections
.OrderedDict()
542 if self
._features
.event_features
.type_id_field_type
is not None:
543 members
['id'] = StructureFieldTypeMember(self
._features
.event_features
.type_id_field_type
)
545 if self
._features
.event_features
.time_field_type
is not None:
546 ft
= self
._features
.event_features
.time_field_type
547 self
._set
_ft
_mapped
_clk
_type
_name
(ft
)
548 members
['timestamp'] = StructureFieldTypeMember(ft
)
550 self
._ev
_header
_ft
= StructureFieldType(8, members
)
561 def default_clock_type(self
):
562 return self
._default
_clock
_type
566 return self
._features
569 def packet_context_field_type_extra_members(self
):
570 return self
._packet
_context
_field
_type
_extra
_members
573 def event_common_context_field_type(self
):
574 return self
._event
_common
_context
_field
_type
577 def event_types(self
):
578 return self
._event
_types
581 class TraceTypeFeatures
:
582 def __init__(self
, magic_field_type
=DEFAULT_FIELD_TYPE
, uuid_field_type
=None,
583 stream_type_id_field_type
=DEFAULT_FIELD_TYPE
):
584 def get_field_type(user_field_type
, default_field_type
):
585 if user_field_type
== DEFAULT_FIELD_TYPE
:
586 return default_field_type
588 return user_field_type
590 self
._magic
_field
_type
= get_field_type(magic_field_type
, UnsignedIntegerFieldType(32))
591 self
._uuid
_field
_type
= get_field_type(uuid_field_type
,
592 StaticArrayFieldType(16, UnsignedIntegerFieldType(8)))
593 self
._stream
_type
_id
_field
_type
= get_field_type(stream_type_id_field_type
,
594 UnsignedIntegerFieldType(64))
597 def magic_field_type(self
):
598 return self
._magic
_field
_type
601 def uuid_field_type(self
):
602 return self
._uuid
_field
_type
605 def stream_type_id_field_type(self
):
606 return self
._stream
_type
_id
_field
_type
610 def __init__(self
, stream_types
, default_byte_order
, uuid
=None, features
=None):
611 self
._default
_byte
_order
= default_byte_order
612 self
._stream
_types
= frozenset(stream_types
)
615 for index
, stream_type
in enumerate(sorted(self
._stream
_types
, key
=lambda st
: st
.name
)):
616 assert stream_type
._id
is None
617 stream_type
._id
= index
620 self
._set
_features
(features
)
621 self
._set
_pkt
_header
_ft
()
622 self
._set
_fts
_effective
_byte
_order
()
624 def _set_features(self
, features
):
625 if features
is not None:
626 self
._features
= features
629 # automatic UUID field type because the trace type has a UUID
630 uuid_ft
= None if self
._uuid
is None else DEFAULT_FIELD_TYPE
631 self
._features
= TraceTypeFeatures(uuid_field_type
=uuid_ft
)
633 def _set_pkt_header_ft(self
):
634 def add_member_if_exists(name
, field_type
):
637 if field_type
is not None:
638 members
[name
] = StructureFieldTypeMember(field_type
)
640 members
= collections
.OrderedDict()
641 add_member_if_exists('magic', self
._features
.magic_field_type
)
642 add_member_if_exists('uuid', self
._features
.uuid_field_type
)
643 add_member_if_exists('stream_id', self
._features
.stream_type_id_field_type
)
644 self
._pkt
_header
_ft
= StructureFieldType(8, members
)
646 def _set_fts_effective_byte_order(self
):
647 def set_ft_effective_byte_order(ft
):
651 if isinstance(ft
, _BitArrayFieldType
):
652 if ft
._byte
_order
is None:
653 assert self
._default
_byte
_order
is not None
654 ft
._byte
_order
= self
._default
_byte
_order
655 elif isinstance(ft
, StaticArrayFieldType
):
656 set_ft_effective_byte_order(ft
.element_field_type
)
657 elif isinstance(ft
, StructureFieldType
):
658 for member
in ft
.members
.values():
659 set_ft_effective_byte_order(member
.field_type
)
661 # packet header field type
662 set_ft_effective_byte_order(self
._pkt
_header
_ft
)
664 # stream type field types
665 for stream_type
in self
._stream
_types
:
666 set_ft_effective_byte_order(stream_type
._pkt
_ctx
_ft
)
667 set_ft_effective_byte_order(stream_type
._ev
_header
_ft
)
668 set_ft_effective_byte_order(stream_type
._event
_common
_context
_field
_type
)
670 # event type field types
671 for ev_type
in stream_type
.event_types
:
672 set_ft_effective_byte_order(ev_type
._specific
_context
_field
_type
)
673 set_ft_effective_byte_order(ev_type
._payload
_field
_type
)
676 def default_byte_order(self
):
677 return self
._default
_byte
_order
684 def stream_types(self
):
685 return self
._stream
_types
687 def stream_type(self
, name
):
688 for cand_stream_type
in self
._stream
_types
:
689 if cand_stream_type
.name
== name
:
690 return cand_stream_type
694 return self
._features
697 class TraceEnvironment(collections
.abc
.Mapping
):
698 def __init__(self
, environment
):
699 self
._env
= {name
: value
for name
, value
in environment
.items()}
701 def __getitem__(self
, key
):
702 return self
._env
[key
]
705 return iter(self
._env
)
708 return len(self
._env
)
712 def __init__(self
, type, environment
=None):
714 self
._set
_env
(environment
)
716 def _set_env(self
, environment
):
717 init_env
= collections
.OrderedDict([
719 ('tracer_name', 'barectf'),
720 ('tracer_major', barectf_version
.__major
_version
__),
721 ('tracer_minor', barectf_version
.__minor
_version
__),
722 ('tracer_patch', barectf_version
.__patch
_version
__),
723 ('barectf_gen_date', str(datetime
.datetime
.now().isoformat())),
726 if environment
is None:
729 init_env
.update(environment
)
730 self
._env
= TraceEnvironment(init_env
)
737 def environment(self
):
741 class ClockTypeCTypes(collections
.abc
.Mapping
):
742 def __init__(self
, c_types
):
743 self
._c
_types
= {clk_type
: c_type
for clk_type
, c_type
in c_types
.items()}
745 def __getitem__(self
, key
):
746 return self
._c
_types
[key
]
749 return iter(self
._c
_types
)
752 return len(self
._c
_types
)
755 class ConfigurationCodeGenerationHeaderOptions
:
756 def __init__(self
, identifier_prefix_definition
=False,
757 default_stream_type_name_definition
=False):
758 self
._identifier
_prefix
_definition
= identifier_prefix_definition
759 self
._default
_stream
_type
_name
_definition
= default_stream_type_name_definition
762 def identifier_prefix_definition(self
):
763 return self
._identifier
_prefix
_definition
766 def default_stream_type_name_definition(self
):
767 return self
._default
_stream
_type
_name
_definition
770 class ConfigurationCodeGenerationOptions
:
771 def __init__(self
, identifier_prefix
='barectf_', file_name_prefix
='barectf',
772 default_stream_type
=None, header_options
=None, clock_type_c_types
=None):
773 self
._identifier
_prefix
= identifier_prefix
774 self
._file
_name
_prefix
= file_name_prefix
775 self
._default
_stream
_type
= default_stream_type
777 self
._header
_options
= ConfigurationCodeGenerationHeaderOptions()
779 if header_options
is not None:
780 self
._header
_options
= header_options
782 self
._clock
_type
_c
_types
= ClockTypeCTypes({})
784 if clock_type_c_types
is not None:
785 self
._clock
_type
_c
_types
= ClockTypeCTypes(clock_type_c_types
)
788 def identifier_prefix(self
):
789 return self
._identifier
_prefix
792 def file_name_prefix(self
):
793 return self
._file
_name
_prefix
796 def default_stream_type(self
):
797 return self
._default
_stream
_type
800 def header_options(self
):
801 return self
._header
_options
804 def clock_type_c_types(self
):
805 return self
._clock
_type
_c
_types
808 class ConfigurationOptions
:
809 def __init__(self
, code_generation_options
=None):
810 self
._code
_generation
_options
= ConfigurationCodeGenerationOptions()
812 if code_generation_options
is not None:
813 self
._code
_generation
_options
= code_generation_options
816 def code_generation_options(self
):
817 return self
._code
_generation
_options
821 def __init__(self
, trace
, options
=None):
823 self
._options
= ConfigurationOptions()
825 if options
is not None:
826 self
._options
= options
828 clk_type_c_types
= self
._options
.code_generation_options
.clock_type_c_types
830 for stream_type
in trace
.type.stream_types
:
831 def_clk_type
= stream_type
.default_clock_type
833 if def_clk_type
is None:
836 if def_clk_type
not in clk_type_c_types
:
837 clk_type_c_types
._c
_types
[def_clk_type
] = 'uint32_t'