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
.config_parse
as barectf_config_parse
25 import barectf
.version
as barectf_version
26 import collections
.abc
33 class ByteOrder(enum
.Enum
):
41 raise NotImplementedError
44 class _BitArrayFieldType(_FieldType
):
45 def __init__(self
, size
, byte_order
=None, alignment
=1):
47 self
._byte
_order
= byte_order
48 self
._alignment
= alignment
56 return self
._byte
_order
60 return self
._alignment
63 class DisplayBase(enum
.Enum
):
70 class _IntegerFieldType(_BitArrayFieldType
):
71 def __init__(self
, size
, byte_order
=None, alignment
=None,
72 preferred_display_base
=DisplayBase
.DECIMAL
):
73 effective_alignment
= 1
75 if alignment
is None and size
% 8 == 0:
76 effective_alignment
= 8
78 super().__init
__(size
, byte_order
, effective_alignment
)
79 self
._preferred
_display
_base
= preferred_display_base
82 def preferred_display_base(self
):
83 return self
._preferred
_display
_base
86 class UnsignedIntegerFieldType(_IntegerFieldType
):
87 def __init__(self
, *args
):
88 super().__init
__(*args
)
89 self
._mapped
_clk
_type
_name
= None
92 class SignedIntegerFieldType(_IntegerFieldType
):
96 class EnumerationFieldTypeMappingRange
:
97 def __init__(self
, lower
, upper
):
109 def __eq__(self
, other
):
110 if type(other
) is not type(self
):
113 return (self
._lower
, self
._upper
) == (other
._lower
, other
._upper
)
116 return hash((self
._lower
, self
._upper
))
118 def contains(self
, value
):
119 return self
._lower
<= value
<= self
._upper
122 class EnumerationFieldTypeMapping
:
123 def __init__(self
, ranges
):
124 self
._ranges
= frozenset(ranges
)
130 def ranges_contain_value(self
, value
):
131 return any([rg
.contains(value
) for rg
in self
._ranges
])
134 class EnumerationFieldTypeMappings(collections
.abc
.Mapping
):
135 def __init__(self
, mappings
):
136 self
._mappings
= {label
: mapping
for label
, mapping
in mappings
.items()}
138 def __getitem__(self
, key
):
139 return self
._mappings
[key
]
142 return iter(self
._mappings
)
145 return len(self
._mappings
)
148 class _EnumerationFieldType(_IntegerFieldType
):
149 def __init__(self
, size
, byte_order
=None, alignment
=None,
150 preferred_display_base
=DisplayBase
.DECIMAL
, mappings
=None):
151 super().__init
__(size
, byte_order
, alignment
, preferred_display_base
)
152 self
._mappings
= EnumerationFieldTypeMappings({})
154 if mappings
is not None:
155 self
._mappings
= EnumerationFieldTypeMappings(mappings
)
159 return self
._mappings
161 def labels_for_value(self
, value
):
164 for label
, mapping
in self
._mappings
.items():
165 if mapping
.ranges_contain_value(value
):
171 class UnsignedEnumerationFieldType(_EnumerationFieldType
, UnsignedIntegerFieldType
):
175 class SignedEnumerationFieldType(_EnumerationFieldType
, SignedIntegerFieldType
):
179 class RealFieldType(_BitArrayFieldType
):
183 class StringFieldType(_FieldType
):
189 class _ArrayFieldType(_FieldType
):
190 def __init__(self
, element_field_type
):
191 self
._element
_field
_type
= element_field_type
194 def element_field_type(self
):
195 return self
._element
_field
_type
199 return self
._element
_field
_type
.alignment
202 class StaticArrayFieldType(_ArrayFieldType
):
203 def __init__(self
, length
, element_field_type
):
204 super().__init
__(element_field_type
)
205 self
._length
= length
212 class StructureFieldTypeMember
:
213 def __init__(self
, field_type
):
214 self
._field
_type
= field_type
217 def field_type(self
):
218 return self
._field
_type
221 class StructureFieldTypeMembers(collections
.abc
.Mapping
):
222 def __init__(self
, members
):
223 self
._members
= collections
.OrderedDict()
225 for name
, member
in members
.items():
226 assert type(member
) is StructureFieldTypeMember
227 self
._members
[name
] = member
229 def __getitem__(self
, key
):
230 return self
._members
[key
]
233 return iter(self
._members
)
236 return len(self
._members
)
239 class StructureFieldType(_FieldType
):
240 def __init__(self
, minimum_alignment
=1, members
=None):
241 self
._minimum
_alignment
= minimum_alignment
242 self
._members
= StructureFieldTypeMembers({})
244 if members
is not None:
245 self
._members
= StructureFieldTypeMembers(members
)
247 self
._set
_alignment
()
249 def _set_alignment(self
):
250 self
._alignment
= self
._minimum
_alignment
252 for member
in self
._members
.values():
253 if member
.field_type
.alignment
> self
._alignment
:
254 self
._alignment
= member
.field_type
.alignment
257 def minimum_alignment(self
):
258 return self
._minimum
_alignment
262 return self
._alignment
270 def __eq__(self
, other
):
271 if type(other
) is not type(self
):
274 return self
._name
== other
._name
276 def __lt__(self
, other
):
277 assert type(self
) is type(other
)
278 return self
._name
< other
._name
281 return hash(self
._name
)
284 class EventType(_UniqueByName
):
285 def __init__(self
, name
, log_level
=None, specific_context_field_type
=None,
286 payload_field_type
=None):
289 self
._log
_level
= log_level
290 self
._specific
_context
_field
_type
= specific_context_field_type
291 self
._payload
_field
_type
= payload_field_type
303 return self
._log
_level
306 def specific_context_field_type(self
):
307 return self
._specific
_context
_field
_type
310 def payload_field_type(self
):
311 return self
._payload
_field
_type
314 class ClockTypeOffset
:
315 def __init__(self
, seconds
=0, cycles
=0):
316 self
._seconds
= seconds
317 self
._cycles
= cycles
328 class ClockType(_UniqueByName
):
329 def __init__(self
, name
, frequency
=int(1e9
), uuid
=None, description
=None, precision
=0,
330 offset
=None, origin_is_unix_epoch
=False):
332 self
._frequency
= frequency
334 self
._description
= description
335 self
._precision
= precision
336 self
._offset
= ClockTypeOffset()
338 if offset
is not None:
339 self
._offset
= offset
341 self
._origin
_is
_unix
_epoch
= origin_is_unix_epoch
349 return self
._frequency
356 def description(self
):
357 return self
._description
361 return self
._precision
368 def origin_is_unix_epoch(self
):
369 return self
._origin
_is
_unix
_epoch
372 DEFAULT_FIELD_TYPE
= 'default'
375 class StreamTypePacketFeatures
:
376 def __init__(self
, total_size_field_type
=DEFAULT_FIELD_TYPE
,
377 content_size_field_type
=DEFAULT_FIELD_TYPE
, beginning_time_field_type
=None,
378 end_time_field_type
=None, discarded_events_counter_field_type
=None):
380 if user_ft
== DEFAULT_FIELD_TYPE
:
381 return UnsignedIntegerFieldType(64)
385 self
._total
_size
_field
_type
= get_ft(total_size_field_type
)
386 self
._content
_size
_field
_type
= get_ft(content_size_field_type
)
387 self
._beginning
_time
_field
_type
= get_ft(beginning_time_field_type
)
388 self
._end
_time
_field
_type
= get_ft(end_time_field_type
)
389 self
._discarded
_events
_counter
_field
_type
= get_ft(discarded_events_counter_field_type
)
392 def total_size_field_type(self
):
393 return self
._total
_size
_field
_type
396 def content_size_field_type(self
):
397 return self
._content
_size
_field
_type
400 def beginning_time_field_type(self
):
401 return self
._beginning
_time
_field
_type
404 def end_time_field_type(self
):
405 return self
._end
_time
_field
_type
408 def discarded_events_counter_field_type(self
):
409 return self
._discarded
_events
_counter
_field
_type
412 class StreamTypeEventFeatures
:
413 def __init__(self
, type_id_field_type
=DEFAULT_FIELD_TYPE
, time_field_type
=None):
414 def get_ft(user_field_type
):
415 if user_field_type
== DEFAULT_FIELD_TYPE
:
416 return UnsignedIntegerFieldType(64)
418 return user_field_type
420 self
._type
_id
_field
_type
= get_ft(type_id_field_type
)
421 self
._time
_field
_type
= get_ft(time_field_type
)
424 def type_id_field_type(self
):
425 return self
._type
_id
_field
_type
428 def time_field_type(self
):
429 return self
._time
_field
_type
432 class StreamTypeFeatures
:
433 def __init__(self
, packet_features
=None, event_features
=None):
434 self
._packet
_features
= StreamTypePacketFeatures()
436 if packet_features
is not None:
437 self
._packet
_features
= packet_features
439 self
._event
_features
= StreamTypeEventFeatures()
441 if event_features
is not None:
442 self
._event
_features
= event_features
445 def packet_features(self
):
446 return self
._packet
_features
449 def event_features(self
):
450 return self
._event
_features
453 class StreamType(_UniqueByName
):
454 def __init__(self
, name
, event_types
, default_clock_type
=None, features
=None,
455 packet_context_field_type_extra_members
=None,
456 event_common_context_field_type
=None):
459 self
._default
_clock
_type
= default_clock_type
460 self
._event
_common
_context
_field
_type
= event_common_context_field_type
461 self
._event
_types
= frozenset(event_types
)
464 for index
, ev_type
in enumerate(sorted(self
._event
_types
, key
=lambda evt
: evt
.name
)):
465 assert ev_type
._id
is None
468 self
._set
_features
(features
)
469 self
._packet
_context
_field
_type
_extra
_members
= StructureFieldTypeMembers({})
471 if packet_context_field_type_extra_members
is not None:
472 self
._packet
_context
_field
_type
_extra
_members
= StructureFieldTypeMembers(packet_context_field_type_extra_members
)
474 self
._set
_pkt
_ctx
_ft
()
475 self
._set
_ev
_header
_ft
()
477 def _set_features(self
, features
):
478 if features
is not None:
479 self
._features
= features
483 pkt_beginning_time_ft
= None
484 pkt_end_time_ft
= None
486 if self
._default
_clock
_type
is not None:
487 # Automatic time field types because the stream type has a
488 # default clock type.
489 ev_time_ft
= DEFAULT_FIELD_TYPE
490 pkt_beginning_time_ft
= DEFAULT_FIELD_TYPE
491 pkt_end_time_ft
= DEFAULT_FIELD_TYPE
493 self
._features
= StreamTypeFeatures(StreamTypePacketFeatures(beginning_time_field_type
=pkt_beginning_time_ft
,
494 end_time_field_type
=pkt_end_time_ft
),
495 StreamTypeEventFeatures(time_field_type
=ev_time_ft
))
497 def _set_ft_mapped_clk_type_name(self
, ft
):
501 if self
._default
_clock
_type
is not None:
502 assert isinstance(ft
, UnsignedIntegerFieldType
)
503 ft
._mapped
_clk
_type
_name
= self
._default
_clock
_type
.name
505 def _set_pkt_ctx_ft(self
):
506 def add_member_if_exists(name
, ft
, set_mapped_clk_type_name
=False):
510 if set_mapped_clk_type_name
:
511 self
._set
_ft
_mapped
_clk
_type
_name
(ft
)
513 members
[name
] = StructureFieldTypeMember(ft
)
515 members
= collections
.OrderedDict([
518 StructureFieldTypeMember(self
._features
.packet_features
.total_size_field_type
)
522 StructureFieldTypeMember(self
._features
.packet_features
.content_size_field_type
)
526 add_member_if_exists('timestamp_begin',
527 self
._features
.packet_features
.beginning_time_field_type
, True)
528 add_member_if_exists('timestamp_end', self
._features
.packet_features
.end_time_field_type
,
530 add_member_if_exists('events_discarded',
531 self
._features
.packet_features
.discarded_events_counter_field_type
)
533 if self
._packet
_context
_field
_type
_extra
_members
is not None:
534 for name
, field_type
in self
._packet
_context
_field
_type
_extra
_members
.items():
535 assert name
not in members
536 members
[name
] = field_type
538 self
._pkt
_ctx
_ft
= StructureFieldType(8, members
)
540 def _set_ev_header_ft(self
):
541 members
= collections
.OrderedDict()
543 if self
._features
.event_features
.type_id_field_type
is not None:
544 members
['id'] = StructureFieldTypeMember(self
._features
.event_features
.type_id_field_type
)
546 if self
._features
.event_features
.time_field_type
is not None:
547 ft
= self
._features
.event_features
.time_field_type
548 self
._set
_ft
_mapped
_clk
_type
_name
(ft
)
549 members
['timestamp'] = StructureFieldTypeMember(ft
)
551 self
._ev
_header
_ft
= StructureFieldType(8, members
)
562 def default_clock_type(self
):
563 return self
._default
_clock
_type
567 return self
._features
570 def packet_context_field_type_extra_members(self
):
571 return self
._packet
_context
_field
_type
_extra
_members
574 def event_common_context_field_type(self
):
575 return self
._event
_common
_context
_field
_type
578 def event_types(self
):
579 return self
._event
_types
582 class TraceTypeFeatures
:
583 def __init__(self
, magic_field_type
=DEFAULT_FIELD_TYPE
, uuid_field_type
=None,
584 stream_type_id_field_type
=DEFAULT_FIELD_TYPE
):
585 def get_field_type(user_field_type
, default_field_type
):
586 if user_field_type
== DEFAULT_FIELD_TYPE
:
587 return default_field_type
589 return user_field_type
591 self
._magic
_field
_type
= get_field_type(magic_field_type
, UnsignedIntegerFieldType(32))
592 self
._uuid
_field
_type
= get_field_type(uuid_field_type
,
593 StaticArrayFieldType(16, UnsignedIntegerFieldType(8)))
594 self
._stream
_type
_id
_field
_type
= get_field_type(stream_type_id_field_type
,
595 UnsignedIntegerFieldType(64))
598 def magic_field_type(self
):
599 return self
._magic
_field
_type
602 def uuid_field_type(self
):
603 return self
._uuid
_field
_type
606 def stream_type_id_field_type(self
):
607 return self
._stream
_type
_id
_field
_type
611 def __init__(self
, stream_types
, default_byte_order
, uuid
=None, features
=None):
612 self
._default
_byte
_order
= default_byte_order
613 self
._stream
_types
= frozenset(stream_types
)
616 for index
, stream_type
in enumerate(sorted(self
._stream
_types
, key
=lambda st
: st
.name
)):
617 assert stream_type
._id
is None
618 stream_type
._id
= index
621 self
._set
_features
(features
)
622 self
._set
_pkt
_header
_ft
()
623 self
._set
_fts
_effective
_byte
_order
()
625 def _set_features(self
, features
):
626 if features
is not None:
627 self
._features
= features
630 # automatic UUID field type because the trace type has a UUID
631 uuid_ft
= None if self
._uuid
is None else DEFAULT_FIELD_TYPE
632 self
._features
= TraceTypeFeatures(uuid_field_type
=uuid_ft
)
634 def _set_pkt_header_ft(self
):
635 def add_member_if_exists(name
, field_type
):
638 if field_type
is not None:
639 members
[name
] = StructureFieldTypeMember(field_type
)
641 members
= collections
.OrderedDict()
642 add_member_if_exists('magic', self
._features
.magic_field_type
)
643 add_member_if_exists('uuid', self
._features
.uuid_field_type
)
644 add_member_if_exists('stream_id', self
._features
.stream_type_id_field_type
)
645 self
._pkt
_header
_ft
= StructureFieldType(8, members
)
647 def _set_fts_effective_byte_order(self
):
648 def set_ft_effective_byte_order(ft
):
652 if isinstance(ft
, _BitArrayFieldType
):
653 if ft
._byte
_order
is None:
654 assert self
._default
_byte
_order
is not None
655 ft
._byte
_order
= self
._default
_byte
_order
656 elif isinstance(ft
, StaticArrayFieldType
):
657 set_ft_effective_byte_order(ft
.element_field_type
)
658 elif isinstance(ft
, StructureFieldType
):
659 for member
in ft
.members
.values():
660 set_ft_effective_byte_order(member
.field_type
)
662 # packet header field type
663 set_ft_effective_byte_order(self
._pkt
_header
_ft
)
665 # stream type field types
666 for stream_type
in self
._stream
_types
:
667 set_ft_effective_byte_order(stream_type
._pkt
_ctx
_ft
)
668 set_ft_effective_byte_order(stream_type
._ev
_header
_ft
)
669 set_ft_effective_byte_order(stream_type
._event
_common
_context
_field
_type
)
671 # event type field types
672 for ev_type
in stream_type
.event_types
:
673 set_ft_effective_byte_order(ev_type
._specific
_context
_field
_type
)
674 set_ft_effective_byte_order(ev_type
._payload
_field
_type
)
677 def default_byte_order(self
):
678 return self
._default
_byte
_order
685 def stream_types(self
):
686 return self
._stream
_types
688 def stream_type(self
, name
):
689 for cand_stream_type
in self
._stream
_types
:
690 if cand_stream_type
.name
== name
:
691 return cand_stream_type
695 return self
._features
698 class TraceEnvironment(collections
.abc
.Mapping
):
699 def __init__(self
, environment
):
700 self
._env
= {name
: value
for name
, value
in environment
.items()}
702 def __getitem__(self
, key
):
703 return self
._env
[key
]
706 return iter(self
._env
)
709 return len(self
._env
)
713 def __init__(self
, type, environment
=None):
715 self
._set
_env
(environment
)
717 def _set_env(self
, environment
):
718 init_env
= collections
.OrderedDict([
720 ('tracer_name', 'barectf'),
721 ('tracer_major', barectf_version
.__major
_version
__),
722 ('tracer_minor', barectf_version
.__minor
_version
__),
723 ('tracer_patch', barectf_version
.__patch
_version
__),
724 ('barectf_gen_date', str(datetime
.datetime
.now().isoformat())),
727 if environment
is None:
730 init_env
.update(environment
)
731 self
._env
= TraceEnvironment(init_env
)
738 def environment(self
):
742 class ClockTypeCTypes(collections
.abc
.Mapping
):
743 def __init__(self
, c_types
):
744 self
._c
_types
= {clk_type
: c_type
for clk_type
, c_type
in c_types
.items()}
746 def __getitem__(self
, key
):
747 return self
._c
_types
[key
]
750 return iter(self
._c
_types
)
753 return len(self
._c
_types
)
756 class ConfigurationCodeGenerationHeaderOptions
:
757 def __init__(self
, identifier_prefix_definition
=False,
758 default_stream_type_name_definition
=False):
759 self
._identifier
_prefix
_definition
= identifier_prefix_definition
760 self
._default
_stream
_type
_name
_definition
= default_stream_type_name_definition
763 def identifier_prefix_definition(self
):
764 return self
._identifier
_prefix
_definition
767 def default_stream_type_name_definition(self
):
768 return self
._default
_stream
_type
_name
_definition
771 class ConfigurationCodeGenerationOptions
:
772 def __init__(self
, identifier_prefix
='barectf_', file_name_prefix
='barectf',
773 default_stream_type
=None, header_options
=None, clock_type_c_types
=None):
774 self
._identifier
_prefix
= identifier_prefix
775 self
._file
_name
_prefix
= file_name_prefix
776 self
._default
_stream
_type
= default_stream_type
778 self
._header
_options
= ConfigurationCodeGenerationHeaderOptions()
780 if header_options
is not None:
781 self
._header
_options
= header_options
783 self
._clock
_type
_c
_types
= ClockTypeCTypes({})
785 if clock_type_c_types
is not None:
786 self
._clock
_type
_c
_types
= ClockTypeCTypes(clock_type_c_types
)
789 def identifier_prefix(self
):
790 return self
._identifier
_prefix
793 def file_name_prefix(self
):
794 return self
._file
_name
_prefix
797 def default_stream_type(self
):
798 return self
._default
_stream
_type
801 def header_options(self
):
802 return self
._header
_options
805 def clock_type_c_types(self
):
806 return self
._clock
_type
_c
_types
809 class ConfigurationOptions
:
810 def __init__(self
, code_generation_options
=None):
811 self
._code
_generation
_options
= ConfigurationCodeGenerationOptions()
813 if code_generation_options
is not None:
814 self
._code
_generation
_options
= code_generation_options
817 def code_generation_options(self
):
818 return self
._code
_generation
_options
822 def __init__(self
, trace
, options
=None):
824 self
._options
= ConfigurationOptions()
826 if options
is not None:
827 self
._options
= options
829 clk_type_c_types
= self
._options
.code_generation_options
.clock_type_c_types
831 for stream_type
in trace
.type.stream_types
:
832 def_clk_type
= stream_type
.default_clock_type
834 if def_clk_type
is None:
837 if def_clk_type
not in clk_type_c_types
:
838 clk_type_c_types
._c
_types
[def_clk_type
] = 'uint32_t'
849 def effective_configuration_file(file, inclusion_dirs
, ignore_inclusion_not_found
,
850 indent_space_count
=2):
851 return barectf_config_parse
._effective
_config
_file
(file, inclusion_dirs
,
852 ignore_inclusion_not_found
,
856 def configuration_from_file(file, inclusion_dirs
, ignore_inclusion_not_found
):
857 return barectf_config_parse
._from
_file
(file, inclusion_dirs
, ignore_inclusion_not_found
)
860 def configuration_file_major_version(file):
861 return barectf_config_parse
._config
_file
_major
_version
(file)