Basics ====== .. Note:: This manual focuses on the python bindings. For a definite reference to attributes of definitions or events, please read the documentation of the C interface: `manual (available if built correctly)`_ .. _manual (available if built correctly): ../html/index.html Definitions ----------- OTF2 specifies over twenty different definitions, which are used to represent the state of the application at the start of the tracing. Most definitions have an reference number. This number is unique between all instances of definitions with the same type. Some types of definitions may share the same space of possible reference numbers, e.g., :py:class:`otf2.definitions.MetricClass` definitions and :py:class:`otf2.definitions.MetricInstance` definitions. A definition can reference definitions of the same type and definitions of another type using the reference numbers. Definitions with a reference number inherit from the internal class `otf2.definitions._RefDefinition` or its subclass `otf2.definitions._NamedRefDefinition`. Some definitions are used to represent the structure of the system, e.g., :py:class:`otf2.definitions.SystemTreeNode`, :py:class:`otf2.definitions.SystemTreeNodeDomain`, and :py:class:`otf2.definitions.SystemTreeNodeProperty`. A :py:class:`otf2.definitions.Region` definition represents a code segment, which can be distinguished by name. In case of common code running on a processor, this represents functions. In a GPGPU context a region would represent a kernel. A :py:class:`otf2.definitions.Location` represents a place, where events can occur. This can be a thread running on a common processor or a thread running in a GPGPU environment. A :py:class:`otf2.definitions.Location` can also be of the special type :py:obj:`otf2.LocationType.METRIC`, which is used in conjunction with asynchronous metrics (see :ref:`metrics`). In order to represent metrics, there are three types of definitions, i.e., :py:class:`otf2.definitions.MetricClass`, :py:class:`otf2.definitions.MetricInstance`, and :py:class:`otf2.definitions.MetricMember` (see :ref:`metrics`). .. _def-handling: Creating definitions _______________________ Normally, definitions are not constructed directly, but rather through the :py:class:`otf2.registry.DefinitionRegistry` of a given :py:class:`otf2.writer.Writer`. The `DefinitionRegistry` provides a method for each definition. E.g. :py:func:`otf2.registry.DefinitionRegistry.system_tree_node` generates a :py:class:`otf2.definitions.SystemTreeNode`. The registry will not generate duplicates: Instead of creating a definition that would be equal to an existing definition, the existing one is returned. Fields of definitions _______________________ In general, definitions are nice Python objects with their expected member fields. With definitions referring to each other, they form an acyclic graph. All definition fields have a specific type. Possible types can be one following: - Simple immutable types such as int, :py:mod:`otf2.enums` (typesafe). .. warning:: Never directly change the .value of an enum - game over. - Strings are denoted as type :py:class:`String`, but they are stored as native :py:class:`str` objects within the definitions. Their references are retrieved only when the definition is written. - A definition that refers to another definition simply has the other definition object as attribute. .. note:: Only definition classes marked by the protected base class `_RefDefinition` or its subclass `_NamedRefDefinition` may be referred to by other definitions. - Aggregates (e.g. List of Definitions) are internally tuples (must be immutable). If you want to change/add/remove an element, you have to set it to a new tuple. You may pass any iterable to construct an aggregate attribute. - Other types, especially mutable types, are not supported. Definitions know the IdRegistry that is responsible for them. Whenever any attribute of a Definition is changed, it informs it's IdRegistry of the change. Events ------ Events are used to represent the state changes, which happen during the execution of the traced application. As :py:class:`otf2.definitions.Location` definitions represent all places, where an event can occur, every event is associated with a :py:class:`otf2.definitions.Location` definition, i.e., the event has occurred at the associated location. Every event has a time stamp, which denotes the time point, when the event occurred at the associated location. All events, which occurred at the same location, are chronologically ordered by their timestamp in a monotonically increasing fashion. Certain events reference some definitions using their reference number, to represent stateless semantics. OTF2 specifies over 50 different :py:mod:`otf2.events`. The majority of the specified events are used to represent the different supported parallelism paradigms, e.g., MPI, and OpenMP. All traces contain at least two types of events. These are :py:class:`otf2.events.Enter` and :py:class:`otf2.events.Leave` events. Enter and leave events reference a :py:class:`otf2.definitions.Region` definition, denoting the begin and the end of the execution of the referenced region on the associated location. Therefore, they always occur as a pair and in this particular sequence. Another type of events is the :py:class:`otf2.events.Metric` event. Metric events denote a measurement value of a metric. .. _metrics: Metrics ------- In OTF2 a metric comprises one or more different measurement points, e.g., an energy metric could comprise the measurement for current and voltage. These measurements are called :py:class:`otf2.definitions.MetricMember`. They can have different units, value types, and measurement methods, but they have to be measured at the same time. The representation of these measurements is done with :py:class:`otf2.definitions.MetricMember` definitions. Each metric is represented by a :py:class:`otf2.definitions.MetricClass` definition. The :py:class:`otf2.definitions.MetricClass` definition references all :py:class:`otf2.definitions.MetricMember` definitions, which the metric consists of. The recorded metric values are stored using :py:class:`otf2.events.Metric` events associated to certain locations, which depends on the type of metric in question. Metrics are categorized in two categories. The first category defines, how many locations record the metric. This can be represented with a matching number of locations, which contain associated metric events. The second category is given by the fact, that some measurements are recorded externally, i.e., the recorded values of the metric are not available on the recording locations during the execution of the traced application. Therefore, a asynchronous metric requires, that the metric events are stored differently compared to synchronous metrics. In case of an synchronous metric, the metric events are coupled to :py:class:`otf2.events.Enter` and :py:class:`otf2.events.Leave` events. The metric events always occur right before the enter and leave, though the metric events, and the enter and leave event share the same timestamp. The recorder and the scope of a synchronous metric is given implicitly by the associated locations of the metric events, which are referencing the metric class definition. Asynchronous metrics require two additional definitions, i.e., a :py:class:`otf2.definitions.MetricInstance` and a :py:class:`otf2.definitions.Location` of type :py:obj:`otf2.LocationType.METRIC`. As asynchronous metrics are externally recorded, they cannot be recorded at the location to which the metric belongs, therefore, they have to explicit specify their scope and their recording location. Also the metric events of the asynchronous metrics has to be associated to a location of type instead :py:obj:`otf2.LocationType.METRIC` of the recorder.