Python: add Sphinx doc project
[babeltrace.git] / doc / bindings / python / source / examples.rst
1 .. _examples:
2
3 ********
4 Examples
5 ********
6
7 This section presents a few short and straightforward examples
8 of Babeltrace Python bindings usage.
9
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>`.
13
14
15 .. _reader-api-examples:
16
17 Reader API examples
18 ===================
19
20 The :ref:`reader API <reader-api>` includes everything needed to open
21 traces and iterate on events in order.
22
23
24 Open one trace and print all event names
25 ----------------------------------------
26
27 This example shows how to open a single CTF trace, iterate on all the
28 events, and print their names.
29
30 .. code-block:: python
31
32 import babeltrace.reader
33 import sys
34
35
36 # get the trace path from the first command line argument
37 trace_path = sys.argv[1]
38
39 trace_collection = babeltrace.reader.TraceCollection()
40
41 trace_collection.add_trace(trace_path, 'ctf')
42
43 for event in trace_collection.events:
44 print(event.name)
45
46
47 Open multiple traces and print all event field names
48 ----------------------------------------------------
49
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.
53
54 .. code-block:: python
55
56 import babeltrace.reader
57 import sys
58
59
60 trace_collection = babeltrace.reader.TraceCollection()
61
62 for path in sys.argv[1:]:
63 trace_collection.add_trace(path, 'ctf')
64
65 for event in trace_collection.events:
66 print(', '.join(event.keys()))
67
68
69 Print a specific event field
70 ----------------------------
71
72 Reading the field value of an :class:`babeltrace.reader.Event` object
73 is done by using its :class:`dict`-like interface:
74
75 .. code-block:: python
76
77 field_value = event['field_name']
78
79 As such, you can use Python's ``in`` keyword to verify if a given
80 event contains a given field name:
81
82 .. code-block:: python
83
84 if 'field_name' in event:
85 # ...
86
87 The following example iterates on the events of a trace, and prints the
88 value of the ``fd`` field if it's available.
89
90 .. code-block:: python
91
92 import babeltrace.reader
93 import sys
94
95 # get the trace path from the first command line argument
96 trace_path = sys.argv[1]
97
98 trace_collection = babeltrace.reader.TraceCollection()
99
100 trace_collection.add_trace(trace_path, 'ctf')
101
102 for event in trace_collection.events:
103 if 'fd' in event:
104 print(event['fd'])
105
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`:
114
115 .. code-block:: python
116
117 import babeltrace.reader
118 import babeltrace.common
119
120 # ...
121
122 field_value = event.field_with_scope('field_name',
123 babeltrace.common.CTFScope.EVENT_CONTEXT)
124
125
126 Bonus: top 5 running processes using LTTng
127 ------------------------------------------
128
129 Since `LTTng <http://lttng.org/>`_ produces CTF traces, the
130 Babeltrace Python binding can read LTTng traces.
131
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.
135
136 .. code-block:: python
137
138 from collections import Counter
139 import babeltrace.reader
140 import sys
141
142
143 # a trace collection holds one or more traces
144 col = babeltrace.reader.TraceCollection()
145
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')
150
151 # this counter dict will hold execution times:
152 #
153 # task command name -> total execution time (ns)
154 exec_times = Counter()
155
156 # this holds the last `sched_switch` timestamp
157 last_ts = None
158
159 # iterate on events
160 for event in col.events:
161 # keep only `sched_switch` events
162 if event.name != 'sched_switch':
163 continue
164
165 # keep only events which happened on CPU 0
166 if event['cpu_id'] != 0:
167 continue
168
169 # event timestamp
170 cur_ts = event.timestamp
171
172 if last_ts is None:
173 # we start here
174 last_ts = cur_ts
175
176 # previous task command (short) name
177 prev_comm = event['prev_comm']
178
179 # initialize entry in our dict if not yet done
180 if prev_comm not in exec_times:
181 exec_times[prev_comm] = 0
182
183 # compute previous command execution time
184 diff = cur_ts - last_ts
185
186 # update execution time of this command
187 exec_times[prev_comm] += diff
188
189 # update last timestamp
190 last_ts = cur_ts
191
192 # print top 5
193 for name, ns in exec_times.most_common(5):
194 s = ns / 1000000000
195 print('{:20}{} s'.format(name, s))
196
197
198 Inspect event declarations and their field declarations
199 -------------------------------------------------------
200
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.
211
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:
216
217 * ``prev_comm``, which should be an array of 8-bit integers
218 * ``prev_tid``, which should be an integer
219
220 .. code-block:: python
221
222 import babeltrace.reader as btr
223 import sys
224
225
226 def validate_sched_switch_fields(event_decl):
227 found_prev_comm = False
228 found_prev_tid = False
229
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
234
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
241
242 return found_prev_comm and found_prev_tid
243
244
245 # get the trace path from the first command line argument
246 trace_path = sys.argv[1]
247
248 trace_collection = btr.TraceCollection()
249 trace_handle = trace_collection.add_trace(trace_path, 'ctf')
250 sched_switch_found = False
251
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
256 break
257
258 print('trace path: {}'.format(trace_handle.path))
259
260 if sched_switch_found:
261 print('found sched_switch!')
262 else:
263 print('could not find sched_switch')
264
265
266 .. _ctf-writer-api-examples:
267
268 CTF writer API examples
269 =======================
270
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.
274
275
276 One trace, one stream, one event, one field
277 -------------------------------------------
278
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.
283
284 The trace is written in a temporary directory (its path is printed
285 at the beginning of the script).
286
287 .. code-block:: python
288
289 import babeltrace.writer as btw
290 import tempfile
291
292
293 # temporary directory holding the CTF trace
294 trace_path = tempfile.mkdtemp()
295
296 print('trace path: {}'.format(trace_path))
297
298 # our writer
299 writer = btw.Writer(trace_path)
300
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)
305
306 # create one default stream class and assign our clock to it
307 stream_class = btw.StreamClass('my_stream')
308 stream_class.clock = clock
309
310 # create one default event class
311 event_class = btw.EventClass('my_event')
312
313 # create one 32-bit signed integer field
314 int32_field_decl = btw.IntegerFieldDeclaration(32)
315 int32_field_decl.signed = True
316
317 # add this field declaration to our event class
318 event_class.add_field(int32_field_decl, 'my_field')
319
320 # register our event class to our stream class
321 stream_class.add_event_class(event_class)
322
323 # create our single event, based on our event class
324 event = btw.Event(event_class)
325
326 # assign an integer value to our single field
327 event.payload('my_field').value = -23
328
329 # create our single stream
330 stream = writer.create_stream(stream_class)
331
332 # append our single event to our single stream
333 stream.append_event(event)
334
335 # flush the stream
336 stream.flush()
337
338
339 Basic CTF fields
340 ----------------
341
342 This example writes a few events with basic CTF fields: integers,
343 floating point numbers, enumerations and strings.
344
345 The trace is written in a temporary directory (its path is printed
346 at the beginning of the script).
347
348 .. code-block:: python
349
350 import babeltrace.writer as btw
351 import babeltrace.common
352 import tempfile
353 import math
354
355
356 trace_path = tempfile.mkdtemp()
357
358 print('trace path: {}'.format(trace_path))
359
360
361 writer = btw.Writer(trace_path)
362
363 clock = btw.Clock('my_clock')
364 clock.description = 'this is my clock'
365 writer.add_clock(clock)
366
367 stream_class = btw.StreamClass('my_stream')
368 stream_class.clock = clock
369
370 event_class = btw.EventClass('my_event')
371
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
376
377 # 5-bit unsigned integer field declaration
378 uint5_field_decl = btw.IntegerFieldDeclaration(5)
379 uint5_field_decl.signed = False
380
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
385
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)
391
392 # string field declaration
393 string_field_decl = btw.StringFieldDeclaration()
394 string_field_decl.encoding = babeltrace.common.CTFStringEncoding.UTF8
395
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')
402
403 stream_class.add_event_class(event_class)
404
405 stream = writer.create_stream(stream_class)
406
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)
416
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)
426
427 stream.flush()
428
429
430 Static array and sequence fields
431 --------------------------------
432
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.
436
437 In this example, an event is appended to a single stream, in which
438 three fields are present:
439
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
445
446 The trace is written in a temporary directory (its path is printed
447 at the beginning of the script).
448
449 .. code-block:: python
450
451 import babeltrace.writer as btw
452 import babeltrace.common
453 import tempfile
454 import sys
455
456
457 trace_path = tempfile.mkdtemp()
458
459 print('trace path: {}'.format(trace_path))
460
461
462 writer = btw.Writer(trace_path)
463
464 clock = btw.Clock('my_clock')
465 clock.description = 'this is my clock'
466 writer.add_clock(clock)
467
468 stream_class = btw.StreamClass('my_stream')
469 stream_class.clock = clock
470
471 event_class = btw.EventClass('my_event')
472
473 # 16-bit unsigned integer field declaration
474 uint16_field_decl = btw.IntegerFieldDeclaration(16)
475 uint16_field_decl.signed = False
476
477 # array field declaration (23 16-bit unsigned integers)
478 array_field_decl = btw.ArrayFieldDeclaration(uint16_field_decl, 23)
479
480 # string field declaration
481 string_field_decl = btw.StringFieldDeclaration()
482 string_field_decl.encoding = babeltrace.common.CTFStringEncoding.UTF8
483
484 # sequence field declaration of strings (length will be the `seqlen` field)
485 seq_field_decl = btw.SequenceFieldDeclaration(string_field_decl, 'seqlen')
486
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')
490
491 stream_class.add_event_class(event_class)
492
493 stream = writer.create_stream(stream_class)
494
495 # create event
496 event = btw.Event(event_class)
497
498 # set sequence length field
499 event.payload('seqlen').value = len(sys.argv)
500
501 # get array field
502 array_field = event.payload('array')
503
504 # populate array field
505 for i in range(array_field_decl.length):
506 array_field.field(i).value = i * i
507
508 # get sequence field
509 seq_field = event.payload('seq')
510
511 # assign sequence field's length field
512 seq_field.length = event.payload('seqlen')
513
514 # populate sequence field
515 for i in range(seq_field.length.value):
516 seq_field.field(i).value = sys.argv[i]
517
518 # append event
519 stream.append_event(event)
520
521 stream.flush()
522
523
524 Structure fields
525 ----------------
526
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.
530
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
533 a payload field.
534
535 The trace is written in a temporary directory (its path is printed
536 at the beginning of the script).
537
538 .. code-block:: python
539
540 import babeltrace.writer as btw
541 import babeltrace.common
542 import tempfile
543
544
545 trace_path = tempfile.mkdtemp()
546
547 print('trace path: {}'.format(trace_path))
548
549
550 writer = btw.Writer(trace_path)
551
552 clock = btw.Clock('my_clock')
553 clock.description = 'this is my clock'
554 writer.add_clock(clock)
555
556 stream_class = btw.StreamClass('my_stream')
557 stream_class.clock = clock
558
559 event_class = btw.EventClass('my_event')
560
561 # 32-bit signed integer field declaration
562 int32_field_decl = btw.IntegerFieldDeclaration(32)
563 int32_field_decl.signed = True
564
565 # string field declaration
566 string_field_decl = btw.StringFieldDeclaration()
567 string_field_decl.encoding = babeltrace.common.CTFStringEncoding.UTF8
568
569 # structure field declaration
570 struct_field_decl = btw.StructureFieldDeclaration()
571
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')
576
577 event_class.add_field(struct_field_decl, 'my_struct')
578 event_class.add_field(string_field_decl, 'my_string')
579
580 stream_class.add_event_class(event_class)
581
582 stream = writer.create_stream(stream_class)
583
584 # create event
585 event = btw.Event(event_class)
586
587 # get event's structure field
588 struct_field = event.payload('my_struct')
589
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
594
595 # set event's string field
596 event.payload('my_string').value = 'Tangerine'
597
598 # append event
599 stream.append_event(event)
600
601 stream.flush()
602
603
604 Variant fields
605 --------------
606
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.
611
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.
616
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.
621
622 The trace is written in a temporary directory (its path is printed
623 at the beginning of the script).
624
625 .. code-block:: python
626
627 import babeltrace.writer as btw
628 import babeltrace.common
629 import tempfile
630
631
632 trace_path = tempfile.mkdtemp()
633
634 print('trace path: {}'.format(trace_path))
635
636
637 writer = btw.Writer(trace_path)
638
639 clock = btw.Clock('my_clock')
640 clock.description = 'this is my clock'
641 writer.add_clock(clock)
642
643 stream_class = btw.StreamClass('my_stream')
644 stream_class.clock = clock
645
646 event_class = btw.EventClass('my_event')
647
648 # 32-bit signed integer field declaration
649 int32_field_decl = btw.IntegerFieldDeclaration(32)
650 int32_field_decl.signed = True
651
652 # string field declaration
653 string_field_decl = btw.StringFieldDeclaration()
654 string_field_decl.encoding = babeltrace.common.CTFStringEncoding.UTF8
655
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
660
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)
666
667 # variant field declaration (variant's tag field will be named `vartag`)
668 variant_field_decl = btw.VariantFieldDeclaration(enum_field_decl, 'vartag')
669
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')
674
675 event_class.add_field(enum_field_decl, 'vartag')
676 event_class.add_field(variant_field_decl, 'var')
677
678 stream_class.add_event_class(event_class)
679
680 stream = writer.create_stream(stream_class)
681
682 # first event: integer is selected
683 event = btw.Event(event_class)
684 tag_field = event.payload('vartag')
685 tag_field.value = 0
686 event.payload('var').field(tag_field).value = 23
687 stream.append_event(event)
688
689 # second event: string is selected
690 event = btw.Event(event_class)
691 tag_field = event.payload('vartag')
692 tag_field.value = 1
693 event.payload('var').field(tag_field).value = 'The Battle of Evermore'
694 stream.append_event(event)
695
696 # third event: floating point number is selected
697 event = btw.Event(event_class)
698 tag_field = event.payload('vartag')
699 tag_field.value = 2
700 event.payload('var').field(tag_field).value = -15.34
701 stream.append_event(event)
702
703 stream.flush()
This page took 0.043898 seconds and 4 git commands to generate.