Commit | Line | Data |
---|---|---|
e5aa0be3 PP |
1 | # The MIT License (MIT) |
2 | # | |
4a90140d | 3 | # Copyright (c) 2015-2020 Philippe Proulx <pproulx@efficios.com> |
e5aa0be3 | 4 | # |
1378f213 PP |
5 | # Permission is hereby granted, free of charge, to any person obtaining |
6 | # a copy of this software and associated documentation files (the | |
7 | # "Software"), to deal in the Software without restriction, including | |
8 | # without limitation the rights to use, copy, modify, merge, publish, | |
9 | # distribute, sublicense, and/or sell copies of the Software, and to | |
10 | # permit persons to whom the Software is furnished to do so, subject to | |
11 | # the following conditions: | |
e5aa0be3 | 12 | # |
1378f213 PP |
13 | # The above copyright notice and this permission notice shall be |
14 | # included in all copies or substantial portions of the Software. | |
e5aa0be3 | 15 | # |
1378f213 PP |
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
17 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
18 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
19 | # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
20 | # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
21 | # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |
22 | # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
e5aa0be3 | 23 | |
4810b707 | 24 | import barectf.version as barectf_version |
2d55dc7d PP |
25 | from typing import Optional, Any, FrozenSet, Mapping, Iterator, Set, Union |
26 | import typing | |
27 | from barectf.typing import Count, Alignment, _OptStr, Id | |
4810b707 PP |
28 | import collections.abc |
29 | import collections | |
30 | import datetime | |
31 | import enum | |
2d55dc7d | 32 | import uuid as uuidp |
e5aa0be3 PP |
33 | |
34 | ||
4810b707 PP |
35 | @enum.unique |
36 | class ByteOrder(enum.Enum): | |
37 | LITTLE_ENDIAN = 'le' | |
38 | BIG_ENDIAN = 'be' | |
e5aa0be3 PP |
39 | |
40 | ||
4810b707 PP |
41 | class _FieldType: |
42 | @property | |
2d55dc7d | 43 | def alignment(self) -> Alignment: |
4810b707 | 44 | raise NotImplementedError |
a1a610d4 | 45 | |
1960170e PP |
46 | @property |
47 | def size_is_dynamic(self): | |
48 | return False | |
49 | ||
e5aa0be3 | 50 | |
4810b707 | 51 | class _BitArrayFieldType(_FieldType): |
2d55dc7d PP |
52 | def __init__(self, size: Count, byte_order: Optional[ByteOrder] = None, |
53 | alignment: Alignment = Alignment(1)): | |
4810b707 PP |
54 | self._size = size |
55 | self._byte_order = byte_order | |
56 | self._alignment = alignment | |
e5aa0be3 PP |
57 | |
58 | @property | |
2d55dc7d | 59 | def size(self) -> Count: |
4810b707 | 60 | return self._size |
e5aa0be3 | 61 | |
e5aa0be3 | 62 | @property |
2d55dc7d | 63 | def byte_order(self) -> Optional[ByteOrder]: |
4810b707 | 64 | return self._byte_order |
e5aa0be3 | 65 | |
893854db | 66 | @property |
2d55dc7d | 67 | def alignment(self) -> Alignment: |
4810b707 PP |
68 | return self._alignment |
69 | ||
70 | ||
71 | class DisplayBase(enum.Enum): | |
72 | BINARY = 2 | |
73 | OCTAL = 8 | |
74 | DECIMAL = 10 | |
75 | HEXADECIMAL = 16 | |
76 | ||
77 | ||
78 | class _IntegerFieldType(_BitArrayFieldType): | |
2d55dc7d PP |
79 | def __init__(self, size: Count, byte_order: Optional[ByteOrder] = None, |
80 | alignment: Optional[Alignment] = None, | |
81 | preferred_display_base: DisplayBase = DisplayBase.DECIMAL): | |
5833e4da PP |
82 | if alignment is None: |
83 | alignment = Alignment(8 if size % 8 == 0 else 1) | |
4810b707 | 84 | |
5833e4da | 85 | super().__init__(size, byte_order, alignment) |
4810b707 PP |
86 | self._preferred_display_base = preferred_display_base |
87 | ||
88 | @property | |
2d55dc7d | 89 | def preferred_display_base(self) -> DisplayBase: |
4810b707 PP |
90 | return self._preferred_display_base |
91 | ||
92 | ||
93 | class UnsignedIntegerFieldType(_IntegerFieldType): | |
94 | def __init__(self, *args): | |
95 | super().__init__(*args) | |
96 | self._mapped_clk_type_name = None | |
97 | ||
98 | ||
99 | class SignedIntegerFieldType(_IntegerFieldType): | |
100 | pass | |
101 | ||
102 | ||
103 | class EnumerationFieldTypeMappingRange: | |
2d55dc7d | 104 | def __init__(self, lower: int, upper: int): |
4810b707 PP |
105 | self._lower = lower |
106 | self._upper = upper | |
107 | ||
108 | @property | |
2d55dc7d | 109 | def lower(self) -> int: |
4810b707 PP |
110 | return self._lower |
111 | ||
112 | @property | |
2d55dc7d | 113 | def upper(self) -> int: |
4810b707 PP |
114 | return self._upper |
115 | ||
2d55dc7d | 116 | def __eq__(self, other: Any) -> bool: |
4810b707 PP |
117 | if type(other) is not type(self): |
118 | return False | |
119 | ||
120 | return (self._lower, self._upper) == (other._lower, other._upper) | |
121 | ||
2d55dc7d | 122 | def __hash__(self) -> int: |
4810b707 PP |
123 | return hash((self._lower, self._upper)) |
124 | ||
2d55dc7d | 125 | def contains(self, value: int) -> bool: |
4810b707 PP |
126 | return self._lower <= value <= self._upper |
127 | ||
128 | ||
129 | class EnumerationFieldTypeMapping: | |
2d55dc7d | 130 | def __init__(self, ranges: Set[EnumerationFieldTypeMappingRange]): |
4810b707 PP |
131 | self._ranges = frozenset(ranges) |
132 | ||
133 | @property | |
2d55dc7d | 134 | def ranges(self) -> FrozenSet[EnumerationFieldTypeMappingRange]: |
4810b707 PP |
135 | return self._ranges |
136 | ||
2d55dc7d | 137 | def ranges_contain_value(self, value: int) -> bool: |
4810b707 PP |
138 | return any([rg.contains(value) for rg in self._ranges]) |
139 | ||
140 | ||
2d55dc7d PP |
141 | _EnumFtMappings = Mapping[str, EnumerationFieldTypeMapping] |
142 | ||
143 | ||
4810b707 | 144 | class EnumerationFieldTypeMappings(collections.abc.Mapping): |
2d55dc7d | 145 | def __init__(self, mappings: _EnumFtMappings): |
4810b707 PP |
146 | self._mappings = {label: mapping for label, mapping in mappings.items()} |
147 | ||
2d55dc7d | 148 | def __getitem__(self, key: str) -> EnumerationFieldTypeMapping: |
4810b707 PP |
149 | return self._mappings[key] |
150 | ||
2d55dc7d | 151 | def __iter__(self) -> Iterator[str]: |
4810b707 PP |
152 | return iter(self._mappings) |
153 | ||
2d55dc7d | 154 | def __len__(self) -> int: |
4810b707 | 155 | return len(self._mappings) |
893854db | 156 | |
893854db | 157 | |
4810b707 | 158 | class _EnumerationFieldType(_IntegerFieldType): |
2d55dc7d PP |
159 | def __init__(self, size: Count, byte_order: Optional[ByteOrder] = None, |
160 | alignment: Optional[Alignment] = None, | |
161 | preferred_display_base: DisplayBase = DisplayBase.DECIMAL, | |
162 | mappings: Optional[_EnumFtMappings] = None): | |
4810b707 PP |
163 | super().__init__(size, byte_order, alignment, preferred_display_base) |
164 | self._mappings = EnumerationFieldTypeMappings({}) | |
165 | ||
166 | if mappings is not None: | |
167 | self._mappings = EnumerationFieldTypeMappings(mappings) | |
168 | ||
169 | @property | |
2d55dc7d | 170 | def mappings(self) -> EnumerationFieldTypeMappings: |
4810b707 PP |
171 | return self._mappings |
172 | ||
2d55dc7d | 173 | def labels_for_value(self, value: int) -> Set[str]: |
4810b707 PP |
174 | labels = set() |
175 | ||
176 | for label, mapping in self._mappings.items(): | |
177 | if mapping.ranges_contain_value(value): | |
178 | labels.add(label) | |
179 | ||
180 | return labels | |
181 | ||
182 | ||
183 | class UnsignedEnumerationFieldType(_EnumerationFieldType, UnsignedIntegerFieldType): | |
184 | pass | |
185 | ||
186 | ||
187 | class SignedEnumerationFieldType(_EnumerationFieldType, SignedIntegerFieldType): | |
188 | pass | |
189 | ||
190 | ||
191 | class RealFieldType(_BitArrayFieldType): | |
192 | pass | |
193 | ||
194 | ||
195 | class StringFieldType(_FieldType): | |
196 | @property | |
2d55dc7d PP |
197 | def alignment(self) -> Alignment: |
198 | return Alignment(8) | |
4810b707 | 199 | |
1960170e PP |
200 | @property |
201 | def size_is_dynamic(self): | |
202 | return True | |
203 | ||
4810b707 PP |
204 | |
205 | class _ArrayFieldType(_FieldType): | |
2d55dc7d | 206 | def __init__(self, element_field_type: _FieldType): |
4810b707 PP |
207 | self._element_field_type = element_field_type |
208 | ||
209 | @property | |
2d55dc7d | 210 | def element_field_type(self) -> _FieldType: |
4810b707 | 211 | return self._element_field_type |
893854db PP |
212 | |
213 | @property | |
2d55dc7d | 214 | def alignment(self) -> Alignment: |
4810b707 PP |
215 | return self._element_field_type.alignment |
216 | ||
217 | ||
218 | class StaticArrayFieldType(_ArrayFieldType): | |
2d55dc7d | 219 | def __init__(self, length: Count, element_field_type: _FieldType): |
4810b707 PP |
220 | super().__init__(element_field_type) |
221 | self._length = length | |
893854db | 222 | |
893854db | 223 | @property |
2d55dc7d | 224 | def length(self) -> Count: |
4810b707 PP |
225 | return self._length |
226 | ||
227 | ||
228 | class StructureFieldTypeMember: | |
2d55dc7d | 229 | def __init__(self, field_type: _FieldType): |
4810b707 PP |
230 | self._field_type = field_type |
231 | ||
232 | @property | |
2d55dc7d | 233 | def field_type(self) -> _FieldType: |
4810b707 PP |
234 | return self._field_type |
235 | ||
236 | ||
2d55dc7d PP |
237 | _StructFtMembers = Mapping[str, StructureFieldTypeMember] |
238 | ||
239 | ||
4810b707 | 240 | class StructureFieldTypeMembers(collections.abc.Mapping): |
2d55dc7d | 241 | def __init__(self, members: _StructFtMembers): |
4810b707 PP |
242 | self._members = collections.OrderedDict() |
243 | ||
244 | for name, member in members.items(): | |
245 | assert type(member) is StructureFieldTypeMember | |
246 | self._members[name] = member | |
247 | ||
2d55dc7d | 248 | def __getitem__(self, key: str) -> StructureFieldTypeMember: |
4810b707 PP |
249 | return self._members[key] |
250 | ||
2d55dc7d | 251 | def __iter__(self) -> Iterator[str]: |
4810b707 PP |
252 | return iter(self._members) |
253 | ||
2d55dc7d | 254 | def __len__(self) -> int: |
4810b707 PP |
255 | return len(self._members) |
256 | ||
257 | ||
258 | class StructureFieldType(_FieldType): | |
2d55dc7d PP |
259 | def __init__(self, minimum_alignment: Alignment = Alignment(1), |
260 | members: Optional[_StructFtMembers] = None): | |
4810b707 PP |
261 | self._minimum_alignment = minimum_alignment |
262 | self._members = StructureFieldTypeMembers({}) | |
263 | ||
264 | if members is not None: | |
265 | self._members = StructureFieldTypeMembers(members) | |
266 | ||
267 | self._set_alignment() | |
268 | ||
269 | def _set_alignment(self): | |
2d55dc7d | 270 | self._alignment: Alignment = self._minimum_alignment |
4810b707 PP |
271 | |
272 | for member in self._members.values(): | |
273 | if member.field_type.alignment > self._alignment: | |
274 | self._alignment = member.field_type.alignment | |
275 | ||
276 | @property | |
2d55dc7d | 277 | def minimum_alignment(self) -> Alignment: |
4810b707 PP |
278 | return self._minimum_alignment |
279 | ||
280 | @property | |
2d55dc7d | 281 | def alignment(self) -> Alignment: |
4810b707 PP |
282 | return self._alignment |
283 | ||
1960170e PP |
284 | @property |
285 | def size_is_dynamic(self): | |
286 | return any([member.field_type.size_is_dynamic for member in self.members.values()]) | |
287 | ||
4810b707 | 288 | @property |
2d55dc7d | 289 | def members(self) -> StructureFieldTypeMembers: |
4810b707 PP |
290 | return self._members |
291 | ||
292 | ||
293 | class _UniqueByName: | |
2d55dc7d PP |
294 | _name: str |
295 | ||
296 | def __eq__(self, other: Any) -> bool: | |
4810b707 PP |
297 | if type(other) is not type(self): |
298 | return False | |
299 | ||
300 | return self._name == other._name | |
301 | ||
2d55dc7d | 302 | def __lt__(self, other: '_UniqueByName'): |
4810b707 PP |
303 | assert type(self) is type(other) |
304 | return self._name < other._name | |
305 | ||
2d55dc7d | 306 | def __hash__(self) -> int: |
4810b707 PP |
307 | return hash(self._name) |
308 | ||
309 | ||
2d55dc7d PP |
310 | _OptFt = Optional[_FieldType] |
311 | _OptStructFt = Optional[StructureFieldType] | |
312 | LogLevel = typing.NewType('LogLevel', int) | |
313 | ||
314 | ||
4810b707 | 315 | class EventType(_UniqueByName): |
2d55dc7d PP |
316 | def __init__(self, name: str, log_level: Optional[LogLevel] = None, |
317 | specific_context_field_type: _OptStructFt = None, payload_field_type: _OptStructFt = None): | |
318 | self._id: Optional[Id] = None | |
4810b707 PP |
319 | self._name = name |
320 | self._log_level = log_level | |
321 | self._specific_context_field_type = specific_context_field_type | |
322 | self._payload_field_type = payload_field_type | |
323 | ||
324 | @property | |
2d55dc7d | 325 | def id(self) -> Optional[Id]: |
4810b707 PP |
326 | return self._id |
327 | ||
328 | @property | |
2d55dc7d | 329 | def name(self) -> str: |
4810b707 PP |
330 | return self._name |
331 | ||
332 | @property | |
2d55dc7d | 333 | def log_level(self) -> Optional[LogLevel]: |
4810b707 PP |
334 | return self._log_level |
335 | ||
336 | @property | |
2d55dc7d | 337 | def specific_context_field_type(self) -> _OptStructFt: |
4810b707 PP |
338 | return self._specific_context_field_type |
339 | ||
340 | @property | |
2d55dc7d | 341 | def payload_field_type(self) -> _OptStructFt: |
4810b707 PP |
342 | return self._payload_field_type |
343 | ||
344 | ||
345 | class ClockTypeOffset: | |
2d55dc7d | 346 | def __init__(self, seconds: int = 0, cycles: Count = Count(0)): |
4810b707 PP |
347 | self._seconds = seconds |
348 | self._cycles = cycles | |
349 | ||
350 | @property | |
2d55dc7d | 351 | def seconds(self) -> int: |
4810b707 PP |
352 | return self._seconds |
353 | ||
354 | @property | |
2d55dc7d | 355 | def cycles(self) -> Count: |
4810b707 PP |
356 | return self._cycles |
357 | ||
358 | ||
2d55dc7d PP |
359 | _OptUuid = Optional[uuidp.UUID] |
360 | ||
361 | ||
4810b707 | 362 | class ClockType(_UniqueByName): |
2d55dc7d PP |
363 | def __init__(self, name: str, frequency: Count = Count(int(1e9)), uuid: _OptUuid = None, |
364 | description: _OptStr = None, precision: Count = Count(0), | |
365 | offset: Optional[ClockTypeOffset] = None, origin_is_unix_epoch: bool = False): | |
4810b707 PP |
366 | self._name = name |
367 | self._frequency = frequency | |
368 | self._uuid = uuid | |
369 | self._description = description | |
370 | self._precision = precision | |
371 | self._offset = ClockTypeOffset() | |
372 | ||
373 | if offset is not None: | |
374 | self._offset = offset | |
375 | ||
376 | self._origin_is_unix_epoch = origin_is_unix_epoch | |
377 | ||
378 | @property | |
2d55dc7d | 379 | def name(self) -> str: |
4810b707 PP |
380 | return self._name |
381 | ||
382 | @property | |
2d55dc7d | 383 | def frequency(self) -> Count: |
4810b707 PP |
384 | return self._frequency |
385 | ||
386 | @property | |
2d55dc7d | 387 | def uuid(self) -> _OptUuid: |
4810b707 PP |
388 | return self._uuid |
389 | ||
390 | @property | |
2d55dc7d | 391 | def description(self) -> _OptStr: |
4810b707 PP |
392 | return self._description |
393 | ||
394 | @property | |
2d55dc7d | 395 | def precision(self) -> Count: |
4810b707 PP |
396 | return self._precision |
397 | ||
398 | @property | |
2d55dc7d | 399 | def offset(self) -> ClockTypeOffset: |
4810b707 PP |
400 | return self._offset |
401 | ||
402 | @property | |
2d55dc7d | 403 | def origin_is_unix_epoch(self) -> bool: |
4810b707 PP |
404 | return self._origin_is_unix_epoch |
405 | ||
406 | ||
407 | DEFAULT_FIELD_TYPE = 'default' | |
2d55dc7d PP |
408 | _DefaultableUIntFt = Union[str, UnsignedIntegerFieldType] |
409 | _OptDefaultableUIntFt = Optional[_DefaultableUIntFt] | |
410 | _OptUIntFt = Optional[UnsignedIntegerFieldType] | |
4810b707 PP |
411 | |
412 | ||
413 | class StreamTypePacketFeatures: | |
2d55dc7d PP |
414 | def __init__(self, total_size_field_type: _DefaultableUIntFt = DEFAULT_FIELD_TYPE, |
415 | content_size_field_type: _DefaultableUIntFt = DEFAULT_FIELD_TYPE, | |
416 | beginning_time_field_type: _OptDefaultableUIntFt = None, | |
417 | end_time_field_type: _OptDefaultableUIntFt = None, | |
418 | discarded_events_counter_field_type: _OptDefaultableUIntFt = None): | |
419 | def get_ft(user_ft: _OptDefaultableUIntFt) -> _OptUIntFt: | |
4810b707 PP |
420 | if user_ft == DEFAULT_FIELD_TYPE: |
421 | return UnsignedIntegerFieldType(64) | |
422 | ||
2d55dc7d | 423 | return typing.cast(_OptUIntFt, user_ft) |
4810b707 PP |
424 | |
425 | self._total_size_field_type = get_ft(total_size_field_type) | |
426 | self._content_size_field_type = get_ft(content_size_field_type) | |
427 | self._beginning_time_field_type = get_ft(beginning_time_field_type) | |
428 | self._end_time_field_type = get_ft(end_time_field_type) | |
429 | self._discarded_events_counter_field_type = get_ft(discarded_events_counter_field_type) | |
430 | ||
431 | @property | |
2d55dc7d | 432 | def total_size_field_type(self) -> _OptUIntFt: |
4810b707 PP |
433 | return self._total_size_field_type |
434 | ||
435 | @property | |
2d55dc7d | 436 | def content_size_field_type(self) -> _OptUIntFt: |
4810b707 PP |
437 | return self._content_size_field_type |
438 | ||
439 | @property | |
2d55dc7d | 440 | def beginning_time_field_type(self) -> _OptUIntFt: |
4810b707 PP |
441 | return self._beginning_time_field_type |
442 | ||
443 | @property | |
2d55dc7d | 444 | def end_time_field_type(self) -> _OptUIntFt: |
4810b707 PP |
445 | return self._end_time_field_type |
446 | ||
447 | @property | |
2d55dc7d | 448 | def discarded_events_counter_field_type(self) -> _OptUIntFt: |
4810b707 PP |
449 | return self._discarded_events_counter_field_type |
450 | ||
451 | ||
452 | class StreamTypeEventFeatures: | |
2d55dc7d PP |
453 | def __init__(self, type_id_field_type: _OptDefaultableUIntFt = DEFAULT_FIELD_TYPE, |
454 | time_field_type: _OptDefaultableUIntFt = None): | |
455 | def get_ft(user_ft: _OptDefaultableUIntFt) -> _OptUIntFt: | |
456 | if user_ft == DEFAULT_FIELD_TYPE: | |
4810b707 PP |
457 | return UnsignedIntegerFieldType(64) |
458 | ||
2d55dc7d | 459 | return typing.cast(_OptUIntFt, user_ft) |
4810b707 PP |
460 | |
461 | self._type_id_field_type = get_ft(type_id_field_type) | |
462 | self._time_field_type = get_ft(time_field_type) | |
463 | ||
464 | @property | |
2d55dc7d | 465 | def type_id_field_type(self) -> _OptUIntFt: |
4810b707 PP |
466 | return self._type_id_field_type |
467 | ||
468 | @property | |
2d55dc7d | 469 | def time_field_type(self) -> _OptUIntFt: |
4810b707 PP |
470 | return self._time_field_type |
471 | ||
472 | ||
473 | class StreamTypeFeatures: | |
2d55dc7d PP |
474 | def __init__(self, packet_features: Optional[StreamTypePacketFeatures] = None, |
475 | event_features: Optional[StreamTypeEventFeatures] = None): | |
4810b707 PP |
476 | self._packet_features = StreamTypePacketFeatures() |
477 | ||
478 | if packet_features is not None: | |
479 | self._packet_features = packet_features | |
480 | ||
481 | self._event_features = StreamTypeEventFeatures() | |
482 | ||
483 | if event_features is not None: | |
484 | self._event_features = event_features | |
485 | ||
486 | @property | |
2d55dc7d | 487 | def packet_features(self) -> StreamTypePacketFeatures: |
4810b707 PP |
488 | return self._packet_features |
489 | ||
490 | @property | |
2d55dc7d | 491 | def event_features(self) -> StreamTypeEventFeatures: |
4810b707 PP |
492 | return self._event_features |
493 | ||
494 | ||
495 | class StreamType(_UniqueByName): | |
2d55dc7d PP |
496 | def __init__(self, name: str, event_types: Set[EventType], |
497 | default_clock_type: Optional[ClockType] = None, | |
498 | features: Optional[StreamTypeFeatures] = None, | |
499 | packet_context_field_type_extra_members: Optional[_StructFtMembers] = None, | |
500 | event_common_context_field_type: _OptStructFt = None): | |
501 | self._id: Optional[Id] = None | |
4810b707 PP |
502 | self._name = name |
503 | self._default_clock_type = default_clock_type | |
504 | self._event_common_context_field_type = event_common_context_field_type | |
505 | self._event_types = frozenset(event_types) | |
506 | ||
507 | # assign unique IDs | |
508 | for index, ev_type in enumerate(sorted(self._event_types, key=lambda evt: evt.name)): | |
509 | assert ev_type._id is None | |
2d55dc7d | 510 | ev_type._id = Id(index) |
4810b707 PP |
511 | |
512 | self._set_features(features) | |
513 | self._packet_context_field_type_extra_members = StructureFieldTypeMembers({}) | |
514 | ||
515 | if packet_context_field_type_extra_members is not None: | |
516 | self._packet_context_field_type_extra_members = StructureFieldTypeMembers(packet_context_field_type_extra_members) | |
517 | ||
518 | self._set_pkt_ctx_ft() | |
519 | self._set_ev_header_ft() | |
520 | ||
2d55dc7d | 521 | def _set_features(self, features: Optional[StreamTypeFeatures]): |
4810b707 PP |
522 | if features is not None: |
523 | self._features = features | |
2d55dc7d | 524 | return None |
4810b707 PP |
525 | |
526 | ev_time_ft = None | |
527 | pkt_beginning_time_ft = None | |
528 | pkt_end_time_ft = None | |
529 | ||
530 | if self._default_clock_type is not None: | |
531 | # Automatic time field types because the stream type has a | |
532 | # default clock type. | |
533 | ev_time_ft = DEFAULT_FIELD_TYPE | |
534 | pkt_beginning_time_ft = DEFAULT_FIELD_TYPE | |
535 | pkt_end_time_ft = DEFAULT_FIELD_TYPE | |
536 | ||
537 | self._features = StreamTypeFeatures(StreamTypePacketFeatures(beginning_time_field_type=pkt_beginning_time_ft, | |
538 | end_time_field_type=pkt_end_time_ft), | |
539 | StreamTypeEventFeatures(time_field_type=ev_time_ft)) | |
540 | ||
2d55dc7d | 541 | def _set_ft_mapped_clk_type_name(self, ft: Optional[UnsignedIntegerFieldType]): |
4810b707 PP |
542 | if ft is None: |
543 | return | |
544 | ||
545 | if self._default_clock_type is not None: | |
546 | assert isinstance(ft, UnsignedIntegerFieldType) | |
547 | ft._mapped_clk_type_name = self._default_clock_type.name | |
548 | ||
549 | def _set_pkt_ctx_ft(self): | |
2d55dc7d PP |
550 | members = None |
551 | ||
552 | def add_member_if_exists(name: str, ft: _FieldType, set_mapped_clk_type_name: bool = False): | |
4810b707 PP |
553 | nonlocal members |
554 | ||
555 | if ft is not None: | |
556 | if set_mapped_clk_type_name: | |
2d55dc7d | 557 | self._set_ft_mapped_clk_type_name(typing.cast(UnsignedIntegerFieldType, ft)) |
4810b707 PP |
558 | |
559 | members[name] = StructureFieldTypeMember(ft) | |
560 | ||
561 | members = collections.OrderedDict([ | |
562 | ( | |
563 | 'packet_size', | |
564 | StructureFieldTypeMember(self._features.packet_features.total_size_field_type) | |
565 | ), | |
566 | ( | |
567 | 'content_size', | |
568 | StructureFieldTypeMember(self._features.packet_features.content_size_field_type) | |
569 | ) | |
570 | ]) | |
571 | ||
572 | add_member_if_exists('timestamp_begin', | |
573 | self._features.packet_features.beginning_time_field_type, True) | |
574 | add_member_if_exists('timestamp_end', self._features.packet_features.end_time_field_type, | |
575 | True) | |
576 | add_member_if_exists('events_discarded', | |
577 | self._features.packet_features.discarded_events_counter_field_type) | |
578 | ||
579 | if self._packet_context_field_type_extra_members is not None: | |
580 | for name, field_type in self._packet_context_field_type_extra_members.items(): | |
581 | assert name not in members | |
582 | members[name] = field_type | |
583 | ||
584 | self._pkt_ctx_ft = StructureFieldType(8, members) | |
585 | ||
586 | def _set_ev_header_ft(self): | |
587 | members = collections.OrderedDict() | |
588 | ||
589 | if self._features.event_features.type_id_field_type is not None: | |
590 | members['id'] = StructureFieldTypeMember(self._features.event_features.type_id_field_type) | |
591 | ||
592 | if self._features.event_features.time_field_type is not None: | |
593 | ft = self._features.event_features.time_field_type | |
594 | self._set_ft_mapped_clk_type_name(ft) | |
595 | members['timestamp'] = StructureFieldTypeMember(ft) | |
596 | ||
597 | self._ev_header_ft = StructureFieldType(8, members) | |
598 | ||
599 | @property | |
2d55dc7d | 600 | def id(self) -> Optional[Id]: |
4810b707 PP |
601 | return self._id |
602 | ||
603 | @property | |
2d55dc7d | 604 | def name(self) -> str: |
4810b707 PP |
605 | return self._name |
606 | ||
607 | @property | |
2d55dc7d | 608 | def default_clock_type(self) -> Optional[ClockType]: |
4810b707 PP |
609 | return self._default_clock_type |
610 | ||
611 | @property | |
2d55dc7d | 612 | def features(self) -> StreamTypeFeatures: |
4810b707 PP |
613 | return self._features |
614 | ||
615 | @property | |
2d55dc7d | 616 | def packet_context_field_type_extra_members(self) -> StructureFieldTypeMembers: |
4810b707 PP |
617 | return self._packet_context_field_type_extra_members |
618 | ||
619 | @property | |
2d55dc7d | 620 | def event_common_context_field_type(self) -> _OptStructFt: |
4810b707 PP |
621 | return self._event_common_context_field_type |
622 | ||
623 | @property | |
2d55dc7d | 624 | def event_types(self) -> FrozenSet[EventType]: |
4810b707 PP |
625 | return self._event_types |
626 | ||
627 | ||
2d55dc7d PP |
628 | _OptUuidFt = Optional[Union[str, StaticArrayFieldType]] |
629 | ||
630 | ||
4810b707 | 631 | class TraceTypeFeatures: |
2d55dc7d PP |
632 | def __init__(self, magic_field_type: _OptDefaultableUIntFt = DEFAULT_FIELD_TYPE, |
633 | uuid_field_type: _OptUuidFt = None, | |
634 | stream_type_id_field_type: _OptDefaultableUIntFt = DEFAULT_FIELD_TYPE): | |
635 | def get_field_type(user_ft: Optional[Union[str, _FieldType]], default_ft: _FieldType) -> _OptFt: | |
636 | if user_ft == DEFAULT_FIELD_TYPE: | |
637 | return default_ft | |
4810b707 | 638 | |
2d55dc7d | 639 | return typing.cast(_OptFt, user_ft) |
4810b707 | 640 | |
2d55dc7d PP |
641 | self._magic_field_type = typing.cast(_OptUIntFt, get_field_type(magic_field_type, |
642 | UnsignedIntegerFieldType(32))) | |
643 | self._uuid_field_type = typing.cast(Optional[StaticArrayFieldType], get_field_type(uuid_field_type, | |
644 | StaticArrayFieldType(Count(16), | |
645 | UnsignedIntegerFieldType(8)))) | |
646 | self._stream_type_id_field_type = typing.cast(_OptUIntFt, get_field_type(stream_type_id_field_type, | |
647 | UnsignedIntegerFieldType(64))) | |
4810b707 PP |
648 | |
649 | @property | |
2d55dc7d | 650 | def magic_field_type(self) -> _OptUIntFt: |
4810b707 PP |
651 | return self._magic_field_type |
652 | ||
653 | @property | |
2d55dc7d | 654 | def uuid_field_type(self) -> Optional[StaticArrayFieldType]: |
4810b707 PP |
655 | return self._uuid_field_type |
656 | ||
657 | @property | |
2d55dc7d | 658 | def stream_type_id_field_type(self) -> _OptUIntFt: |
4810b707 PP |
659 | return self._stream_type_id_field_type |
660 | ||
661 | ||
662 | class TraceType: | |
2d55dc7d PP |
663 | def __init__(self, stream_types: Set[StreamType], default_byte_order: ByteOrder, |
664 | uuid: _OptUuid = None, features: Optional[TraceTypeFeatures] = None): | |
4810b707 PP |
665 | self._default_byte_order = default_byte_order |
666 | self._stream_types = frozenset(stream_types) | |
667 | ||
668 | # assign unique IDs | |
669 | for index, stream_type in enumerate(sorted(self._stream_types, key=lambda st: st.name)): | |
670 | assert stream_type._id is None | |
2d55dc7d | 671 | stream_type._id = Id(index) |
4810b707 PP |
672 | |
673 | self._uuid = uuid | |
674 | self._set_features(features) | |
675 | self._set_pkt_header_ft() | |
676 | self._set_fts_effective_byte_order() | |
677 | ||
2d55dc7d | 678 | def _set_features(self, features: Optional[TraceTypeFeatures]): |
4810b707 PP |
679 | if features is not None: |
680 | self._features = features | |
681 | return | |
682 | ||
683 | # automatic UUID field type because the trace type has a UUID | |
684 | uuid_ft = None if self._uuid is None else DEFAULT_FIELD_TYPE | |
685 | self._features = TraceTypeFeatures(uuid_field_type=uuid_ft) | |
686 | ||
687 | def _set_pkt_header_ft(self): | |
2d55dc7d PP |
688 | members = collections.OrderedDict() |
689 | ||
690 | def add_member_if_exists(name: str, ft: _OptFt): | |
4810b707 PP |
691 | nonlocal members |
692 | ||
2d55dc7d PP |
693 | if ft is not None: |
694 | members[name] = StructureFieldTypeMember(ft) | |
4810b707 | 695 | |
4810b707 PP |
696 | add_member_if_exists('magic', self._features.magic_field_type) |
697 | add_member_if_exists('uuid', self._features.uuid_field_type) | |
698 | add_member_if_exists('stream_id', self._features.stream_type_id_field_type) | |
699 | self._pkt_header_ft = StructureFieldType(8, members) | |
700 | ||
701 | def _set_fts_effective_byte_order(self): | |
2d55dc7d | 702 | def set_ft_effective_byte_order(ft: _OptFt): |
4810b707 PP |
703 | if ft is None: |
704 | return | |
705 | ||
706 | if isinstance(ft, _BitArrayFieldType): | |
707 | if ft._byte_order is None: | |
708 | assert self._default_byte_order is not None | |
709 | ft._byte_order = self._default_byte_order | |
710 | elif isinstance(ft, StaticArrayFieldType): | |
711 | set_ft_effective_byte_order(ft.element_field_type) | |
712 | elif isinstance(ft, StructureFieldType): | |
713 | for member in ft.members.values(): | |
714 | set_ft_effective_byte_order(member.field_type) | |
715 | ||
716 | # packet header field type | |
717 | set_ft_effective_byte_order(self._pkt_header_ft) | |
718 | ||
719 | # stream type field types | |
720 | for stream_type in self._stream_types: | |
721 | set_ft_effective_byte_order(stream_type._pkt_ctx_ft) | |
722 | set_ft_effective_byte_order(stream_type._ev_header_ft) | |
723 | set_ft_effective_byte_order(stream_type._event_common_context_field_type) | |
724 | ||
725 | # event type field types | |
726 | for ev_type in stream_type.event_types: | |
727 | set_ft_effective_byte_order(ev_type._specific_context_field_type) | |
728 | set_ft_effective_byte_order(ev_type._payload_field_type) | |
729 | ||
730 | @property | |
2d55dc7d | 731 | def default_byte_order(self) -> ByteOrder: |
4810b707 PP |
732 | return self._default_byte_order |
733 | ||
734 | @property | |
2d55dc7d | 735 | def uuid(self) -> _OptUuid: |
4810b707 PP |
736 | return self._uuid |
737 | ||
738 | @property | |
2d55dc7d | 739 | def stream_types(self) -> FrozenSet[StreamType]: |
4810b707 PP |
740 | return self._stream_types |
741 | ||
2d55dc7d | 742 | def stream_type(self, name: str) -> Optional[StreamType]: |
4810b707 PP |
743 | for cand_stream_type in self._stream_types: |
744 | if cand_stream_type.name == name: | |
745 | return cand_stream_type | |
746 | ||
2d55dc7d PP |
747 | return None |
748 | ||
4810b707 | 749 | @property |
2d55dc7d | 750 | def features(self) -> TraceTypeFeatures: |
4810b707 PP |
751 | return self._features |
752 | ||
de49021e PP |
753 | @property |
754 | def clock_types(self) -> Set[ClockType]: | |
755 | clk_types = set() | |
756 | ||
757 | for stream_type in self._stream_types: | |
758 | if stream_type.default_clock_type is not None: | |
759 | clk_types.add(stream_type.default_clock_type) | |
760 | ||
761 | return clk_types | |
762 | ||
4810b707 | 763 | |
2d55dc7d PP |
764 | _EnvEntry = Union[str, int] |
765 | _EnvEntries = Mapping[str, _EnvEntry] | |
766 | ||
767 | ||
4810b707 | 768 | class TraceEnvironment(collections.abc.Mapping): |
2d55dc7d | 769 | def __init__(self, environment: _EnvEntries): |
4810b707 PP |
770 | self._env = {name: value for name, value in environment.items()} |
771 | ||
2d55dc7d | 772 | def __getitem__(self, key: str) -> _EnvEntry: |
4810b707 PP |
773 | return self._env[key] |
774 | ||
2d55dc7d | 775 | def __iter__(self) -> Iterator[str]: |
4810b707 PP |
776 | return iter(self._env) |
777 | ||
2d55dc7d | 778 | def __len__(self) -> int: |
4810b707 PP |
779 | return len(self._env) |
780 | ||
781 | ||
782 | class Trace: | |
2d55dc7d | 783 | def __init__(self, type: TraceType, environment: Optional[_EnvEntries] = None): |
4810b707 PP |
784 | self._type = type |
785 | self._set_env(environment) | |
786 | ||
2d55dc7d | 787 | def _set_env(self, environment: Optional[_EnvEntries]): |
4810b707 PP |
788 | init_env = collections.OrderedDict([ |
789 | ('domain', 'bare'), | |
790 | ('tracer_name', 'barectf'), | |
791 | ('tracer_major', barectf_version.__major_version__), | |
792 | ('tracer_minor', barectf_version.__minor_version__), | |
793 | ('tracer_patch', barectf_version.__patch_version__), | |
794 | ('barectf_gen_date', str(datetime.datetime.now().isoformat())), | |
795 | ]) | |
796 | ||
797 | if environment is None: | |
798 | environment = {} | |
799 | ||
800 | init_env.update(environment) | |
2d55dc7d | 801 | self._env = TraceEnvironment(typing.cast(_EnvEntries, init_env)) |
4810b707 PP |
802 | |
803 | @property | |
2d55dc7d | 804 | def type(self) -> TraceType: |
4810b707 PP |
805 | return self._type |
806 | ||
807 | @property | |
2d55dc7d | 808 | def environment(self) -> TraceEnvironment: |
4810b707 PP |
809 | return self._env |
810 | ||
811 | ||
2d55dc7d PP |
812 | _ClkTypeCTypes = Mapping[ClockType, str] |
813 | ||
814 | ||
4810b707 | 815 | class ClockTypeCTypes(collections.abc.Mapping): |
2d55dc7d | 816 | def __init__(self, c_types: _ClkTypeCTypes): |
4810b707 PP |
817 | self._c_types = {clk_type: c_type for clk_type, c_type in c_types.items()} |
818 | ||
2d55dc7d | 819 | def __getitem__(self, key: ClockType) -> str: |
4810b707 PP |
820 | return self._c_types[key] |
821 | ||
2d55dc7d | 822 | def __iter__(self) -> Iterator[ClockType]: |
4810b707 PP |
823 | return iter(self._c_types) |
824 | ||
2d55dc7d | 825 | def __len__(self) -> int: |
4810b707 PP |
826 | return len(self._c_types) |
827 | ||
828 | ||
829 | class ConfigurationCodeGenerationHeaderOptions: | |
2d55dc7d PP |
830 | def __init__(self, identifier_prefix_definition: bool = False, |
831 | default_stream_type_name_definition: bool = False): | |
4810b707 PP |
832 | self._identifier_prefix_definition = identifier_prefix_definition |
833 | self._default_stream_type_name_definition = default_stream_type_name_definition | |
834 | ||
835 | @property | |
2d55dc7d | 836 | def identifier_prefix_definition(self) -> bool: |
4810b707 PP |
837 | return self._identifier_prefix_definition |
838 | ||
839 | @property | |
2d55dc7d | 840 | def default_stream_type_name_definition(self) -> bool: |
4810b707 PP |
841 | return self._default_stream_type_name_definition |
842 | ||
843 | ||
844 | class ConfigurationCodeGenerationOptions: | |
2d55dc7d PP |
845 | def __init__(self, identifier_prefix: str = 'barectf_', file_name_prefix: str = 'barectf', |
846 | default_stream_type: Optional[StreamType] = None, | |
847 | header_options: Optional[ConfigurationCodeGenerationHeaderOptions] = None, | |
848 | clock_type_c_types: Optional[_ClkTypeCTypes] = None): | |
4810b707 PP |
849 | self._identifier_prefix = identifier_prefix |
850 | self._file_name_prefix = file_name_prefix | |
851 | self._default_stream_type = default_stream_type | |
852 | ||
853 | self._header_options = ConfigurationCodeGenerationHeaderOptions() | |
854 | ||
855 | if header_options is not None: | |
856 | self._header_options = header_options | |
857 | ||
858 | self._clock_type_c_types = ClockTypeCTypes({}) | |
859 | ||
860 | if clock_type_c_types is not None: | |
861 | self._clock_type_c_types = ClockTypeCTypes(clock_type_c_types) | |
862 | ||
863 | @property | |
2d55dc7d | 864 | def identifier_prefix(self) -> str: |
4810b707 PP |
865 | return self._identifier_prefix |
866 | ||
867 | @property | |
2d55dc7d | 868 | def file_name_prefix(self) -> str: |
4810b707 PP |
869 | return self._file_name_prefix |
870 | ||
871 | @property | |
2d55dc7d | 872 | def default_stream_type(self) -> Optional[StreamType]: |
4810b707 PP |
873 | return self._default_stream_type |
874 | ||
875 | @property | |
2d55dc7d | 876 | def header_options(self) -> ConfigurationCodeGenerationHeaderOptions: |
4810b707 PP |
877 | return self._header_options |
878 | ||
879 | @property | |
2d55dc7d | 880 | def clock_type_c_types(self) -> ClockTypeCTypes: |
4810b707 PP |
881 | return self._clock_type_c_types |
882 | ||
883 | ||
884 | class ConfigurationOptions: | |
2d55dc7d PP |
885 | def __init__(self, |
886 | code_generation_options: Optional[ConfigurationCodeGenerationOptions] = None): | |
4810b707 PP |
887 | self._code_generation_options = ConfigurationCodeGenerationOptions() |
888 | ||
889 | if code_generation_options is not None: | |
890 | self._code_generation_options = code_generation_options | |
891 | ||
892 | @property | |
2d55dc7d | 893 | def code_generation_options(self) -> ConfigurationCodeGenerationOptions: |
4810b707 PP |
894 | return self._code_generation_options |
895 | ||
896 | ||
897 | class Configuration: | |
2d55dc7d | 898 | def __init__(self, trace: Trace, options: Optional[ConfigurationOptions] = None): |
4810b707 PP |
899 | self._trace = trace |
900 | self._options = ConfigurationOptions() | |
901 | ||
902 | if options is not None: | |
903 | self._options = options | |
904 | ||
905 | clk_type_c_types = self._options.code_generation_options.clock_type_c_types | |
906 | ||
907 | for stream_type in trace.type.stream_types: | |
908 | def_clk_type = stream_type.default_clock_type | |
909 | ||
910 | if def_clk_type is None: | |
911 | continue | |
912 | ||
913 | if def_clk_type not in clk_type_c_types: | |
914 | clk_type_c_types._c_types[def_clk_type] = 'uint32_t' | |
915 | ||
916 | @property | |
2d55dc7d | 917 | def trace(self) -> Trace: |
4810b707 PP |
918 | return self._trace |
919 | ||
920 | @property | |
2d55dc7d | 921 | def options(self) -> ConfigurationOptions: |
4810b707 | 922 | return self._options |