94010d47aa04aac8e2dc48795bf758a7dddf59e6
[babeltrace.git] / src / bindings / python / bt2 / bt2 / trace_class.py
1 # The MIT License (MIT)
2 #
3 # Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
4 # Copyright (c) 2018 Francis Deslauriers <francis.deslauriers@efficios.com>
5 # Copyright (c) 2019 Simon Marchi <simon.marchi@efficios.com>
6 #
7 # Permission is hereby granted, free of charge, to any person obtaining a copy
8 # of this software and associated documentation files (the "Software"), to deal
9 # in the Software without restriction, including without limitation the rights
10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 # copies of the Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
13 #
14 # The above copyright notice and this permission notice shall be included in
15 # all copies or substantial portions of the Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 # THE SOFTWARE.
24
25 from bt2 import native_bt, utils, object
26 from bt2 import stream_class as bt2_stream_class
27 from bt2 import field_class as bt2_field_class
28 from bt2 import integer_range_set as bt2_integer_range_set
29 from bt2 import trace as bt2_trace
30 from bt2 import value as bt2_value
31 import collections.abc
32 import functools
33 import bt2
34
35
36 def _trace_class_destruction_listener_from_native(
37 user_listener, handle, trace_class_ptr
38 ):
39 trace_class = _TraceClass._create_from_ptr_and_get_ref(trace_class_ptr)
40 user_listener(trace_class)
41 handle._invalidate()
42
43
44 class _TraceClassConst(object._SharedObject, collections.abc.Mapping):
45 _get_ref = staticmethod(native_bt.trace_class_get_ref)
46 _put_ref = staticmethod(native_bt.trace_class_put_ref)
47 _borrow_stream_class_ptr_by_index = staticmethod(
48 native_bt.trace_class_borrow_stream_class_by_index_const
49 )
50 _borrow_stream_class_ptr_by_id = staticmethod(
51 native_bt.trace_class_borrow_stream_class_by_id_const
52 )
53 _borrow_user_attributes_ptr = staticmethod(
54 native_bt.trace_class_borrow_user_attributes_const
55 )
56 _stream_class_pycls = bt2_stream_class._StreamClassConst
57 _create_value_from_ptr_and_get_ref = staticmethod(
58 bt2_value._create_from_const_ptr_and_get_ref
59 )
60
61 @property
62 def user_attributes(self):
63 ptr = self._borrow_user_attributes_ptr(self._ptr)
64 assert ptr is not None
65 return self._create_value_from_ptr_and_get_ref(ptr)
66
67 # Number of stream classes in this trace class.
68
69 def __len__(self):
70 count = native_bt.trace_class_get_stream_class_count(self._ptr)
71 assert count >= 0
72 return count
73
74 # Get a stream class by stream id.
75
76 def __getitem__(self, key):
77 utils._check_uint64(key)
78
79 sc_ptr = self._borrow_stream_class_ptr_by_id(self._ptr, key)
80 if sc_ptr is None:
81 raise KeyError(key)
82
83 return self._stream_class_pycls._create_from_ptr_and_get_ref(sc_ptr)
84
85 def __iter__(self):
86 for idx in range(len(self)):
87 sc_ptr = self._borrow_stream_class_ptr_by_index(self._ptr, idx)
88 assert sc_ptr is not None
89
90 id = native_bt.stream_class_get_id(sc_ptr)
91 assert id >= 0
92
93 yield id
94
95 @property
96 def assigns_automatic_stream_class_id(self):
97 return native_bt.trace_class_assigns_automatic_stream_class_id(self._ptr)
98
99 # Add a listener to be called when the trace class is destroyed.
100
101 def add_destruction_listener(self, listener):
102
103 if not callable(listener):
104 raise TypeError("'listener' parameter is not callable")
105
106 handle = utils._ListenerHandle(self.addr)
107
108 listener_from_native = functools.partial(
109 _trace_class_destruction_listener_from_native, listener, handle
110 )
111
112 fn = native_bt.bt2_trace_class_add_destruction_listener
113 status, listener_id = fn(self._ptr, listener_from_native)
114 utils._handle_func_status(
115 status, 'cannot add destruction listener to trace class object'
116 )
117
118 handle._set_listener_id(listener_id)
119
120 return handle
121
122 def remove_destruction_listener(self, listener_handle):
123 utils._check_type(listener_handle, utils._ListenerHandle)
124
125 if listener_handle._addr != self.addr:
126 raise ValueError(
127 'This trace class destruction listener does not match the trace class object.'
128 )
129
130 if listener_handle._listener_id is None:
131 raise ValueError(
132 'This trace class destruction listener was already removed.'
133 )
134
135 status = native_bt.trace_class_remove_destruction_listener(
136 self._ptr, listener_handle._listener_id
137 )
138 utils._handle_func_status(status)
139 listener_handle._invalidate()
140
141
142 class _TraceClass(_TraceClassConst):
143 _borrow_stream_class_ptr_by_index = staticmethod(
144 native_bt.trace_class_borrow_stream_class_by_index
145 )
146 _borrow_stream_class_ptr_by_id = staticmethod(
147 native_bt.trace_class_borrow_stream_class_by_id
148 )
149 _borrow_user_attributes_ptr = staticmethod(
150 native_bt.trace_class_borrow_user_attributes
151 )
152 _stream_class_pycls = bt2_stream_class._StreamClass
153 _create_value_from_ptr_and_get_ref = staticmethod(
154 bt2_value._create_from_ptr_and_get_ref
155 )
156
157 # Instantiate a trace of this class.
158
159 def __call__(self, name=None, user_attributes=None, uuid=None, environment=None):
160 trace_ptr = native_bt.trace_create(self._ptr)
161
162 if trace_ptr is None:
163 raise bt2._MemoryError('cannot create trace class object')
164
165 trace = bt2_trace._Trace._create_from_ptr(trace_ptr)
166
167 if name is not None:
168 trace._name = name
169
170 if user_attributes is not None:
171 trace._user_attributes = user_attributes
172
173 if uuid is not None:
174 trace._uuid = uuid
175
176 if environment is not None:
177 for key, value in environment.items():
178 trace.environment[key] = value
179
180 return trace
181
182 def create_stream_class(
183 self,
184 id=None,
185 name=None,
186 user_attributes=None,
187 packet_context_field_class=None,
188 event_common_context_field_class=None,
189 default_clock_class=None,
190 assigns_automatic_event_class_id=True,
191 assigns_automatic_stream_id=True,
192 supports_packets=False,
193 packets_have_beginning_default_clock_snapshot=False,
194 packets_have_end_default_clock_snapshot=False,
195 supports_discarded_events=False,
196 discarded_events_have_default_clock_snapshots=False,
197 supports_discarded_packets=False,
198 discarded_packets_have_default_clock_snapshots=False,
199 ):
200 # Validate parameters before we create the object.
201 bt2_stream_class._StreamClass._validate_create_params(
202 name,
203 user_attributes,
204 packet_context_field_class,
205 event_common_context_field_class,
206 default_clock_class,
207 assigns_automatic_event_class_id,
208 assigns_automatic_stream_id,
209 supports_packets,
210 packets_have_beginning_default_clock_snapshot,
211 packets_have_end_default_clock_snapshot,
212 supports_discarded_events,
213 discarded_events_have_default_clock_snapshots,
214 supports_discarded_packets,
215 discarded_packets_have_default_clock_snapshots,
216 )
217
218 if self.assigns_automatic_stream_class_id:
219 if id is not None:
220 raise ValueError(
221 'id provided, but trace class assigns automatic stream class ids'
222 )
223
224 sc_ptr = native_bt.stream_class_create(self._ptr)
225 else:
226 if id is None:
227 raise ValueError(
228 'id not provided, but trace class does not assign automatic stream class ids'
229 )
230
231 utils._check_uint64(id)
232 sc_ptr = native_bt.stream_class_create_with_id(self._ptr, id)
233
234 sc = bt2_stream_class._StreamClass._create_from_ptr(sc_ptr)
235
236 if name is not None:
237 sc._name = name
238
239 if user_attributes is not None:
240 sc._user_attributes = user_attributes
241
242 if event_common_context_field_class is not None:
243 sc._event_common_context_field_class = event_common_context_field_class
244
245 if default_clock_class is not None:
246 sc._default_clock_class = default_clock_class
247
248 # call after `sc._default_clock_class` because, if
249 # `packets_have_beginning_default_clock_snapshot` or
250 # `packets_have_end_default_clock_snapshot` is true, then this
251 # stream class needs a default clock class already.
252 sc._set_supports_packets(
253 supports_packets,
254 packets_have_beginning_default_clock_snapshot,
255 packets_have_end_default_clock_snapshot,
256 )
257
258 # call after sc._set_supports_packets() because, if
259 # `packet_context_field_class` is not `None`, then this stream
260 # class needs to support packets already.
261 if packet_context_field_class is not None:
262 sc._packet_context_field_class = packet_context_field_class
263
264 sc._assigns_automatic_event_class_id = assigns_automatic_event_class_id
265 sc._assigns_automatic_stream_id = assigns_automatic_stream_id
266 sc._set_supports_discarded_events(
267 supports_discarded_events, discarded_events_have_default_clock_snapshots
268 )
269 sc._set_supports_discarded_packets(
270 supports_discarded_packets, discarded_packets_have_default_clock_snapshots
271 )
272 return sc
273
274 def _user_attributes(self, user_attributes):
275 value = bt2_value.create_value(user_attributes)
276 utils._check_type(value, bt2_value.MapValue)
277 native_bt.trace_class_set_user_attributes(self._ptr, value._ptr)
278
279 _user_attributes = property(fset=_user_attributes)
280
281 def _assigns_automatic_stream_class_id(self, auto_id):
282 utils._check_bool(auto_id)
283 return native_bt.trace_class_set_assigns_automatic_stream_class_id(
284 self._ptr, auto_id
285 )
286
287 _assigns_automatic_stream_class_id = property(
288 fset=_assigns_automatic_stream_class_id
289 )
290
291 # Field class creation methods.
292
293 def _check_field_class_create_status(self, ptr, type_name):
294 if ptr is None:
295 raise bt2._MemoryError('cannot create {} field class'.format(type_name))
296
297 @staticmethod
298 def _set_field_class_user_attrs(fc, user_attributes):
299 if user_attributes is not None:
300 fc._user_attributes = user_attributes
301
302 def create_bool_field_class(self, user_attributes=None):
303 field_class_ptr = native_bt.field_class_bool_create(self._ptr)
304 self._check_field_class_create_status(field_class_ptr, 'boolean')
305 fc = bt2_field_class._BoolFieldClass._create_from_ptr(field_class_ptr)
306 self._set_field_class_user_attrs(fc, user_attributes)
307 return fc
308
309 def create_bit_array_field_class(self, length, user_attributes=None):
310 utils._check_uint64(length)
311
312 if length < 1 or length > 64:
313 raise ValueError(
314 'invalid length {}: expecting a value in the [1, 64] range'.format(
315 length
316 )
317 )
318
319 field_class_ptr = native_bt.field_class_bit_array_create(self._ptr, length)
320 self._check_field_class_create_status(field_class_ptr, 'bit array')
321 fc = bt2_field_class._BitArrayFieldClass._create_from_ptr(field_class_ptr)
322 self._set_field_class_user_attrs(fc, user_attributes)
323 return fc
324
325 def _create_integer_field_class(
326 self,
327 create_func,
328 py_cls,
329 type_name,
330 field_value_range,
331 preferred_display_base,
332 user_attributes,
333 ):
334 field_class_ptr = create_func(self._ptr)
335 self._check_field_class_create_status(field_class_ptr, type_name)
336
337 field_class = py_cls._create_from_ptr(field_class_ptr)
338
339 if field_value_range is not None:
340 field_class._field_value_range = field_value_range
341
342 if preferred_display_base is not None:
343 field_class._preferred_display_base = preferred_display_base
344
345 self._set_field_class_user_attrs(field_class, user_attributes)
346 return field_class
347
348 def create_signed_integer_field_class(
349 self, field_value_range=None, preferred_display_base=None, user_attributes=None
350 ):
351 return self._create_integer_field_class(
352 native_bt.field_class_integer_signed_create,
353 bt2_field_class._SignedIntegerFieldClass,
354 'signed integer',
355 field_value_range,
356 preferred_display_base,
357 user_attributes,
358 )
359
360 def create_unsigned_integer_field_class(
361 self, field_value_range=None, preferred_display_base=None, user_attributes=None
362 ):
363 return self._create_integer_field_class(
364 native_bt.field_class_integer_unsigned_create,
365 bt2_field_class._UnsignedIntegerFieldClass,
366 'unsigned integer',
367 field_value_range,
368 preferred_display_base,
369 user_attributes,
370 )
371
372 def create_signed_enumeration_field_class(
373 self, field_value_range=None, preferred_display_base=None, user_attributes=None
374 ):
375 return self._create_integer_field_class(
376 native_bt.field_class_enumeration_signed_create,
377 bt2_field_class._SignedEnumerationFieldClass,
378 'signed enumeration',
379 field_value_range,
380 preferred_display_base,
381 user_attributes,
382 )
383
384 def create_unsigned_enumeration_field_class(
385 self, field_value_range=None, preferred_display_base=None, user_attributes=None
386 ):
387 return self._create_integer_field_class(
388 native_bt.field_class_enumeration_unsigned_create,
389 bt2_field_class._UnsignedEnumerationFieldClass,
390 'unsigned enumeration',
391 field_value_range,
392 preferred_display_base,
393 user_attributes,
394 )
395
396 def create_single_precision_real_field_class(self, user_attributes=None):
397 field_class_ptr = native_bt.field_class_real_single_precision_create(self._ptr)
398 self._check_field_class_create_status(field_class_ptr, 'single-precision real')
399
400 field_class = bt2_field_class._SinglePrecisionRealFieldClass._create_from_ptr(
401 field_class_ptr
402 )
403
404 self._set_field_class_user_attrs(field_class, user_attributes)
405
406 return field_class
407
408 def create_double_precision_real_field_class(self, user_attributes=None):
409 field_class_ptr = native_bt.field_class_real_double_precision_create(self._ptr)
410 self._check_field_class_create_status(field_class_ptr, 'double-precision real')
411
412 field_class = bt2_field_class._DoublePrecisionRealFieldClass._create_from_ptr(
413 field_class_ptr
414 )
415
416 self._set_field_class_user_attrs(field_class, user_attributes)
417
418 return field_class
419
420 def create_structure_field_class(self, user_attributes=None):
421 field_class_ptr = native_bt.field_class_structure_create(self._ptr)
422 self._check_field_class_create_status(field_class_ptr, 'structure')
423 fc = bt2_field_class._StructureFieldClass._create_from_ptr(field_class_ptr)
424 self._set_field_class_user_attrs(fc, user_attributes)
425 return fc
426
427 def create_string_field_class(self, user_attributes=None):
428 field_class_ptr = native_bt.field_class_string_create(self._ptr)
429 self._check_field_class_create_status(field_class_ptr, 'string')
430 fc = bt2_field_class._StringFieldClass._create_from_ptr(field_class_ptr)
431 self._set_field_class_user_attrs(fc, user_attributes)
432 return fc
433
434 def create_static_array_field_class(self, elem_fc, length, user_attributes=None):
435 utils._check_type(elem_fc, bt2_field_class._FieldClass)
436 utils._check_uint64(length)
437 ptr = native_bt.field_class_array_static_create(self._ptr, elem_fc._ptr, length)
438 self._check_field_class_create_status(ptr, 'static array')
439 fc = bt2_field_class._StaticArrayFieldClass._create_from_ptr_and_get_ref(ptr)
440 self._set_field_class_user_attrs(fc, user_attributes)
441 return fc
442
443 def create_dynamic_array_field_class(
444 self, elem_fc, length_fc=None, user_attributes=None
445 ):
446 utils._check_type(elem_fc, bt2_field_class._FieldClass)
447 length_fc_ptr = None
448
449 if length_fc is not None:
450 utils._check_type(length_fc, bt2_field_class._UnsignedIntegerFieldClass)
451 length_fc_ptr = length_fc._ptr
452
453 ptr = native_bt.field_class_array_dynamic_create(
454 self._ptr, elem_fc._ptr, length_fc_ptr
455 )
456 self._check_field_class_create_status(ptr, 'dynamic array')
457 fc = bt2_field_class._create_field_class_from_ptr_and_get_ref(ptr)
458 self._set_field_class_user_attrs(fc, user_attributes)
459 return fc
460
461 def create_option_without_selector_field_class(
462 self, content_fc, user_attributes=None
463 ):
464 utils._check_type(content_fc, bt2_field_class._FieldClass)
465 ptr = native_bt.field_class_option_without_selector_create(
466 self._ptr, content_fc._ptr
467 )
468 self._check_field_class_create_status(ptr, 'option')
469 fc = bt2_field_class._create_field_class_from_ptr_and_get_ref(ptr)
470 self._set_field_class_user_attrs(fc, user_attributes)
471 return fc
472
473 def create_option_with_bool_selector_field_class(
474 self, content_fc, selector_fc, selector_is_reversed=False, user_attributes=None
475 ):
476 utils._check_type(content_fc, bt2_field_class._FieldClass)
477 utils._check_bool(selector_is_reversed)
478 utils._check_type(selector_fc, bt2_field_class._BoolFieldClass)
479 ptr = native_bt.field_class_option_with_selector_field_bool_create(
480 self._ptr, content_fc._ptr, selector_fc._ptr
481 )
482 self._check_field_class_create_status(ptr, 'option')
483 fc = bt2_field_class._create_field_class_from_ptr_and_get_ref(ptr)
484 self._set_field_class_user_attrs(fc, user_attributes)
485 fc._selector_is_reversed = selector_is_reversed
486 return fc
487
488 def create_option_with_integer_selector_field_class(
489 self, content_fc, selector_fc, ranges, user_attributes=None
490 ):
491 utils._check_type(content_fc, bt2_field_class._FieldClass)
492 utils._check_type(selector_fc, bt2_field_class._IntegerFieldClass)
493
494 if len(ranges) == 0:
495 raise ValueError('integer range set is empty')
496
497 if isinstance(selector_fc, bt2_field_class._UnsignedIntegerFieldClass):
498 utils._check_type(ranges, bt2_integer_range_set.UnsignedIntegerRangeSet)
499 ptr = native_bt.field_class_option_with_selector_field_integer_unsigned_create(
500 self._ptr, content_fc._ptr, selector_fc._ptr, ranges._ptr
501 )
502 else:
503 utils._check_type(ranges, bt2_integer_range_set.SignedIntegerRangeSet)
504 ptr = native_bt.field_class_option_with_selector_field_integer_signed_create(
505 self._ptr, content_fc._ptr, selector_fc._ptr, ranges._ptr
506 )
507
508 self._check_field_class_create_status(ptr, 'option')
509 fc = bt2_field_class._create_field_class_from_ptr_and_get_ref(ptr)
510 self._set_field_class_user_attrs(fc, user_attributes)
511 return fc
512
513 def create_variant_field_class(self, selector_fc=None, user_attributes=None):
514 selector_fc_ptr = None
515
516 if selector_fc is not None:
517 utils._check_type(selector_fc, bt2_field_class._IntegerFieldClass)
518 selector_fc_ptr = selector_fc._ptr
519
520 ptr = native_bt.field_class_variant_create(self._ptr, selector_fc_ptr)
521 self._check_field_class_create_status(ptr, 'variant')
522 fc = bt2_field_class._create_field_class_from_ptr_and_get_ref(ptr)
523 self._set_field_class_user_attrs(fc, user_attributes)
524 return fc
This page took 0.039431 seconds and 3 git commands to generate.