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