X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=blobdiff_plain;f=doc%2Fbindings%2Fpython%2Fsource%2Fexamples.rst;fp=doc%2Fbindings%2Fpython%2Fsource%2Fexamples.rst;h=0000000000000000000000000000000000000000;hp=317574762dd1160077d4157c54e414b1edd7e45d;hb=48ba910c442105da68c0f9bb703213517409f863;hpb=5cea295bfb45e7e7b495a5d9812b9a0522c3f743 diff --git a/doc/bindings/python/source/examples.rst b/doc/bindings/python/source/examples.rst deleted file mode 100644 index 31757476..00000000 --- a/doc/bindings/python/source/examples.rst +++ /dev/null @@ -1,703 +0,0 @@ -.. _examples: - -******** -Examples -******** - -This section presents a few short and straightforward examples -of Babeltrace legacy Python bindings usage. - -The examples are divided into two categories: those which demonstrate -the :ref:`reader API `, and those which demonstrate -the :ref:`CTF writer API `. - - -.. _reader-api-examples: - -Reader API examples -=================== - -The :ref:`reader API ` includes everything needed to open -traces and iterate on events in order. - - -Open one trace and print all event names ----------------------------------------- - -This example shows how to open a single CTF trace, iterate on all the -events, and print their names. - -.. code-block:: python - - import babeltrace.reader - import sys - - - # get the trace path from the first command line argument - trace_path = sys.argv[1] - - trace_collection = babeltrace.reader.TraceCollection() - - trace_collection.add_trace(trace_path, 'ctf') - - for event in trace_collection.events: - print(event.name) - - -Open multiple traces and print all event field names ----------------------------------------------------- - -This example opens multiple CTF traces (their paths are provided as -command line arguments), iterates on all their correlated events in -order, and prints a list of their field names. - -.. code-block:: python - - import babeltrace.reader - import sys - - - trace_collection = babeltrace.reader.TraceCollection() - - for path in sys.argv[1:]: - trace_collection.add_trace(path, 'ctf') - - for event in trace_collection.events: - print(', '.join(event.keys())) - - -Print a specific event field ----------------------------- - -Reading the field value of an :class:`babeltrace.reader.Event` object -is done by using its :class:`dict`-like interface: - -.. code-block:: python - - field_value = event['field_name'] - -As such, you can use Python's ``in`` keyword to verify if a given -event contains a given field name: - -.. code-block:: python - - if 'field_name' in event: - # ... - -The following example iterates on the events of a trace, and prints the -value of the ``fd`` field if it's available. - -.. code-block:: python - - import babeltrace.reader - import sys - - # get the trace path from the first command line argument - trace_path = sys.argv[1] - - trace_collection = babeltrace.reader.TraceCollection() - - trace_collection.add_trace(trace_path, 'ctf') - - for event in trace_collection.events: - if 'fd' in event: - print(event['fd']) - -Beware that different fields of the same event may share the same name -if they are in different scopes. In this case, the :class:`dict`-like -interface prioritizes event payload fields before event context fields, -event context fields before stream event context fields, and so on -(see :class:`babeltrace.reader.Event` for this exact list of -priorities). It is possible to get the value of an event's field -within a specific scope using -:meth:`babeltrace.reader.Event.field_with_scope`: - -.. code-block:: python - - import babeltrace.reader - import babeltrace.common - - # ... - - field_value = event.field_with_scope('field_name', - babeltrace.common.CTFScope.EVENT_CONTEXT) - - -Bonus: top 5 running processes using LTTng ------------------------------------------- - -Since `LTTng `_ produces CTF traces, the -Babeltrace Python binding can read LTTng traces. - -This somewhat more complex example reads a whole LTTng Linux kernel -trace, and outputs the short names of the top 5 running processes on -CPU 0 during the whole trace. - -.. code-block:: python - - from collections import Counter - import babeltrace.reader - import sys - - - # a trace collection holds one or more traces - col = babeltrace.reader.TraceCollection() - - # add the trace provided by the user (first command line argument) - # (LTTng traces always have the 'ctf' format) - if col.add_trace(sys.argv[1], 'ctf') is None: - raise RuntimeError('Cannot add trace') - - # this counter dict will hold execution times: - # - # task command name -> total execution time (ns) - exec_times = Counter() - - # this holds the last `sched_switch` timestamp - last_ts = None - - # iterate on events - for event in col.events: - # keep only `sched_switch` events - if event.name != 'sched_switch': - continue - - # keep only events which happened on CPU 0 - if event['cpu_id'] != 0: - continue - - # event timestamp - cur_ts = event.timestamp - - if last_ts is None: - # we start here - last_ts = cur_ts - - # previous task command (short) name - prev_comm = event['prev_comm'] - - # initialize entry in our dict if not yet done - if prev_comm not in exec_times: - exec_times[prev_comm] = 0 - - # compute previous command execution time - diff = cur_ts - last_ts - - # update execution time of this command - exec_times[prev_comm] += diff - - # update last timestamp - last_ts = cur_ts - - # print top 5 - for name, ns in exec_times.most_common(5): - s = ns / 1000000000 - print('{:20}{} s'.format(name, s)) - - -Inspect event declarations and their field declarations -------------------------------------------------------- - -When :meth:`babeltrace.reader.TraceCollection.add_trace` is called -and a trace is successfully opened and added, a corresponding -:class:`babeltrace.reader.TraceHandle` object for this trace is -returned. It is then possible to iterate on the event declarations of -this trace handle using :attr:`babeltrace.reader.TraceHandle.events`. -Each generated :class:`babeltrace.reader.EventDeclaration` object -contains common properties for this type of event, including its -field declarations. This is useful for inspecting the available -events of a trace, and their "signature" in terms of fields, before -iterating its actual events. - -This example adds a trace to a trace collection, and uses the returned -trace handle to iterate on its event declarations. The goal here is to -make sure the ``sched_switch`` event exists, and that it contains -at least the following fields: - -* ``prev_comm``, which should be an array of 8-bit integers -* ``prev_tid``, which should be an integer - -.. code-block:: python - - import babeltrace.reader as btr - import sys - - - def validate_sched_switch_fields(event_decl): - found_prev_comm = False - found_prev_tid = False - - for field_decl in event_decl.fields: - if field_decl.name == 'prev_comm': - if isinstance(field_decl, btr.ArrayFieldDeclaration): - elem_decl = field_decl.element_declaration - - if isinstance(elem_decl, btr.IntegerFieldDeclaration): - if elem_decl.size == 8: - found_prev_comm = True - elif field_decl.name == 'prev_tid': - if isinstance(field_decl, btr.IntegerFieldDeclaration): - found_prev_tid = True - - return found_prev_comm and found_prev_tid - - - # get the trace path from the first command line argument - trace_path = sys.argv[1] - - trace_collection = btr.TraceCollection() - trace_handle = trace_collection.add_trace(trace_path, 'ctf') - sched_switch_found = False - - for event_decl in trace_handle.events: - if event_decl.name == 'sched_switch': - if validate_sched_switch_fields(event_decl): - sched_switch_found = True - break - - print('trace path: {}'.format(trace_handle.path)) - - if sched_switch_found: - print('found sched_switch!') - else: - print('could not find sched_switch') - - -.. _ctf-writer-api-examples: - -CTF writer API examples -======================= - -The :ref:`CTF writer API ` is a set of classes which -allows a Python script to write complete -`CTF `_ (Common Trace Format) traces. - - -One trace, one stream, one event, one field -------------------------------------------- - -This is the most simple example of using the CTF writer API. It creates -one writer (responsible for writing one trace), then uses it to create -one stream. One event with a single field is appended to this single -stream, and everything is flushed. - -The trace is written in a temporary directory (its path is printed -at the beginning of the script). - -.. code-block:: python - - import babeltrace.writer as btw - import tempfile - - - # temporary directory holding the CTF trace - trace_path = tempfile.mkdtemp() - - print('trace path: {}'.format(trace_path)) - - # our writer - writer = btw.Writer(trace_path) - - # create one default clock and register it to the writer - clock = btw.Clock('my_clock') - clock.description = 'this is my clock' - writer.add_clock(clock) - - # create one default stream class and assign our clock to it - stream_class = btw.StreamClass('my_stream') - stream_class.clock = clock - - # create one default event class - event_class = btw.EventClass('my_event') - - # create one 32-bit signed integer field - int32_field_decl = btw.IntegerFieldDeclaration(32) - int32_field_decl.signed = True - - # add this field declaration to our event class - event_class.add_field(int32_field_decl, 'my_field') - - # register our event class to our stream class - stream_class.add_event_class(event_class) - - # create our single event, based on our event class - event = btw.Event(event_class) - - # assign an integer value to our single field - event.payload('my_field').value = -23 - - # create our single stream - stream = writer.create_stream(stream_class) - - # append our single event to our single stream - stream.append_event(event) - - # flush the stream - stream.flush() - - -Basic CTF fields ----------------- - -This example writes a few events with basic CTF fields: integers, -floating point numbers, enumerations and strings. - -The trace is written in a temporary directory (its path is printed -at the beginning of the script). - -.. code-block:: python - - import babeltrace.writer as btw - import babeltrace.common - import tempfile - import math - - - trace_path = tempfile.mkdtemp() - - print('trace path: {}'.format(trace_path)) - - - writer = btw.Writer(trace_path) - - clock = btw.Clock('my_clock') - clock.description = 'this is my clock' - writer.add_clock(clock) - - stream_class = btw.StreamClass('my_stream') - stream_class.clock = clock - - event_class = btw.EventClass('my_event') - - # 32-bit signed integer field declaration - int32_field_decl = btw.IntegerFieldDeclaration(32) - int32_field_decl.signed = True - int32_field_decl.base = btw.IntegerBase.HEX - - # 5-bit unsigned integer field declaration - uint5_field_decl = btw.IntegerFieldDeclaration(5) - uint5_field_decl.signed = False - - # IEEE 754 single precision floating point number field declaration - float_field_decl = btw.FloatingPointFieldDeclaration() - float_field_decl.exponent_digits = btw.FloatingPointFieldDeclaration.FLT_EXP_DIG - float_field_decl.mantissa_digits = btw.FloatingPointFieldDeclaration.FLT_MANT_DIG - - # enumeration field declaration (based on the 5-bit unsigned integer above) - enum_field_decl = btw.EnumerationFieldDeclaration(uint5_field_decl) - enum_field_decl.add_mapping('DAZED', 3, 11) - enum_field_decl.add_mapping('AND', 13, 13) - enum_field_decl.add_mapping('CONFUSED', 17, 30) - - # string field declaration - string_field_decl = btw.StringFieldDeclaration() - string_field_decl.encoding = babeltrace.common.CTFStringEncoding.UTF8 - - event_class.add_field(int32_field_decl, 'my_int32_field') - event_class.add_field(uint5_field_decl, 'my_uint5_field') - event_class.add_field(float_field_decl, 'my_float_field') - event_class.add_field(enum_field_decl, 'my_enum_field') - event_class.add_field(int32_field_decl, 'another_int32_field') - event_class.add_field(string_field_decl, 'my_string_field') - - stream_class.add_event_class(event_class) - - stream = writer.create_stream(stream_class) - - # create and append first event - event = btw.Event(event_class) - event.payload('my_int32_field').value = 0xbeef - event.payload('my_uint5_field').value = 17 - event.payload('my_float_field').value = -math.pi - event.payload('my_enum_field').value = 8 # label: 'DAZED' - event.payload('another_int32_field').value = 0x20141210 - event.payload('my_string_field').value = 'Hello, World!' - stream.append_event(event) - - # create and append second event - event = btw.Event(event_class) - event.payload('my_int32_field').value = 0x12345678 - event.payload('my_uint5_field').value = 31 - event.payload('my_float_field').value = math.e - event.payload('my_enum_field').value = 28 # label: 'CONFUSED' - event.payload('another_int32_field').value = -1 - event.payload('my_string_field').value = trace_path - stream.append_event(event) - - stream.flush() - - -Static array and sequence fields --------------------------------- - -This example demonstrates how to write static array and sequence -fields. A static array has a fixed length, whereas a sequence reads -its length dynamically from another (integer) field. - -In this example, an event is appended to a single stream, in which -three fields are present: - -* ``seqlen``, the dynamic length of the sequence ``seq`` (set to the - number of command line arguments) -* ``array``, a static array of 23 16-bit unsigned integers -* ``seq``, a sequence of ``seqlen`` strings, where the strings are - the command line arguments - -The trace is written in a temporary directory (its path is printed -at the beginning of the script). - -.. code-block:: python - - import babeltrace.writer as btw - import babeltrace.common - import tempfile - import sys - - - trace_path = tempfile.mkdtemp() - - print('trace path: {}'.format(trace_path)) - - - writer = btw.Writer(trace_path) - - clock = btw.Clock('my_clock') - clock.description = 'this is my clock' - writer.add_clock(clock) - - stream_class = btw.StreamClass('my_stream') - stream_class.clock = clock - - event_class = btw.EventClass('my_event') - - # 16-bit unsigned integer field declaration - uint16_field_decl = btw.IntegerFieldDeclaration(16) - uint16_field_decl.signed = False - - # array field declaration (23 16-bit unsigned integers) - array_field_decl = btw.ArrayFieldDeclaration(uint16_field_decl, 23) - - # string field declaration - string_field_decl = btw.StringFieldDeclaration() - string_field_decl.encoding = babeltrace.common.CTFStringEncoding.UTF8 - - # sequence field declaration of strings (length will be the `seqlen` field) - seq_field_decl = btw.SequenceFieldDeclaration(string_field_decl, 'seqlen') - - event_class.add_field(uint16_field_decl, 'seqlen') - event_class.add_field(array_field_decl, 'array') - event_class.add_field(seq_field_decl, 'seq') - - stream_class.add_event_class(event_class) - - stream = writer.create_stream(stream_class) - - # create event - event = btw.Event(event_class) - - # set sequence length field - event.payload('seqlen').value = len(sys.argv) - - # get array field - array_field = event.payload('array') - - # populate array field - for i in range(array_field_decl.length): - array_field.field(i).value = i * i - - # get sequence field - seq_field = event.payload('seq') - - # assign sequence field's length field - seq_field.length = event.payload('seqlen') - - # populate sequence field - for i in range(seq_field.length.value): - seq_field.field(i).value = sys.argv[i] - - # append event - stream.append_event(event) - - stream.flush() - - -Structure fields ----------------- - -A CTF structure is an ordered map of field names to actual fields, just -like C structures. In fact, an event's payload is a structure field, -so structure fields may contain other structure fields, and so on. - -This examples shows how to create a structure field from a structure -field declaration, populate it, and write an event containing it as -a payload field. - -The trace is written in a temporary directory (its path is printed -at the beginning of the script). - -.. code-block:: python - - import babeltrace.writer as btw - import babeltrace.common - import tempfile - - - trace_path = tempfile.mkdtemp() - - print('trace path: {}'.format(trace_path)) - - - writer = btw.Writer(trace_path) - - clock = btw.Clock('my_clock') - clock.description = 'this is my clock' - writer.add_clock(clock) - - stream_class = btw.StreamClass('my_stream') - stream_class.clock = clock - - event_class = btw.EventClass('my_event') - - # 32-bit signed integer field declaration - int32_field_decl = btw.IntegerFieldDeclaration(32) - int32_field_decl.signed = True - - # string field declaration - string_field_decl = btw.StringFieldDeclaration() - string_field_decl.encoding = babeltrace.common.CTFStringEncoding.UTF8 - - # structure field declaration - struct_field_decl = btw.StructureFieldDeclaration() - - # add field declarations to our structure field declaration - struct_field_decl.add_field(int32_field_decl, 'field_one') - struct_field_decl.add_field(string_field_decl, 'field_two') - struct_field_decl.add_field(int32_field_decl, 'field_three') - - event_class.add_field(struct_field_decl, 'my_struct') - event_class.add_field(string_field_decl, 'my_string') - - stream_class.add_event_class(event_class) - - stream = writer.create_stream(stream_class) - - # create event - event = btw.Event(event_class) - - # get event's structure field - struct_field = event.payload('my_struct') - - # populate this structure field - struct_field.field('field_one').value = 23 - struct_field.field('field_two').value = 'Achilles Last Stand' - struct_field.field('field_three').value = -1534 - - # set event's string field - event.payload('my_string').value = 'Tangerine' - - # append event - stream.append_event(event) - - stream.flush() - - -Variant fields --------------- - -The CTF variant is the most versatile field type. It acts as a -placeholder for any other type. Which type is selected depends on the -current value of an outer enumeration field, known as a *tag* from the -variant's point of view. - -Variants are typical constructs in communication protocols with -dynamic types. For example, `BSON `_, -the protocol used by `MongoDB `_, has specific -numeric IDs for each element type. - -This examples shows how to create a CTF variant field. The tag, an -enumeration field, must also be created and associated with the -variant. In this case, the tag selects between three types: a -32-bit signed integer, a string, or a floating point number. - -The trace is written in a temporary directory (its path is printed -at the beginning of the script). - -.. code-block:: python - - import babeltrace.writer as btw - import babeltrace.common - import tempfile - - - trace_path = tempfile.mkdtemp() - - print('trace path: {}'.format(trace_path)) - - - writer = btw.Writer(trace_path) - - clock = btw.Clock('my_clock') - clock.description = 'this is my clock' - writer.add_clock(clock) - - stream_class = btw.StreamClass('my_stream') - stream_class.clock = clock - - event_class = btw.EventClass('my_event') - - # 32-bit signed integer field declaration - int32_field_decl = btw.IntegerFieldDeclaration(32) - int32_field_decl.signed = True - - # string field declaration - string_field_decl = btw.StringFieldDeclaration() - string_field_decl.encoding = babeltrace.common.CTFStringEncoding.UTF8 - - # IEEE 754 single precision floating point number field declaration - float_field_decl = btw.FloatingPointFieldDeclaration() - float_field_decl.exponent_digits = btw.FloatingPointFieldDeclaration.FLT_EXP_DIG - float_field_decl.mantissa_digits = btw.FloatingPointFieldDeclaration.FLT_MANT_DIG - - # enumeration field declaration (variant's tag) - enum_field_decl = btw.EnumerationFieldDeclaration(int32_field_decl) - enum_field_decl.add_mapping('INT', 0, 0) - enum_field_decl.add_mapping('STRING', 1, 1) - enum_field_decl.add_mapping('FLOAT', 2, 2) - - # variant field declaration (variant's tag field will be named `vartag`) - variant_field_decl = btw.VariantFieldDeclaration(enum_field_decl, 'vartag') - - # register selectable fields to variant - variant_field_decl.add_field(int32_field_decl, 'INT') - variant_field_decl.add_field(string_field_decl, 'STRING') - variant_field_decl.add_field(float_field_decl, 'FLOAT') - - event_class.add_field(enum_field_decl, 'vartag') - event_class.add_field(variant_field_decl, 'var') - - stream_class.add_event_class(event_class) - - stream = writer.create_stream(stream_class) - - # first event: integer is selected - event = btw.Event(event_class) - tag_field = event.payload('vartag') - tag_field.value = 0 - event.payload('var').field(tag_field).value = 23 - stream.append_event(event) - - # second event: string is selected - event = btw.Event(event_class) - tag_field = event.payload('vartag') - tag_field.value = 1 - event.payload('var').field(tag_field).value = 'The Battle of Evermore' - stream.append_event(event) - - # third event: floating point number is selected - event = btw.Event(event_class) - tag_field = event.payload('vartag') - tag_field.value = 2 - event.payload('var').field(tag_field).value = -15.34 - stream.append_event(event) - - stream.flush()