Add initial Python bindings documentation
[babeltrace.git] / doc / bindings / python / source / examples.rst
1 .. include:: common.rst
2
3 .. _examples:
4
5 Examples
6 ========
7 This section contains a few short and straightforward examples which
8 show how to use the Babeltrace |~| 2 Python bindings.
9
10 The :mod:`bt2` package provides the Babeltrace |~| 2 Python bindings.
11 Note that the :mod:`babeltrace` package is part of the Babeltrace |~| 1
12 project: it's somewhat out-of-date and not compatible with the
13 :mod:`bt2` package.
14
15 Assume that all the examples below are named :file:`example.py`.
16
17 .. _examples_tcmi:
18
19 Iterate trace events
20 --------------------
21 The most convenient and high-level way to iterate the events of one or
22 more traces is with a :class:`bt2.TraceCollectionMessageIterator`
23 object.
24
25 A :class:`bt2.TraceCollectionMessageIterator` object roughly offers the
26 same features as the ``convert`` command of the :command:`babeltrace2`
27 command-line program (see the :bt2man:`babeltrace2-convert(1)` manual
28 page), but in a programmatic, Pythonic way.
29
30 As of Babeltrace |~| |version|, the trace collection message iterator
31 class is a Python bindings-only feature: the Python code uses
32 libbabeltrace2 internally, but the latter does not offer this utility as
33 such.
34
35 The :class:`bt2.TraceCollectionMessageIterator` interface features:
36
37 * **Automatic source component (trace format) discovery**.
38
39 ``convert`` command equivalent example:
40
41 .. code-block:: text
42
43 $ babeltrace2 /path/to/my/trace
44
45 * **Explicit component class instantiation**.
46
47 ``convert`` command equivalent example:
48
49 .. code-block:: text
50
51 $ babeltrace2 --component=source.my.format
52
53 * **Passing initialization parameters to both auto-discovered and
54 explicitly created components**.
55
56 ``convert`` command equivalent example:
57
58 .. code-block:: text
59
60 $ babeltrace2 /path/to/my/trace --params=detailed=no \
61 --component=source.ctf.fs \
62 --params='inputs=["/path/to/my/trace"]'
63
64 * **Trace event muxing**.
65
66 The message iterator muxes (combines) the events from multiple
67 compatible streams into a single, time-sorted sequence of events.
68
69 .. code-block:: text
70
71 $ babeltrace2 /path/to/trace1 /path/to/trace2 /path/to/trace3
72
73 * **Stream intersection mode**.
74
75 ``convert`` command equivalent example:
76
77 .. code-block:: text
78
79 $ babeltrace2 /path/to/my/trace --stream-intersection
80
81 * **Stream trimming with beginning and/or end times**.
82
83 ``convert`` command equivalent example:
84
85 .. code-block:: text
86
87 $ babeltrace2 /path/to/my/trace --begin=22:14:38 --end=22:15:07
88
89 While the :command:`babeltrace2 convert` command creates a ``sink.text.pretty``
90 component class (by default) to pretty-print events as plain text lines,
91 a :class:`bt2.TraceCollectionMessageIterator` object is a Python
92 iterator which makes its user a message consumer (there's no sink
93 component)::
94
95 import bt2
96
97 for msg in bt2.TraceCollectionMessageIterator('/path/to/trace'):
98 if type(msg) is bt2._EventMessageConst:
99 print(msg.event.name)
100
101 .. _examples_tcmi_autodisc:
102
103 Discover traces
104 ~~~~~~~~~~~~~~~
105 Pass one or more file paths, directory paths, or other strings when you
106 build a :class:`bt2.TraceCollectionMessageIterator` object to let it
107 automatically determine which source components to create for you.
108
109 If you pass a directory path, the message iterator traverses the
110 directory recursively to find traces, automatically selecting the
111 appropriate source component classes to instantiate.
112
113 The :class:`bt2.TraceCollectionMessageIterator` object and the
114 :command:`babeltrace2 convert` CLI command share the same automatic
115 component discovery algorithm. See the
116 :bt2link:`Create implicit components from non-option arguments <https://babeltrace.org/docs/v@ver@/man1/babeltrace2-convert.1/#doc-comp-create-impl-non-opt>`
117 section of the :bt2man:`babeltrace2-convert(1)` manual page for more
118 details.
119
120 The following example shows how to use a
121 :class:`bt2.TraceCollectionMessageIterator` object to automatically
122 discover one or more traces from a single path (file or directory). For
123 each trace event, the example prints its name::
124
125 import bt2
126 import sys
127
128 # Get the trace path from the first command-line argument.
129 path = sys.argv[1]
130
131 # Create a trace collection message iterator with this path.
132 msg_it = bt2.TraceCollectionMessageIterator(path)
133
134 # Iterate the trace messages.
135 for msg in msg_it:
136 # `bt2._EventMessageConst` is the Python type of an event message.
137 if type(msg) is bt2._EventMessageConst:
138 # An event message holds a trace event.
139 event = msg.event
140
141 # Print event's name.
142 print(event.name)
143
144 Run this example:
145
146 .. code-block:: text
147
148 $ python3 example.py /path/to/one/or/more/traces
149
150 Output example:
151
152 .. code-block:: text
153
154 kmem_kmalloc
155 kmem_kfree
156 kmem_cache_alloc_node
157 block_getrq
158 kmem_kmalloc
159 block_plug
160 kmem_kfree
161 block_rq_insert
162 kmem_kmalloc
163 kmem_kfree
164 kmem_kmalloc
165 kmem_kfree
166
167 The example above is simplistic; it does not catch the exceptions that
168 some statements can raise:
169
170 * ``bt2.TraceCollectionMessageIterator(path)`` raises an exception if
171 it cannot find any trace.
172
173 * Each iteration of the loop, or, more precisely, the
174 :meth:`bt2.TraceCollectionMessageIterator.__next__` method, raises
175 an exception if there's any error during the iteration process.
176
177 For example, an internal source component message iterator can fail
178 when trying to decode a malformed trace file.
179
180 .. _examples_tcmi_expl:
181
182 Create explicit source components
183 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
184 If `automatic source component discovery <#examples-tcmi-autodisc>`_
185 doesn't work for you (for example, because the source component class
186 you actually need to instantiate doesn't offer the
187 ``babeltrace.support-info`` query object), create explicit source
188 components when you build a :class:`bt2.TraceCollectionMessageIterator`
189 object.
190
191 The following example builds a trace collection message iterator to
192 explicitly instantiate a ``source.ctf.fs`` component class (found in the
193 ``ctf`` plugin). Again, for each trace event, the example prints its
194 name::
195
196 import bt2
197 import sys
198
199 # Find the `ctf` plugin (shipped with Babeltrace 2).
200 ctf_plugin = bt2.find_plugin('ctf')
201
202 # Get the `source.ctf.fs` component class from the plugin.
203 fs_cc = ctf_plugin.source_component_classes['fs']
204
205 # Create a trace collection message iterator, instantiating a single
206 # `source.ctf.fs` component class with the `inputs` initialization
207 # parameter set to open a single CTF trace.
208 msg_it = bt2.TraceCollectionMessageIterator(bt2.ComponentSpec(fs_cc, {
209 # Get the CTF trace path from the first command-line argument.
210 'inputs': [sys.argv[1]],
211 }))
212
213 # Iterate the trace messages.
214 for msg in msg_it:
215 # `bt2._EventMessageConst` is the Python type of an event message.
216 if type(msg) is bt2._EventMessageConst:
217 # Print event's name.
218 print(msg.event.name)
219
220 Run this example:
221
222 .. code-block:: text
223
224 $ python3 example.py /path/to/ctf/trace
225
226 Output example:
227
228 .. code-block:: text
229
230 kmem_kmalloc
231 kmem_kfree
232 kmem_cache_alloc_node
233 block_getrq
234 kmem_kmalloc
235 block_plug
236 kmem_kfree
237 block_rq_insert
238 kmem_kmalloc
239 kmem_kfree
240 kmem_kmalloc
241 kmem_kfree
242
243 The example above looks similar to the previous one using
244 `automatic source component discovery <#examples-tcmi-autodisc>`_,
245 but there are notable differences:
246
247 * A ``source.ctf.fs`` component expects to receive the path to a
248 *single* `CTF <https://diamon.org/ctf/>`_ trace (a directory
249 containing a file named ``metadata``).
250
251 Unlike the previous example, you must pass the exact
252 :abbr:`CTF (Common Trace Format)` trace directory path, *not* a
253 parent directory path.
254
255 * Unlike the previous example, the example above can only read a single
256 trace.
257
258 If you want to read multiple :abbr:`CTF (Common Trace Format)` traces
259 using explicit component class instantiation with a single trace
260 collection message iterator, you must create one ``source.ctf.fs``
261 component per trace.
262
263 Note that the :class:`bt2.ComponentSpec` class offers the
264 :meth:`from_named_plugin_and_component_class` convenience static method
265 which finds the plugin and component class for you. You could therefore
266 rewrite the trace collection message iterator creation part of the
267 example above as::
268
269 # Create a trace collection message iterator, instantiating a single
270 # `source.ctf.fs` component class with the `inputs` initialization
271 # parameter set to open a single CTF trace.
272 msg_it = bt2.TraceCollectionMessageIterator(
273 bt2.ComponentSpec.from_named_plugin_and_component_class('ctf', 'fs', {
274 # Get the CTF trace path from the first command-line argument.
275 'inputs': [sys.argv[1]],
276 })
277 )
278
279 .. _examples_tcmi_ev_field:
280
281 Get a specific event field's value
282 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
283 The :ref:`examples_tcmi_autodisc` and :ref:`examples_tcmi_expl` examples
284 show that a :class:`bt2.TraceCollectionMessageIterator` iterates the
285 time-sorted *messages* of one or more traces.
286
287 One specific type of message is :class:`bt2._EventMessageConst`, which
288 holds a trace event object.
289
290 .. note::
291
292 Everything you can find in the :mod:`bt2` package is publicly
293 accessible.
294
295 Names which start with ``_`` (underscore), like
296 :class:`bt2._EventMessageConst`, indicate that you can't
297 *instantiate* such a class (you cannot call the class). However, the
298 type itself remains public so that you can use its name to check an
299 object's type:
300
301 .. code-block:: python
302
303 if type(msg) is bt2._EventMessageConst:
304 # ...
305
306 .. code-block:: python
307
308 if isinstance(field, bt2._IntegerFieldConst):
309 # ...
310
311 Access an event object's field by using the event as a simple mapping
312 (like a read-only :class:`dict`), where keys are field names. The field
313 can belong to any part of the event (contexts or payload) and to its
314 packet's context, if any::
315
316 import bt2
317 import sys
318
319 # Create a trace collection message iterator from the first
320 # command-line argument.
321 msg_it = bt2.TraceCollectionMessageIterator(sys.argv[1])
322
323 # Iterate the trace messages.
324 for msg in msg_it:
325 # `bt2._EventMessageConst` is the Python type of an event message.
326 # Only keep such messages.
327 if type(msg) is not bt2._EventMessageConst:
328 continue
329
330 # An event message holds a trace event.
331 event = msg.event
332
333 # Only check `sched_switch` events.
334 if event.name != 'sched_switch':
335 continue
336
337 # In an LTTng trace, the `cpu_id` field is a packet context field.
338 # The mapping interface of `event` can still find it.
339 cpu_id = event['cpu_id']
340
341 # Previous and next process short names are found in the event's
342 # `prev_comm` and `next_comm` fields.
343 prev_comm = event['prev_comm']
344 next_comm = event['next_comm']
345
346 # Print line, using field values.
347 msg = 'CPU {}: Switching process `{}` → `{}`'
348 print(msg.format(cpu_id, prev_comm, next_comm))
349
350 The example above assumes that the traces to open are
351 `LTTng <https://lttng.org/>`_ Linux kernel traces.
352
353 Run this example:
354
355 .. code-block:: text
356
357 $ python3 example.py /path/to/one/or/more/lttng/traces
358
359 Output example:
360
361 .. code-block:: text
362
363 CPU 2: Switching process `Timer` → `swapper/2`
364 CPU 0: Switching process `swapper/0` → `firefox`
365 CPU 0: Switching process `firefox` → `swapper/0`
366 CPU 0: Switching process `swapper/0` → `rcu_preempt`
367 CPU 0: Switching process `rcu_preempt` → `swapper/0`
368 CPU 3: Switching process `swapper/3` → `alsa-sink-ALC26`
369 CPU 2: Switching process `swapper/2` → `Timer`
370 CPU 2: Switching process `Timer` → `swapper/2`
371 CPU 2: Switching process `swapper/2` → `pulseaudio`
372 CPU 0: Switching process `swapper/0` → `firefox`
373 CPU 1: Switching process `swapper/1` → `threaded-ml`
374 CPU 2: Switching process `pulseaudio` → `Timer`
375
376 If you need to access a specific field, use:
377
378 Event payload
379 :attr:`bt2._EventConst.payload_field` property.
380
381 Event specific context
382 :attr:`bt2._EventConst.specific_context_field` property.
383
384 Event common context
385 :attr:`bt2._EventConst.common_context_field` property.
386
387 Packet context
388 :attr:`bt2._PacketConst.context_field` property.
389
390 Use Python's ``in`` operator to verify if a specific "root" field (in the list
391 above) contains a given field by name::
392
393 if 'next_comm' in event.payload_field:
394 # ...
395
396 The following example iterates the events of a given trace, printing the
397 value of the ``fd`` payload field if it's available::
398
399 import bt2
400 import sys
401
402 # Create a trace collection message iterator from the first command-line
403 # argument.
404 msg_it = bt2.TraceCollectionMessageIterator(sys.argv[1])
405
406 # Iterate the trace messages.
407 for msg in msg_it:
408 # `bt2._EventMessageConst` is the Python type of an event message.
409 if type(msg) is bt2._EventMessageConst:
410 # Check if the `fd` event payload field exists.
411 if 'fd' in msg.event.payload_field:
412 # Print the `fd` event payload field's value.
413 print(msg.event.payload_field['fd'])
414
415 Output example:
416
417 .. code-block:: text
418
419 14
420 15
421 16
422 19
423 30
424 31
425 33
426 42
427 0
428 1
429 2
430 3
431
432 .. _examples_tcmi_ev_time:
433
434 Get an event's time
435 ~~~~~~~~~~~~~~~~~~~
436 The time, or timestamp, of an event object belongs to its message as
437 a *default clock snapshot*.
438
439 An event's clock snapshot is a *snapshot* (an immutable value) of the
440 value of the event's stream's clock when the event occurred. As of
441 Babeltrace |~| |version|, a stream can only have one clock: its default
442 clock.
443
444 Use the :attr:`default_clock_snapshot` property of an event message
445 to get its default clock snapshot. A clock snapshot object offers,
446 amongst other things, the following properties:
447
448 :attr:`value` (:class:`int`)
449 Value of the clock snapshot in clock cycles.
450
451 A stream clock can have any frequency (Hz).
452
453 :attr:`ns_from_origin` (:class:`int`)
454 Number of nanoseconds from the stream clock's origin (often the Unix
455 epoch).
456
457 The following example prints, for each event, its name, its date/time,
458 and the difference, in seconds, since the previous event's time (if
459 any)::
460
461 import bt2
462 import sys
463 import datetime
464
465 # Create a trace collection message iterator from the first command-line
466 # argument.
467 msg_it = bt2.TraceCollectionMessageIterator(sys.argv[1])
468
469 # Last event's time (ns from origin).
470 last_event_ns_from_origin = None
471
472 # Iterate the trace messages.
473 for msg in msg_it:
474 # `bt2._EventMessageConst` is the Python type of an event message.
475 if type(msg) is bt2._EventMessageConst:
476 # Get event message's default clock snapshot's ns from origin
477 # value.
478 ns_from_origin = msg.default_clock_snapshot.ns_from_origin
479
480 # Compute the time difference since the last event message.
481 diff_s = 0
482
483 if last_event_ns_from_origin is not None:
484 diff_s = (ns_from_origin - last_event_ns_from_origin) / 1e9
485
486 # Create a `datetime.datetime` object from `ns_from_origin` for
487 # presentation. Note that such an object is less accurate than
488 # `ns_from_origin` as it holds microseconds, not nanoseconds.
489 dt = datetime.datetime.fromtimestamp(ns_from_origin / 1e9)
490
491 # Print line.
492 fmt = '{} (+{:.6f} s): {}'
493 print(fmt.format(dt, diff_s, msg.event.name))
494
495 # Update last event's time.
496 last_event_ns_from_origin = ns_from_origin
497
498 Run this example:
499
500 .. code-block:: text
501
502 $ python3 example.py /path/to/one/or/more/traces
503
504 Output example:
505
506 .. code-block:: text
507
508 2015-09-09 22:40:41.551451 (+0.000004 s): lttng_ust_statedump:end
509 2015-09-09 22:40:43.003397 (+1.451946 s): lttng_ust_dl:dlopen
510 2015-09-09 22:40:43.003412 (+0.000015 s): lttng_ust_dl:build_id
511 2015-09-09 22:40:43.003861 (+0.000449 s): lttng_ust_dl:dlopen
512 2015-09-09 22:40:43.003865 (+0.000004 s): lttng_ust_dl:build_id
513 2015-09-09 22:40:43.003879 (+0.000014 s): my_provider:my_first_tracepoint
514 2015-09-09 22:40:43.003895 (+0.000016 s): my_provider:my_first_tracepoint
515 2015-09-09 22:40:43.003898 (+0.000003 s): my_provider:my_other_tracepoint
516 2015-09-09 22:40:43.003922 (+0.000023 s): lttng_ust_dl:dlclose
517
518 Bonus: Print top 5 running processes using LTTng
519 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
520 As :ref:`examples_tcmi_ev_field` shows, a
521 :class:`bt2.TraceCollectionMessageIterator` can read
522 `LTTng <https://lttng.org/>`_ traces.
523
524 The following example is similar to :ref:`examples_tcmi_ev_time`: it
525 reads a whole LTTng Linux kernel trace, but instead of printing the time
526 difference for each event, it accumulates them to print the short names
527 of the top |~| 5 running processes on CPU |~| 0 during the whole trace.
528
529 .. code-block:: python
530
531 import bt2
532 import sys
533 import collections
534
535 # Create a trace collection message iterator from the first command-line
536 # argument.
537 msg_it = bt2.TraceCollectionMessageIterator(sys.argv[1])
538
539 # This counter dictionary will hold execution times:
540 #
541 # Task command name -> Total execution time (ns)
542 exec_times = collections.Counter()
543
544 # This holds the last `sched_switch` event time.
545 last_ns_from_origin = None
546
547 for msg in msg_it:
548 # `bt2._EventMessageConst` is the Python type of an event message.
549 # Only keep such messages.
550 if type(msg) is not bt2._EventMessageConst:
551 continue
552
553 # An event message holds a trace event.
554 event = msg.event
555
556 # Only check `sched_switch` events.
557 if event.name != 'sched_switch':
558 continue
559
560 # Keep only events which occurred on CPU 0.
561 if event['cpu_id'] != 0:
562 continue
563
564 # Get event message's default clock snapshot's ns from origin value.
565 ns_from_origin = msg.default_clock_snapshot.ns_from_origin
566
567 if last_ns_from_origin is None:
568 # We start here.
569 last_ns_from_origin = ns_from_origin
570
571 # Previous process's short name.
572 prev_comm = str(event['prev_comm'])
573
574 # Initialize an entry in our dictionary if not done yet.
575 if prev_comm not in exec_times:
576 exec_times[prev_comm] = 0
577
578 # Compute previous process's execution time.
579 diff_ns = ns_from_origin - last_ns_from_origin
580
581 # Update execution time of this command.
582 exec_times[prev_comm] += diff_ns
583
584 # Update last event's time.
585 last_ns_from_origin = ns_from_origin
586
587 # Print top 5.
588 for comm, ns in exec_times.most_common(5):
589 print('{:20}{} s'.format(comm, ns / 1e9))
590
591 Run this example:
592
593 .. code-block:: text
594
595 $ python3 example.py /path/to/lttng/trace
596
597 Output example:
598
599 .. code-block:: text
600
601 swapper/0 326.294314471 s
602 chromium 2.500456202 s
603 Xorg.bin 0.546656895 s
604 threaded-ml 0.545098185 s
605 pulseaudio 0.53677713 s
606
607 Note that ``swapper/0`` is the "idle" process of CPU |~| 0 on Linux;
608 since we weren't using the CPU that much when tracing, its first
609 position in the list makes sense.
610
611 Inspect event classes
612 ~~~~~~~~~~~~~~~~~~~~~
613 Each event stream is a *stream class* instance.
614
615 A stream class contains *event classes*. A stream class's event classes
616 describe all the possible events you can find in its instances. Stream
617 classes and event classes form the *metadata* of streams and events.
618
619 The following example shows how to list all the event classes of a
620 stream class. For each event class, the example also prints the names of
621 its payload field class's first-level members.
622
623 .. note::
624
625 As of Babeltrace |~| |version|, there's no way to access a stream class
626 without consuming at least one message for one of its instances
627 (streams).
628
629 A source component can add new event classes to existing stream
630 classes during the trace processing task. Therefore, this example
631 only lists the initial stream class's event classes.
632
633 .. code-block:: python
634
635 import bt2
636 import sys
637
638 # Create a trace collection message iterator from the first command-line
639 # argument.
640 msg_it = bt2.TraceCollectionMessageIterator(sys.argv[1])
641
642 # Get the message iterator's first stream beginning message.
643 for msg in msg_it:
644 # `bt2._StreamBeginningMessageConst` is the Python type of a stream
645 # beginning message.
646 if type(msg) is bt2._StreamBeginningMessageConst:
647 break
648
649 # A stream beginning message holds a stream.
650 stream = msg.stream
651
652 # Get the stream's class.
653 stream_class = stream.cls
654
655 # The stream class object offers a mapping interface (like a read-only
656 # `dict`), where keys are event class IDs and values are
657 # `bt2._EventClassConst` objects.
658 for event_class in stream_class.values():
659 print('{}:'.format(event_class.name))
660
661 # The `payload_field_class` property of an event class returns a
662 # `bt2._StructureFieldClassConst` object. This object offers a
663 # mapping interface, where keys are member names and values are
664 # `bt2._StructureFieldClassMemberConst` objects.
665 for member in event_class.payload_field_class.values():
666 fmt = ' {}: `{}.{}`'
667 print(fmt.format(member.name, bt2.__name__,
668 member.field_class.__class__.__name__))
669
670 Run this example:
671
672 .. code-block:: text
673
674 $ python3 example.py /path/to/trace
675
676 Output example:
677
678 .. code-block:: text
679
680 sched_migrate_task:
681 comm: `bt2._StringFieldClassConst`
682 tid: `bt2._SignedIntegerFieldClassConst`
683 prio: `bt2._SignedIntegerFieldClassConst`
684 orig_cpu: `bt2._SignedIntegerFieldClassConst`
685 dest_cpu: `bt2._SignedIntegerFieldClassConst`
686 sched_switch:
687 prev_comm: `bt2._StringFieldClassConst`
688 prev_tid: `bt2._SignedIntegerFieldClassConst`
689 prev_prio: `bt2._SignedIntegerFieldClassConst`
690 prev_state: `bt2._SignedIntegerFieldClassConst`
691 next_comm: `bt2._StringFieldClassConst`
692 next_tid: `bt2._SignedIntegerFieldClassConst`
693 next_prio: `bt2._SignedIntegerFieldClassConst`
694 sched_wakeup_new:
695 comm: `bt2._StringFieldClassConst`
696 tid: `bt2._SignedIntegerFieldClassConst`
697 prio: `bt2._SignedIntegerFieldClassConst`
698 target_cpu: `bt2._SignedIntegerFieldClassConst`
699
700 .. _examples_graph:
701
702 Build and run a trace processing graph
703 --------------------------------------
704 Internally, a :class:`bt2.TraceCollectionMessageIterator` object (see
705 :ref:`examples_tcmi`) builds a *trace processing graph*, just like the
706 :bt2man:`babeltrace2-convert(1)` CLI command, and then offers a
707 Python iterator interface on top of it.
708
709 See the :bt2man:`babeltrace2-intro(7)` manual page to learn more about
710 the Babeltrace |~| 2 project and its core concepts.
711
712 The following examples shows how to manually build and then run a trace
713 processing graph yourself (like the :bt2man:`babeltrace2-run(1)` CLI
714 command does). The general steps to do so are:
715
716 #. Create an empty graph.
717
718 #. Add components to the graph.
719
720 This process is also known as *instantiating a component class*
721 because the graph must first create the component from its class
722 before adding it.
723
724 A viable graph contains at least one source component and one sink
725 component.
726
727 #. Connect component ports.
728
729 On initialization, components add input and output ports, depending
730 on their type.
731
732 You can connect component output ports to input ports within a graph.
733
734 #. Run the graph.
735
736 This is a blocking operation which makes each sink component consume
737 some messages in a round robin fashion until there are no more.
738
739 .. code-block:: python
740
741 import bt2
742 import sys
743
744 # Create an empty graph.
745 graph = bt2.Graph()
746
747 # Add a `source.text.dmesg` component.
748 #
749 # graph.add_component() returns the created and added component.
750 #
751 # Such a component reads Linux kernel ring buffer messages (see
752 # `dmesg(1)`) from the standard input and creates corresponding event
753 # messages. See `babeltrace2-source.text.dmesg(7)`.
754 #
755 # `my source` is the unique name of this component within `graph`.
756 comp_cls = bt2.find_plugin('text').source_component_classes['dmesg']
757 src_comp = graph.add_component(comp_cls, 'my source')
758
759 # Add a `sink.text.pretty` component.
760 #
761 # Such a component pretty-prints event messages on the standard output
762 # (one message per line). See `babeltrace2-sink.text.pretty(7)`.
763 #
764 # The `babeltrace2 convert` CLI command uses a `sink.text.pretty`
765 # sink component by default.
766 comp_cls = bt2.find_plugin('text').sink_component_classes['pretty']
767 sink_comp = graph.add_component(comp_cls, 'my sink')
768
769 # Connect the `out` output port of the `source.text.dmesg` component
770 # to the `in` input port of the `sink.text.pretty` component.
771 graph.connect_ports(src_comp.output_ports['out'],
772 sink_comp.input_ports['in'])
773
774 # Run the trace processing graph.
775 graph.run()
776
777 Run this example:
778
779 .. code-block:: text
780
781 $ dmesg -t | python3 example.py
782
783 Output example:
784
785 .. code-block:: text
786
787 string: { str = "ata1.00: NCQ Send/Recv Log not supported" }
788 string: { str = "ata1.00: ACPI cmd ef/02:00:00:00:00:a0 (SET FEATURES) succeeded" }
789 string: { str = "ata1.00: ACPI cmd f5/00:00:00:00:00:a0 (SECURITY FREEZE LOCK) filtered out" }
790 string: { str = "ata1.00: ACPI cmd ef/10:03:00:00:00:a0 (SET FEATURES) filtered out" }
791 string: { str = "ata1.00: NCQ Send/Recv Log not supported" }
792 string: { str = "ata1.00: configured for UDMA/133" }
793 string: { str = "ata1.00: Enabling discard_zeroes_data" }
794 string: { str = "OOM killer enabled." }
795 string: { str = "Restarting tasks ... done." }
796 string: { str = "PM: suspend exit" }
797
798 Query a component class
799 -----------------------
800 Component classes, provided by plugins, can implement a method to
801 support *query operations*.
802
803 A query operation is similar to a function call: the caller makes a
804 request (a query) with parameters and the component class's query
805 method returns a result object.
806
807 The query operation feature exists so that you can benefit from a
808 component class's implementation to get information about a trace, a
809 stream, a distant server, and so on. For example, the
810 ``source.ctf.lttng-live`` component class (see
811 :bt2man:`babeltrace2-source.ctf.lttng-live(7)`) offers the ``sessions``
812 object to list the available
813 `LTTng live <https://lttng.org/docs/#doc-lttng-live>`_ tracing
814 session names and other properties.
815
816 The semantics of the query parameters and the returned object are
817 completely defined by the component class implementation: the library
818 and its Python bindings don't enforce or suggest any layout.
819 The best way to know which objects you can query from a component class,
820 what are the expected and optional parameters, and what the returned
821 object contains is to read this component class's documentation.
822
823 The following example queries the "standard" ``babeltrace.support-info``
824 query object (see
825 :bt2man:`babeltrace2-query-babeltrace.support-info(7)`) from the
826 ``source.ctf.fs`` component class
827 (see :bt2man:`babeltrace2-source.ctf.fs(7)`) and
828 pretty-prints the result. The ``babeltrace.support-info`` query object
829 indicates whether or not a given path locates a
830 :abbr:`CTF (Common Trace Format)` trace directory::
831
832 import bt2
833 import sys
834
835 # Get the `source.ctf.fs` component class from the `ctf` plugin.
836 comp_cls = bt2.find_plugin('ctf').source_component_classes['fs']
837
838 # The `babeltrace.support-info` query operation expects a `type`
839 # parameter (set to `directory` here) and an `input` parameter (the
840 # actual path or string to check, in this case the first command-line
841 # argument).
842 #
843 # See `babeltrace2-query-babeltrace.support-info(7)`.
844 params = {
845 'type': 'directory',
846 'input': sys.argv[1],
847 }
848
849 # Create a query executor.
850 #
851 # This is the environment in which query operations happens. The
852 # queried component class has access to this executor, for example to
853 # retrieve the query operation's logging level.
854 query_exec = bt2.QueryExecutor(comp_cls, 'babeltrace.support-info',
855 params)
856
857 # Query the component class through the query executor.
858 #
859 # This method returns the result.
860 result = query_exec.query()
861
862 # Print the result.
863 print(result)
864
865 As you can see, no trace processing graph is involved (like in
866 :ref:`examples_tcmi` and :ref:`examples_graph`): a query operation
867 is *not* a sequential trace processing task, but a simple, atomic
868 procedure call.
869
870 Run this example:
871
872 .. code-block:: text
873
874 $ python3 example.py /path/to/ctf/trace
875
876 Output example:
877
878 .. code-block:: text
879
880 {'group': '21c63a42-40bc-4c08-9761-3815ae01f43d', 'weight': 0.75}
881
882 This result indicates that the component class is 75 |~| % confident that
883 :file:`/path/to/ctf/trace` is a CTF trace directory path. It also shows
884 that this specific CTF trace belongs to the
885 ``21c63a42-40bc-4c08-9761-3815ae01f43d`` group; a single component can
886 handle multiple traces which belong to the same group.
887
888 Let's try the sample example with a path that doesn't locate a CTF
889 trace:
890
891 .. code-block:: text
892
893 $ python3 example.py /etc
894
895 Output:
896
897 .. code-block:: text
898
899 {'weight': 0.0}
900
901 As expected, the zero weight indicates that ``/etc`` isn't a CTF trace
902 directory path.
This page took 0.047264 seconds and 4 git commands to generate.