From c6af194f4d5f4478fbd14a019e41cff93f9c207e Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Thu, 13 Jun 2019 22:22:26 -0400 Subject: [PATCH] bt2: stream activity messages: create with unknown/infinite default CS This patch makes it possible to create stream activity beginning and end messages with unknown or infinite default clock snapshots. It was already possible to create them with known default clock snapshots, that is, with a value. With this patch, you pass either `self._unknown_clock_snapshot` or `self._infinite_clock_snapshot`, when implementing a `bt2._UserMessageIterator`, as the default clock snapshot when you call self._create_stream_activity_beginning_message() or self._create_stream_activity_end_message(). They are instances of internal types which are only used for this. The creation methods use `_unknown_clock_snapshot` by default. This is similar to how bt_message_stream_activity_beginning_create() and bt_message_stream_activity_end_create() create messages with unknown default clock snapshots. `test_message.py` tests the new feature. Also in this patch: `_BaseClockSnapshot` does not inherit `object._UniqueObject` anymore so that `_UnknownClockSnapshot` and `_InfiniteClockSnapshot` do not either. This is so that the default clock snapshot properties of the stream activity beginning/end messages can return instances of those types without having actual native pointers, because there are none. Signed-off-by: Philippe Proulx Change-Id: I56d5cd9fffb77d505f61522073aaf80ccd58eb8e Reviewed-on: https://review.lttng.org/c/babeltrace/+/1430 Reviewed-by: Simon Marchi --- src/bindings/python/bt2/bt2/__init__.py.in | 2 + src/bindings/python/bt2/bt2/clock_snapshot.py | 10 +- src/bindings/python/bt2/bt2/message.py | 37 ++- .../python/bt2/bt2/message_iterator.py | 63 ++--- src/bindings/python/bt2/bt2/utils.py | 30 ++- tests/bindings/python/bt2/test_message.py | 225 +++++++++++++++++- 6 files changed, 312 insertions(+), 55 deletions(-) diff --git a/src/bindings/python/bt2/bt2/__init__.py.in b/src/bindings/python/bt2/bt2/__init__.py.in index f80cf658..1bebfd4e 100644 --- a/src/bindings/python/bt2/bt2/__init__.py.in +++ b/src/bindings/python/bt2/bt2/__init__.py.in @@ -62,6 +62,8 @@ from bt2.trace_collection_message_iterator import * from bt2.value import * from bt2.value import _Value from bt2.value import _IntegerValue +from bt2.clock_snapshot import _UnknownClockSnapshot +from bt2.clock_snapshot import _InfiniteClockSnapshot class Error(Exception): diff --git a/src/bindings/python/bt2/bt2/clock_snapshot.py b/src/bindings/python/bt2/bt2/clock_snapshot.py index 4bf37d62..89d7a11b 100644 --- a/src/bindings/python/bt2/bt2/clock_snapshot.py +++ b/src/bindings/python/bt2/bt2/clock_snapshot.py @@ -26,16 +26,14 @@ import bt2 import functools -class _BaseClockSnapshot(object._UniqueObject): +@functools.total_ordering +class _ClockSnapshot(object._UniqueObject): @property def clock_class(self): cc_ptr = native_bt.clock_snapshot_borrow_clock_class_const(self._ptr) assert cc_ptr is not None return bt2.clock_class._ClockClass._create_from_ptr_and_get_ref(cc_ptr) - -@functools.total_ordering -class _ClockSnapshot(_BaseClockSnapshot): @property def value(self): return native_bt.clock_snapshot_get_value(self._ptr) @@ -62,9 +60,9 @@ class _ClockSnapshot(_BaseClockSnapshot): return self.value < int(other) -class _UnknownClockSnapshot(_BaseClockSnapshot): +class _UnknownClockSnapshot: pass -class _InfiniteClockSnapshot(_BaseClockSnapshot): +class _InfiniteClockSnapshot: pass diff --git a/src/bindings/python/bt2/bt2/message.py b/src/bindings/python/bt2/bt2/message.py index 56b545da..97782653 100644 --- a/src/bindings/python/bt2/bt2/message.py +++ b/src/bindings/python/bt2/bt2/message.py @@ -110,28 +110,43 @@ class _StreamEndMessage(_StreamMessage): _borrow_stream_ptr = staticmethod(native_bt.message_stream_end_borrow_stream) +# Specific type to pass an unknown clock snapshot when creating a stream +# beginning/end message. +class _StreamActivityMessageUnknownClockSnapshot: + pass + + +# Specific type to pass an infinite clock snapshot when creating a +# stream beginning/end message. +class _StreamActivityMessageInfiniteClockSnapshot: + pass + + class _StreamActivityMessage(_Message): @property def default_clock_snapshot(self): - self._check_has_default_clock_class(self.stream.cls.default_clock_class) status, snapshot_ptr = self._borrow_default_clock_snapshot_ptr(self._ptr) if status == native_bt.MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN: - snapshot_type = bt2.clock_snapshot._ClockSnapshot + cs_type = bt2.clock_snapshot._ClockSnapshot + assert snapshot_ptr is not None + return cs_type._create_from_ptr_and_get_ref(snapshot_ptr, self._ptr, + self._get_ref, self._put_ref) elif status == native_bt.MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN: - snapshot_type = bt2.clock_snapshot._UnknownClockSnapshot + return bt2.clock_snapshot._UnknownClockSnapshot() elif status == native_bt.MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE: - snapshot_type = bt2.clock_snapshot._InfiniteClockSnapshot + return bt2.clock_snapshot._InfiniteClockSnapshot() else: raise bt2.Error('cannot borrow default clock snapshot from message') - assert snapshot_ptr is not None - - return snapshot_type._create_from_ptr_and_get_ref( - snapshot_ptr, self._ptr, self._get_ref, self._put_ref) - def _default_clock_snapshot(self, value): - self._set_default_clock_snapshot_ptr(self._ptr, value) + if type(value) is _StreamActivityMessageUnknownClockSnapshot: + self._set_default_clock_snapshot_state(self._ptr, native_bt.MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN) + elif type(value) is _StreamActivityMessageInfiniteClockSnapshot: + self._set_default_clock_snapshot_state(self._ptr, native_bt.MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE) + else: + assert utils._is_uint64(value) + self._set_default_clock_snapshot_ptr(self._ptr, value) _default_clock_snapshot = property(fset=_default_clock_snapshot) @@ -145,12 +160,14 @@ class _StreamActivityMessage(_Message): class _StreamActivityBeginningMessage(_StreamActivityMessage): _borrow_default_clock_snapshot_ptr = staticmethod(native_bt.message_stream_activity_beginning_borrow_default_clock_snapshot_const) _set_default_clock_snapshot_ptr = staticmethod(native_bt.message_stream_activity_beginning_set_default_clock_snapshot) + _set_default_clock_snapshot_state = staticmethod(native_bt.message_stream_activity_beginning_set_default_clock_snapshot_state) _borrow_stream_ptr = staticmethod(native_bt.message_stream_activity_beginning_borrow_stream) class _StreamActivityEndMessage(_StreamActivityMessage): _borrow_default_clock_snapshot_ptr = staticmethod(native_bt.message_stream_activity_end_borrow_default_clock_snapshot_const) _set_default_clock_snapshot_ptr = staticmethod(native_bt.message_stream_activity_end_set_default_clock_snapshot) + _set_default_clock_snapshot_state = staticmethod(native_bt.message_stream_activity_end_set_default_clock_snapshot_state) _borrow_stream_ptr = staticmethod(native_bt.message_stream_activity_end_borrow_stream) diff --git a/src/bindings/python/bt2/bt2/message_iterator.py b/src/bindings/python/bt2/bt2/message_iterator.py index 7f996b00..e5199290 100644 --- a/src/bindings/python/bt2/bt2/message_iterator.py +++ b/src/bindings/python/bt2/bt2/message_iterator.py @@ -135,30 +135,21 @@ class _UserMessageIterator(_MessageIterator): ptr = msg._release() return int(ptr) - # Validate that the presence or lack of presence of a - # `default_clock_snapshot` value is valid in the context of `stream_class`. - @staticmethod - def _validate_default_clock_snapshot(stream_class, default_clock_snapshot): - stream_class_has_default_clock_class = stream_class.default_clock_class is not None - - if stream_class_has_default_clock_class and default_clock_snapshot is None: - raise bt2.Error( - 'stream class has a default clock class, default_clock_snapshot should not be None') - - if not stream_class_has_default_clock_class and default_clock_snapshot is not None: - raise bt2.Error( - 'stream class has no default clock class, default_clock_snapshot should be None') - def _create_event_message(self, event_class, packet, default_clock_snapshot=None): utils._check_type(event_class, bt2.event_class._EventClass) utils._check_type(packet, bt2.packet._Packet) - self._validate_default_clock_snapshot(packet.stream.cls, default_clock_snapshot) if default_clock_snapshot is not None: + if event_class.stream_class.default_clock_class is None: + raise ValueError('event messages in this stream must not have a default clock snapshot') + utils._check_uint64(default_clock_snapshot) ptr = native_bt.message_event_create_with_default_clock_snapshot( self._ptr, event_class._ptr, packet._ptr, default_clock_snapshot) else: + if event_class.stream_class.default_clock_class is not None: + raise ValueError('event messages in this stream must have a default clock snapshot') + ptr = native_bt.message_event_create( self._ptr, event_class._ptr, packet._ptr) @@ -177,6 +168,26 @@ class _UserMessageIterator(_MessageIterator): return bt2.message._MessageIteratorInactivityMessage(ptr) + _unknown_clock_snapshot = bt2.message._StreamActivityMessageUnknownClockSnapshot() + _infinite_clock_snapshot = bt2.message._StreamActivityMessageInfiniteClockSnapshot() + + @staticmethod + def _validate_stream_activity_message_default_clock_snapshot(stream, default_cs): + isinst_infinite = isinstance(default_cs, bt2.message._StreamActivityMessageInfiniteClockSnapshot) + isinst_unknown = isinstance(default_cs, bt2.message._StreamActivityMessageUnknownClockSnapshot) + + if utils._is_uint64(default_cs): + pass + elif isinst_infinite or isinst_unknown: + if default_cs is not _UserMessageIterator._unknown_clock_snapshot and default_cs is not _UserMessageIterator._infinite_clock_snapshot: + raise ValueError('unexpected value for default clock snapshot') + else: + raise TypeError("unexpected type '{}' for default clock snapshot".format(default_cs.__class__.__name__)) + + if stream.cls.default_clock_class is None: + if utils._is_uint64(default_cs): + raise ValueError('stream activity messages in this stream cannot have a known default clock snapshot') + def _create_stream_beginning_message(self, stream): utils._check_type(stream, bt2.stream._Stream) @@ -186,10 +197,10 @@ class _UserMessageIterator(_MessageIterator): return bt2.message._StreamBeginningMessage(ptr) - def _create_stream_activity_beginning_message(self, stream, default_clock_snapshot=None): + def _create_stream_activity_beginning_message(self, stream, + default_clock_snapshot=_unknown_clock_snapshot): utils._check_type(stream, bt2.stream._Stream) - self._validate_default_clock_snapshot(stream.cls, default_clock_snapshot) - + self._validate_stream_activity_message_default_clock_snapshot(stream, default_clock_snapshot) ptr = native_bt.message_stream_activity_beginning_create(self._ptr, stream._ptr) if ptr is None: @@ -197,16 +208,13 @@ class _UserMessageIterator(_MessageIterator): 'cannot create stream activity beginning message object') msg = bt2.message._StreamActivityBeginningMessage(ptr) - - if default_clock_snapshot is not None: - msg._default_clock_snapshot = default_clock_snapshot - + msg._default_clock_snapshot = default_clock_snapshot return msg - def _create_stream_activity_end_message(self, stream, default_clock_snapshot=None): + def _create_stream_activity_end_message(self, stream, + default_clock_snapshot=_unknown_clock_snapshot): utils._check_type(stream, bt2.stream._Stream) - self._validate_default_clock_snapshot(stream.cls, default_clock_snapshot) - + self._validate_stream_activity_message_default_clock_snapshot(stream, default_clock_snapshot) ptr = native_bt.message_stream_activity_end_create(self._ptr, stream._ptr) if ptr is None: @@ -214,10 +222,7 @@ class _UserMessageIterator(_MessageIterator): 'cannot create stream activity end message object') msg = bt2.message._StreamActivityEndMessage(ptr) - - if default_clock_snapshot is not None: - msg._default_clock_snapshot = default_clock_snapshot - + msg._default_clock_snapshot = default_clock_snapshot return msg def _create_stream_end_message(self, stream): diff --git a/src/bindings/python/bt2/bt2/utils.py b/src/bindings/python/bt2/bt2/utils.py index bd8ebf8e..b564fcad 100644 --- a/src/bindings/python/bt2/bt2/utils.py +++ b/src/bindings/python/bt2/bt2/utils.py @@ -49,18 +49,34 @@ def _check_type(o, expected_type): expected_type)) -def _is_int64(v): - _check_int(v) +def _is_in_int64_range(v): + assert(isinstance(v, int)) return v >= -(2**63) and v <= (2**63 - 1) -def _is_uint64(v): - _check_int(v) +def _is_int64(v): + if not isinstance(v, int): + return False + + return _is_in_int64_range(v) + + +def _is_in_uint64_range(v): + assert(isinstance(v, int)) return v >= 0 and v <= (2**64 - 1) +def _is_uint64(v): + if not isinstance(v, int): + return False + + return _is_in_uint64_range(v) + + def _check_int64(v, msg=None): - if not _is_int64(v): + _check_int(v) + + if not _is_in_int64_range(v): if msg is None: msg = 'expecting a signed 64-bit integral value' @@ -69,7 +85,9 @@ def _check_int64(v, msg=None): def _check_uint64(v, msg=None): - if not _is_uint64(v): + _check_int(v) + + if not _is_in_uint64_range(v): if msg is None: msg = 'expecting an unsigned 64-bit integral value' diff --git a/tests/bindings/python/bt2/test_message.py b/tests/bindings/python/bt2/test_message.py index 5f11c9a9..ed6c3129 100644 --- a/tests/bindings/python/bt2/test_message.py +++ b/tests/bindings/python/bt2/test_message.py @@ -164,8 +164,8 @@ class AllMessagesTestCase(unittest.TestCase): self.assertEqual(msg.stream.addr, self._stream.addr) elif i == 1: self.assertIsInstance(msg, bt2.message._StreamActivityBeginningMessage) - with self.assertRaises(bt2.NonexistentClockSnapshot): - msg.default_clock_snapshot + self.assertIsInstance(msg.default_clock_snapshot, + bt2._UnknownClockSnapshot) elif i == 2: self.assertIsInstance(msg, bt2.message._PacketBeginningMessage) self.assertEqual(msg.packet.addr, self._packet.addr) @@ -198,11 +198,228 @@ class AllMessagesTestCase(unittest.TestCase): elif i == 7: self.assertIsInstance(msg, bt2.message._StreamActivityEndMessage) self.assertEqual(msg.stream.addr, self._stream.addr) - with self.assertRaises(bt2.NonexistentClockSnapshot): - msg.default_clock_snapshot + self.assertIsInstance(msg.default_clock_snapshot, + bt2._UnknownClockSnapshot) elif i == 8: self.assertIsInstance(msg, bt2.message._StreamEndMessage) self.assertEqual(msg.stream.addr, self._stream.addr) else: raise Exception + +class StreamActivityMessagesTestCase(unittest.TestCase): + def _test_create_msg(self, with_cc, test_create_beginning_func, test_create_end_func): + class MyIter(bt2._UserMessageIterator): + def __init__(self, self_port_output): + self._at = 0 + + def __next__(self): + if self._at == 0: + msg = self._create_stream_beginning_message(self._component._stream) + elif self._at == 1: + msg = test_create_beginning_func(self, self._component._stream) + elif self._at == 2: + msg = test_create_end_func(self, self._component._stream) + elif self._at == 3: + msg = self._create_stream_end_message(self._component._stream) + elif self._at >= 4: + raise bt2.Stop + + self._at += 1 + return msg + + class MySrc(bt2._UserSourceComponent, message_iterator_class=MyIter): + def __init__(self, params): + self._add_output_port('out') + tc = self._create_trace_class() + + if with_cc: + cc = self._create_clock_class() + sc = tc.create_stream_class(default_clock_class=cc) + else: + sc = tc.create_stream_class() + + # Create payload field class + trace = tc() + self._stream = trace.create_stream(sc) + + graph = bt2.Graph() + src_comp = graph.add_component(MySrc, 'src') + msg_iter = graph.create_output_port_message_iterator(src_comp.output_ports['out']) + + for msg in msg_iter: + pass + + def test_create_beginning_with_cc_with_known_default_cs(self): + def create_beginning(msg_iter, stream): + msg = msg_iter._create_stream_activity_beginning_message(stream, 172) + self.assertEqual(msg.default_clock_snapshot.value, 172) + return msg + + def create_end(msg_iter, stream): + return msg_iter._create_stream_activity_end_message(stream, 199) + + self._test_create_msg(True, create_beginning, create_end) + + def test_create_end_with_cc_with_known_default_cs(self): + def create_beginning(msg_iter, stream): + return msg_iter._create_stream_activity_beginning_message(stream, 172) + + def create_end(msg_iter, stream): + msg = msg_iter._create_stream_activity_end_message(stream, 199) + self.assertEqual(msg.default_clock_snapshot.value, 199) + return msg + + self._test_create_msg(True, create_beginning, create_end) + + def test_create_beginning_with_cc_with_unknown_default_cs(self): + def create_beginning(msg_iter, stream): + msg = msg_iter._create_stream_activity_beginning_message(stream, + msg_iter._unknown_clock_snapshot) + self.assertIsInstance(msg.default_clock_snapshot, + bt2._UnknownClockSnapshot) + return msg + + def create_end(msg_iter, stream): + return msg_iter._create_stream_activity_end_message(stream, 199) + + self._test_create_msg(True, create_beginning, create_end) + + def test_create_end_with_cc_with_unknown_default_cs(self): + def create_beginning(msg_iter, stream): + return msg_iter._create_stream_activity_beginning_message(stream, 172) + + def create_end(msg_iter, stream): + msg = msg_iter._create_stream_activity_end_message(stream, + msg_iter._unknown_clock_snapshot) + self.assertIsInstance(msg.default_clock_snapshot, + bt2._UnknownClockSnapshot) + return msg + + self._test_create_msg(True, create_beginning, create_end) + + def test_create_beginning_with_cc_with_infinite_default_cs(self): + def create_beginning(msg_iter, stream): + msg = msg_iter._create_stream_activity_beginning_message(stream, + msg_iter._infinite_clock_snapshot) + self.assertIsInstance(msg.default_clock_snapshot, + bt2._InfiniteClockSnapshot) + return msg + + def create_end(msg_iter, stream): + return msg_iter._create_stream_activity_end_message(stream, 199) + + self._test_create_msg(True, create_beginning, create_end) + + def test_create_end_with_cc_with_infinite_default_cs(self): + def create_beginning(msg_iter, stream): + return msg_iter._create_stream_activity_beginning_message(stream, 172) + + def create_end(msg_iter, stream): + msg = msg_iter._create_stream_activity_end_message(stream, + msg_iter._infinite_clock_snapshot) + self.assertIsInstance(msg.default_clock_snapshot, + bt2._InfiniteClockSnapshot) + return msg + + self._test_create_msg(True, create_beginning, create_end) + + def test_create_beginning_without_cc_with_known_default_cs(self): + def create_beginning(msg_iter, stream): + with self.assertRaises(ValueError): + msg_iter._create_stream_activity_beginning_message(stream, 172) + + return msg_iter._create_stream_activity_beginning_message(stream) + + def create_end(msg_iter, stream): + return msg_iter._create_stream_activity_end_message(stream) + + self._test_create_msg(False, create_beginning, create_end) + + def test_create_end_without_cc_with_known_default_cs(self): + def create_beginning(msg_iter, stream): + return msg_iter._create_stream_activity_beginning_message(stream) + + def create_end(msg_iter, stream): + with self.assertRaises(ValueError): + msg_iter._create_stream_activity_end_message(stream, 199) + + return msg_iter._create_stream_activity_end_message(stream) + + self._test_create_msg(False, create_beginning, create_end) + + def test_create_beginning_without_cc_with_unknown_default_cs(self): + def create_beginning(msg_iter, stream): + msg = msg_iter._create_stream_activity_beginning_message(stream, + msg_iter._unknown_clock_snapshot) + self.assertIsInstance(msg.default_clock_snapshot, + bt2._UnknownClockSnapshot) + return msg + + def create_end(msg_iter, stream): + return msg_iter._create_stream_activity_end_message(stream) + + self._test_create_msg(False, create_beginning, create_end) + + def test_create_end_without_cc_with_unknown_default_cs(self): + def create_beginning(msg_iter, stream): + return msg_iter._create_stream_activity_beginning_message(stream) + + def create_end(msg_iter, stream): + msg = msg_iter._create_stream_activity_end_message(stream, + msg_iter._unknown_clock_snapshot) + self.assertIsInstance(msg.default_clock_snapshot, + bt2._UnknownClockSnapshot) + return msg + + self._test_create_msg(False, create_beginning, create_end) + + def test_create_beginning_without_cc_with_infinite_default_cs(self): + def create_beginning(msg_iter, stream): + msg = msg_iter._create_stream_activity_beginning_message(stream, + msg_iter._infinite_clock_snapshot) + self.assertIsInstance(msg.default_clock_snapshot, + bt2._InfiniteClockSnapshot) + return msg + + def create_end(msg_iter, stream): + return msg_iter._create_stream_activity_end_message(stream) + + self._test_create_msg(False, create_beginning, create_end) + + def test_create_end_without_cc_with_infinite_default_cs(self): + def create_beginning(msg_iter, stream): + return msg_iter._create_stream_activity_beginning_message(stream) + + def create_end(msg_iter, stream): + msg = msg_iter._create_stream_activity_end_message(stream, + msg_iter._infinite_clock_snapshot) + self.assertIsInstance(msg.default_clock_snapshot, + bt2._InfiniteClockSnapshot) + return msg + + self._test_create_msg(False, create_beginning, create_end) + + def test_create_beginning_default_cs_wrong_type(self): + def create_beginning(msg_iter, stream): + with self.assertRaises(TypeError): + msg_iter._create_stream_activity_beginning_message(stream, 'infinite') + + return msg_iter._create_stream_activity_beginning_message(stream) + + def create_end(msg_iter, stream): + return msg_iter._create_stream_activity_end_message(stream) + + self._test_create_msg(False, create_beginning, create_end) + + def test_create_end_without_default_cs_wrong_type(self): + def create_beginning(msg_iter, stream): + return msg_iter._create_stream_activity_beginning_message(stream) + + def create_end(msg_iter, stream): + with self.assertRaises(TypeError): + msg_iter._create_stream_activity_end_message(stream, 'unknown') + + return msg_iter._create_stream_activity_end_message(stream) + + self._test_create_msg(False, create_beginning, create_end) -- 2.34.1