1 # The MIT License (MIT)
3 # Copyright (c) 2013-2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
5 # Permission is hereby granted, free of charge, to any person obtaining a copy
6 # of this software and associated documentation files (the "Software"), to deal
7 # in the Software without restriction, including without limitation the rights
8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 # copies of the Software, and to permit persons to whom the Software is
10 # furnished to do so, subject to the following conditions:
12 # The above copyright notice and this permission notice shall be included in
13 # all copies or substantial portions of the Software.
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 import babeltrace
.common
as common
25 from babeltrace
import reader_trace_handle
26 from babeltrace
import reader_event
30 class TraceCollection
:
32 A :class:`TraceCollection` is a collection of opened traces.
34 Once a trace collection is created, you can add traces to the
35 collection by using the :meth:`add_trace` or
36 :meth:`add_traces_recursive`, and then iterate on the merged
37 events using :attr:`events`.
39 You may use :meth:`remove_trace` to close and remove a specific
40 trace from a trace collection.
43 def __init__(self
, intersect_mode
=False):
45 Creates an empty trace collection.
48 self
._intersect
_mode
= intersect_mode
49 self
._trace
_handles
= set()
51 self
._ctf
_plugin
= bt2
.find_plugin('ctf')
52 assert(self
._ctf
_plugin
is not None)
53 self
._fs
_comp
_cls
= self
._ctf
_plugin
.source_component_classes
['fs']
55 def add_trace(self
, path
, format_str
):
57 Adds a trace to the trace collection.
59 *path* is the exact path of the trace on the filesystem.
61 *format_str* is a string indicating the type of trace to
62 add. ``ctf`` is currently the only supported trace format.
64 Returns the corresponding :class:`TraceHandle` instance for
65 this opened trace on success, or ``None`` on error.
67 This function **does not** recurse directories to find a
68 trace. See :meth:`add_traces_recursive` for a recursive
69 version of this function.
72 if format_str
!= 'ctf':
73 raise ValueError('only the "ctf" format is supported')
75 if not os
.path
.isfile(os
.path
.join(path
, 'metadata')):
76 raise ValueError('no "metadata" file found in "{}"'.format(path
))
78 th
= reader_trace_handle
.TraceHandle
.__new
__(reader_trace_handle
.TraceHandle
)
79 th
._id
= self
._next
_th
_id
81 th
._trace
_collection
= self
83 self
._trace
_handles
.add(th
)
86 def add_traces_recursive(self
, path
, format_str
):
88 Adds traces to this trace collection by recursively searching
89 in the *path* directory.
91 *format_str* is a string indicating the type of trace to add.
92 ``ctf`` is currently the only supported trace format.
94 Returns a :class:`dict` object mapping full paths to trace
95 handles for each trace found, or ``None`` on error.
97 See also :meth:`add_trace`.
104 for fullpath
, dirs
, files
in os
.walk(path
):
105 if "metadata" in files
:
106 trace_handle
= self
.add_trace(fullpath
, format_str
)
108 if trace_handle
is None:
112 trace_handles
[fullpath
] = trace_handle
115 if noTrace
and error
:
120 def remove_trace(self
, handle
):
122 Removes a trace from the trace collection using its trace
123 handle *trace_handle*.
125 :class:`TraceHandle` objects are returned by :meth:`add_trace`
126 and :meth:`add_traces_recursive`.
129 if not isinstance(handle
, reader_trace_handle
.TraceHandle
):
130 raise TypeError("'{}' is not a 'TraceHandle' object".format(
131 handle
.__class
__.__name
__))
133 # this can raise but it would mean the trace handle is not part
134 # of this trace collection anyway
135 self
._trace
_handles
.remove(handle
)
138 def intersect_mode(self
):
139 return self
._intersect
_mode
142 def has_intersection(self
):
143 return any(th
._has
_intersection
for th
in self
._trace
_handles
)
148 Generates the ordered :class:`Event` objects of all the opened
149 traces contained in this trace collection.
152 return self
._gen
_events
()
154 def events_timestamps(self
, timestamp_begin
, timestamp_end
):
156 Generates the ordered :class:`Event` objects of all the opened
157 traces contained in this trace collection from *timestamp_begin*
160 *timestamp_begin* and *timestamp_end* are given in nanoseconds
163 See :attr:`events` for notes and limitations.
166 return self
._gen
_events
(timestamp_begin
/ 1e9
, timestamp_end
/ 1e9
)
168 def _gen_events(self
, begin_s
=None, end_s
=None):
169 specs
= [bt2
.SourceComponentSpec('ctf', 'fs', th
.path
) for th
in self
._trace
_handles
]
172 iter_cls
= bt2
.TraceCollectionNotificationIterator
173 tc_iter
= iter_cls(specs
,
174 stream_intersection_mode
=self
._intersect
_mode
,
175 begin
=begin_s
, end
=end_s
,
176 notification_types
=[bt2
.EventNotification
])
177 return map(reader_event
._create
_event
, tc_iter
)
182 def timestamp_begin(self
):
184 Begin timestamp of this trace collection (nanoseconds since Epoch).
187 if not self
._trace
_handles
:
190 return min(th
.timestamp_begin
for th
in self
._trace
_handles
)
193 def timestamp_end(self
):
195 End timestamp of this trace collection (nanoseconds since Epoch).
198 if not self
._trace
_handles
:
201 return max(th
.timestamp_end
for th
in self
._trace
_handles
)