7 This section presents a few short and straightforward examples
8 of Babeltrace legacy Python bindings usage.
10 The examples are divided into two categories: those which demonstrate
11 the :ref:`reader API <reader-api>`, and those which demonstrate
12 the :ref:`CTF writer API <ctf-writer-api>`.
15 .. _reader-api-examples:
20 The :ref:`reader API <reader-api>` includes everything needed to open
21 traces and iterate on events in order.
24 Open one trace and print all event names
25 ----------------------------------------
27 This example shows how to open a single CTF trace, iterate on all the
28 events, and print their names.
30 .. code-block:: python
32 import babeltrace.reader
36 # get the trace path from the first command line argument
37 trace_path = sys.argv[1]
39 trace_collection = babeltrace.reader.TraceCollection()
41 trace_collection.add_trace(trace_path, 'ctf')
43 for event in trace_collection.events:
47 Open multiple traces and print all event field names
48 ----------------------------------------------------
50 This example opens multiple CTF traces (their paths are provided as
51 command line arguments), iterates on all their correlated events in
52 order, and prints a list of their field names.
54 .. code-block:: python
56 import babeltrace.reader
60 trace_collection = babeltrace.reader.TraceCollection()
62 for path in sys.argv[1:]:
63 trace_collection.add_trace(path, 'ctf')
65 for event in trace_collection.events:
66 print(', '.join(event.keys()))
69 Print a specific event field
70 ----------------------------
72 Reading the field value of an :class:`babeltrace.reader.Event` object
73 is done by using its :class:`dict`-like interface:
75 .. code-block:: python
77 field_value = event['field_name']
79 As such, you can use Python's ``in`` keyword to verify if a given
80 event contains a given field name:
82 .. code-block:: python
84 if 'field_name' in event:
87 The following example iterates on the events of a trace, and prints the
88 value of the ``fd`` field if it's available.
90 .. code-block:: python
92 import babeltrace.reader
95 # get the trace path from the first command line argument
96 trace_path = sys.argv[1]
98 trace_collection = babeltrace.reader.TraceCollection()
100 trace_collection.add_trace(trace_path, 'ctf')
102 for event in trace_collection.events:
106 Beware that different fields of the same event may share the same name
107 if they are in different scopes. In this case, the :class:`dict`-like
108 interface prioritizes event payload fields before event context fields,
109 event context fields before stream event context fields, and so on
110 (see :class:`babeltrace.reader.Event` for this exact list of
111 priorities). It is possible to get the value of an event's field
112 within a specific scope using
113 :meth:`babeltrace.reader.Event.field_with_scope`:
115 .. code-block:: python
117 import babeltrace.reader
118 import babeltrace.common
122 field_value = event.field_with_scope('field_name',
123 babeltrace.common.CTFScope.EVENT_CONTEXT)
126 Bonus: top 5 running processes using LTTng
127 ------------------------------------------
129 Since `LTTng <http://lttng.org/>`_ produces CTF traces, the
130 Babeltrace Python binding can read LTTng traces.
132 This somewhat more complex example reads a whole LTTng Linux kernel
133 trace, and outputs the short names of the top 5 running processes on
134 CPU 0 during the whole trace.
136 .. code-block:: python
138 from collections import Counter
139 import babeltrace.reader
143 # a trace collection holds one or more traces
144 col = babeltrace.reader.TraceCollection()
146 # add the trace provided by the user (first command line argument)
147 # (LTTng traces always have the 'ctf' format)
148 if col.add_trace(sys.argv[1], 'ctf') is None:
149 raise RuntimeError('Cannot add trace')
151 # this counter dict will hold execution times:
153 # task command name -> total execution time (ns)
154 exec_times = Counter()
156 # this holds the last `sched_switch` timestamp
160 for event in col.events:
161 # keep only `sched_switch` events
162 if event.name != 'sched_switch':
165 # keep only events which happened on CPU 0
166 if event['cpu_id'] != 0:
170 cur_ts = event.timestamp
176 # previous task command (short) name
177 prev_comm = event['prev_comm']
179 # initialize entry in our dict if not yet done
180 if prev_comm not in exec_times:
181 exec_times[prev_comm] = 0
183 # compute previous command execution time
184 diff = cur_ts - last_ts
186 # update execution time of this command
187 exec_times[prev_comm] += diff
189 # update last timestamp
193 for name, ns in exec_times.most_common(5):
195 print('{:20}{} s'.format(name, s))
198 Inspect event declarations and their field declarations
199 -------------------------------------------------------
201 When :meth:`babeltrace.reader.TraceCollection.add_trace` is called
202 and a trace is successfully opened and added, a corresponding
203 :class:`babeltrace.reader.TraceHandle` object for this trace is
204 returned. It is then possible to iterate on the event declarations of
205 this trace handle using :attr:`babeltrace.reader.TraceHandle.events`.
206 Each generated :class:`babeltrace.reader.EventDeclaration` object
207 contains common properties for this type of event, including its
208 field declarations. This is useful for inspecting the available
209 events of a trace, and their "signature" in terms of fields, before
210 iterating its actual events.
212 This example adds a trace to a trace collection, and uses the returned
213 trace handle to iterate on its event declarations. The goal here is to
214 make sure the ``sched_switch`` event exists, and that it contains
215 at least the following fields:
217 * ``prev_comm``, which should be an array of 8-bit integers
218 * ``prev_tid``, which should be an integer
220 .. code-block:: python
222 import babeltrace.reader as btr
226 def validate_sched_switch_fields(event_decl):
227 found_prev_comm = False
228 found_prev_tid = False
230 for field_decl in event_decl.fields:
231 if field_decl.name == 'prev_comm':
232 if isinstance(field_decl, btr.ArrayFieldDeclaration):
233 elem_decl = field_decl.element_declaration
235 if isinstance(elem_decl, btr.IntegerFieldDeclaration):
236 if elem_decl.size == 8:
237 found_prev_comm = True
238 elif field_decl.name == 'prev_tid':
239 if isinstance(field_decl, btr.IntegerFieldDeclaration):
240 found_prev_tid = True
242 return found_prev_comm and found_prev_tid
245 # get the trace path from the first command line argument
246 trace_path = sys.argv[1]
248 trace_collection = btr.TraceCollection()
249 trace_handle = trace_collection.add_trace(trace_path, 'ctf')
250 sched_switch_found = False
252 for event_decl in trace_handle.events:
253 if event_decl.name == 'sched_switch':
254 if validate_sched_switch_fields(event_decl):
255 sched_switch_found = True
258 print('trace path: {}'.format(trace_handle.path))
260 if sched_switch_found:
261 print('found sched_switch!')
263 print('could not find sched_switch')
266 .. _ctf-writer-api-examples:
268 CTF writer API examples
269 =======================
271 The :ref:`CTF writer API <ctf-writer-api>` is a set of classes which
272 allows a Python script to write complete
273 `CTF <http://www.efficios.com/ctf>`_ (Common Trace Format) traces.
276 One trace, one stream, one event, one field
277 -------------------------------------------
279 This is the most simple example of using the CTF writer API. It creates
280 one writer (responsible for writing one trace), then uses it to create
281 one stream. One event with a single field is appended to this single
282 stream, and everything is flushed.
284 The trace is written in a temporary directory (its path is printed
285 at the beginning of the script).
287 .. code-block:: python
289 import babeltrace.writer as btw
293 # temporary directory holding the CTF trace
294 trace_path = tempfile.mkdtemp()
296 print('trace path: {}'.format(trace_path))
299 writer = btw.Writer(trace_path)
301 # create one default clock and register it to the writer
302 clock = btw.Clock('my_clock')
303 clock.description = 'this is my clock'
304 writer.add_clock(clock)
306 # create one default stream class and assign our clock to it
307 stream_class = btw.StreamClass('my_stream')
308 stream_class.clock = clock
310 # create one default event class
311 event_class = btw.EventClass('my_event')
313 # create one 32-bit signed integer field
314 int32_field_decl = btw.IntegerFieldDeclaration(32)
315 int32_field_decl.signed = True
317 # add this field declaration to our event class
318 event_class.add_field(int32_field_decl, 'my_field')
320 # register our event class to our stream class
321 stream_class.add_event_class(event_class)
323 # create our single event, based on our event class
324 event = btw.Event(event_class)
326 # assign an integer value to our single field
327 event.payload('my_field').value = -23
329 # create our single stream
330 stream = writer.create_stream(stream_class)
332 # append our single event to our single stream
333 stream.append_event(event)
342 This example writes a few events with basic CTF fields: integers,
343 floating point numbers, enumerations and strings.
345 The trace is written in a temporary directory (its path is printed
346 at the beginning of the script).
348 .. code-block:: python
350 import babeltrace.writer as btw
351 import babeltrace.common
356 trace_path = tempfile.mkdtemp()
358 print('trace path: {}'.format(trace_path))
361 writer = btw.Writer(trace_path)
363 clock = btw.Clock('my_clock')
364 clock.description = 'this is my clock'
365 writer.add_clock(clock)
367 stream_class = btw.StreamClass('my_stream')
368 stream_class.clock = clock
370 event_class = btw.EventClass('my_event')
372 # 32-bit signed integer field declaration
373 int32_field_decl = btw.IntegerFieldDeclaration(32)
374 int32_field_decl.signed = True
375 int32_field_decl.base = btw.IntegerBase.HEX
377 # 5-bit unsigned integer field declaration
378 uint5_field_decl = btw.IntegerFieldDeclaration(5)
379 uint5_field_decl.signed = False
381 # IEEE 754 single precision floating point number field declaration
382 float_field_decl = btw.FloatingPointFieldDeclaration()
383 float_field_decl.exponent_digits = btw.FloatingPointFieldDeclaration.FLT_EXP_DIG
384 float_field_decl.mantissa_digits = btw.FloatingPointFieldDeclaration.FLT_MANT_DIG
386 # enumeration field declaration (based on the 5-bit unsigned integer above)
387 enum_field_decl = btw.EnumerationFieldDeclaration(uint5_field_decl)
388 enum_field_decl.add_mapping('DAZED', 3, 11)
389 enum_field_decl.add_mapping('AND', 13, 13)
390 enum_field_decl.add_mapping('CONFUSED', 17, 30)
392 # string field declaration
393 string_field_decl = btw.StringFieldDeclaration()
394 string_field_decl.encoding = babeltrace.common.CTFStringEncoding.UTF8
396 event_class.add_field(int32_field_decl, 'my_int32_field')
397 event_class.add_field(uint5_field_decl, 'my_uint5_field')
398 event_class.add_field(float_field_decl, 'my_float_field')
399 event_class.add_field(enum_field_decl, 'my_enum_field')
400 event_class.add_field(int32_field_decl, 'another_int32_field')
401 event_class.add_field(string_field_decl, 'my_string_field')
403 stream_class.add_event_class(event_class)
405 stream = writer.create_stream(stream_class)
407 # create and append first event
408 event = btw.Event(event_class)
409 event.payload('my_int32_field').value = 0xbeef
410 event.payload('my_uint5_field').value = 17
411 event.payload('my_float_field').value = -math.pi
412 event.payload('my_enum_field').value = 8 # label: 'DAZED'
413 event.payload('another_int32_field').value = 0x20141210
414 event.payload('my_string_field').value = 'Hello, World!'
415 stream.append_event(event)
417 # create and append second event
418 event = btw.Event(event_class)
419 event.payload('my_int32_field').value = 0x12345678
420 event.payload('my_uint5_field').value = 31
421 event.payload('my_float_field').value = math.e
422 event.payload('my_enum_field').value = 28 # label: 'CONFUSED'
423 event.payload('another_int32_field').value = -1
424 event.payload('my_string_field').value = trace_path
425 stream.append_event(event)
430 Static array and sequence fields
431 --------------------------------
433 This example demonstrates how to write static array and sequence
434 fields. A static array has a fixed length, whereas a sequence reads
435 its length dynamically from another (integer) field.
437 In this example, an event is appended to a single stream, in which
438 three fields are present:
440 * ``seqlen``, the dynamic length of the sequence ``seq`` (set to the
441 number of command line arguments)
442 * ``array``, a static array of 23 16-bit unsigned integers
443 * ``seq``, a sequence of ``seqlen`` strings, where the strings are
444 the command line arguments
446 The trace is written in a temporary directory (its path is printed
447 at the beginning of the script).
449 .. code-block:: python
451 import babeltrace.writer as btw
452 import babeltrace.common
457 trace_path = tempfile.mkdtemp()
459 print('trace path: {}'.format(trace_path))
462 writer = btw.Writer(trace_path)
464 clock = btw.Clock('my_clock')
465 clock.description = 'this is my clock'
466 writer.add_clock(clock)
468 stream_class = btw.StreamClass('my_stream')
469 stream_class.clock = clock
471 event_class = btw.EventClass('my_event')
473 # 16-bit unsigned integer field declaration
474 uint16_field_decl = btw.IntegerFieldDeclaration(16)
475 uint16_field_decl.signed = False
477 # array field declaration (23 16-bit unsigned integers)
478 array_field_decl = btw.ArrayFieldDeclaration(uint16_field_decl, 23)
480 # string field declaration
481 string_field_decl = btw.StringFieldDeclaration()
482 string_field_decl.encoding = babeltrace.common.CTFStringEncoding.UTF8
484 # sequence field declaration of strings (length will be the `seqlen` field)
485 seq_field_decl = btw.SequenceFieldDeclaration(string_field_decl, 'seqlen')
487 event_class.add_field(uint16_field_decl, 'seqlen')
488 event_class.add_field(array_field_decl, 'array')
489 event_class.add_field(seq_field_decl, 'seq')
491 stream_class.add_event_class(event_class)
493 stream = writer.create_stream(stream_class)
496 event = btw.Event(event_class)
498 # set sequence length field
499 event.payload('seqlen').value = len(sys.argv)
502 array_field = event.payload('array')
504 # populate array field
505 for i in range(array_field_decl.length):
506 array_field.field(i).value = i * i
509 seq_field = event.payload('seq')
511 # assign sequence field's length field
512 seq_field.length = event.payload('seqlen')
514 # populate sequence field
515 for i in range(seq_field.length.value):
516 seq_field.field(i).value = sys.argv[i]
519 stream.append_event(event)
527 A CTF structure is an ordered map of field names to actual fields, just
528 like C structures. In fact, an event's payload is a structure field,
529 so structure fields may contain other structure fields, and so on.
531 This examples shows how to create a structure field from a structure
532 field declaration, populate it, and write an event containing it as
535 The trace is written in a temporary directory (its path is printed
536 at the beginning of the script).
538 .. code-block:: python
540 import babeltrace.writer as btw
541 import babeltrace.common
545 trace_path = tempfile.mkdtemp()
547 print('trace path: {}'.format(trace_path))
550 writer = btw.Writer(trace_path)
552 clock = btw.Clock('my_clock')
553 clock.description = 'this is my clock'
554 writer.add_clock(clock)
556 stream_class = btw.StreamClass('my_stream')
557 stream_class.clock = clock
559 event_class = btw.EventClass('my_event')
561 # 32-bit signed integer field declaration
562 int32_field_decl = btw.IntegerFieldDeclaration(32)
563 int32_field_decl.signed = True
565 # string field declaration
566 string_field_decl = btw.StringFieldDeclaration()
567 string_field_decl.encoding = babeltrace.common.CTFStringEncoding.UTF8
569 # structure field declaration
570 struct_field_decl = btw.StructureFieldDeclaration()
572 # add field declarations to our structure field declaration
573 struct_field_decl.add_field(int32_field_decl, 'field_one')
574 struct_field_decl.add_field(string_field_decl, 'field_two')
575 struct_field_decl.add_field(int32_field_decl, 'field_three')
577 event_class.add_field(struct_field_decl, 'my_struct')
578 event_class.add_field(string_field_decl, 'my_string')
580 stream_class.add_event_class(event_class)
582 stream = writer.create_stream(stream_class)
585 event = btw.Event(event_class)
587 # get event's structure field
588 struct_field = event.payload('my_struct')
590 # populate this structure field
591 struct_field.field('field_one').value = 23
592 struct_field.field('field_two').value = 'Achilles Last Stand'
593 struct_field.field('field_three').value = -1534
595 # set event's string field
596 event.payload('my_string').value = 'Tangerine'
599 stream.append_event(event)
607 The CTF variant is the most versatile field type. It acts as a
608 placeholder for any other type. Which type is selected depends on the
609 current value of an outer enumeration field, known as a *tag* from the
610 variant's point of view.
612 Variants are typical constructs in communication protocols with
613 dynamic types. For example, `BSON <http://bsonspec.org/spec.html>`_,
614 the protocol used by `MongoDB <http://www.mongodb.org/>`_, has specific
615 numeric IDs for each element type.
617 This examples shows how to create a CTF variant field. The tag, an
618 enumeration field, must also be created and associated with the
619 variant. In this case, the tag selects between three types: a
620 32-bit signed integer, a string, or a floating point number.
622 The trace is written in a temporary directory (its path is printed
623 at the beginning of the script).
625 .. code-block:: python
627 import babeltrace.writer as btw
628 import babeltrace.common
632 trace_path = tempfile.mkdtemp()
634 print('trace path: {}'.format(trace_path))
637 writer = btw.Writer(trace_path)
639 clock = btw.Clock('my_clock')
640 clock.description = 'this is my clock'
641 writer.add_clock(clock)
643 stream_class = btw.StreamClass('my_stream')
644 stream_class.clock = clock
646 event_class = btw.EventClass('my_event')
648 # 32-bit signed integer field declaration
649 int32_field_decl = btw.IntegerFieldDeclaration(32)
650 int32_field_decl.signed = True
652 # string field declaration
653 string_field_decl = btw.StringFieldDeclaration()
654 string_field_decl.encoding = babeltrace.common.CTFStringEncoding.UTF8
656 # IEEE 754 single precision floating point number field declaration
657 float_field_decl = btw.FloatingPointFieldDeclaration()
658 float_field_decl.exponent_digits = btw.FloatingPointFieldDeclaration.FLT_EXP_DIG
659 float_field_decl.mantissa_digits = btw.FloatingPointFieldDeclaration.FLT_MANT_DIG
661 # enumeration field declaration (variant's tag)
662 enum_field_decl = btw.EnumerationFieldDeclaration(int32_field_decl)
663 enum_field_decl.add_mapping('INT', 0, 0)
664 enum_field_decl.add_mapping('STRING', 1, 1)
665 enum_field_decl.add_mapping('FLOAT', 2, 2)
667 # variant field declaration (variant's tag field will be named `vartag`)
668 variant_field_decl = btw.VariantFieldDeclaration(enum_field_decl, 'vartag')
670 # register selectable fields to variant
671 variant_field_decl.add_field(int32_field_decl, 'INT')
672 variant_field_decl.add_field(string_field_decl, 'STRING')
673 variant_field_decl.add_field(float_field_decl, 'FLOAT')
675 event_class.add_field(enum_field_decl, 'vartag')
676 event_class.add_field(variant_field_decl, 'var')
678 stream_class.add_event_class(event_class)
680 stream = writer.create_stream(stream_class)
682 # first event: integer is selected
683 event = btw.Event(event_class)
684 tag_field = event.payload('vartag')
686 event.payload('var').field(tag_field).value = 23
687 stream.append_event(event)
689 # second event: string is selected
690 event = btw.Event(event_class)
691 tag_field = event.payload('vartag')
693 event.payload('var').field(tag_field).value = 'The Battle of Evermore'
694 stream.append_event(event)
696 # third event: floating point number is selected
697 event = btw.Event(event_class)
698 tag_field = event.payload('vartag')
700 event.payload('var').field(tag_field).value = -15.34
701 stream.append_event(event)