-Common Trace Format (CTF) Specification (pre-v1.8)
+Common Trace Format (CTF) Specification (v1.8.1)
Mathieu Desnoyers, EfficiOS Inc.
3. Event stream
An event stream can be divided into contiguous event packets of variable
-size. These subdivisions have a variable size. An event packet can
-contain a certain amount of padding at the end. The stream header is
-repeated at the beginning of each event packet. The rationale for the
-event stream design choices is explained in Appendix B. Stream Header
-Rationale.
+size. An event packet can contain a certain amount of padding at the
+end. The stream header is repeated at the beginning of each event
+packet. The rationale for the event stream design choices is explained
+in Appendix B. Stream Header Rationale.
The event stream header will therefore be referred to as the "event packet
header" throughout the rest of this document.
4.1.3 Byte order
-By default, the native endianness of the source architecture the trace is used.
+By default, the native endianness of the source architecture is used.
Byte order can be overridden for a basic type by specifying a "byte_order"
attribute. Typical use-case is to specify the network byte order (big endian:
"be") to save data captured from the network into the trace without conversion.
};
If the values are omitted, the enumeration starts at 0 and increment of 1 for
-each entry:
+each entry. An entry with omitted value that follows a range entry takes
+as value the end_value of the previous range + 1:
enum name : unsigned int {
ZERO,
possess a field name, which is a unique identifier within the structure.
The identifier is not allowed to use any reserved keyword
(see Section C.1.2). Replacing reserved keywords with
-underscore-prefixed field names is recommended.
+underscore-prefixed field names is recommended. Fields starting with an
+underscore should have their leading underscore removed by the CTF trace
+readers.
A nameless structure can be declared as a field type or as part of a typedef:
Each variant type selector possess a field name, which is a unique
identifier within the variant. The identifier is not allowed to use any
reserved keyword (see Section C.1.2). Replacing reserved keywords with
-underscore-prefixed field names is recommended.
+underscore-prefixed field names is recommended. Fields starting with an
+underscore should have their leading underscore removed by the CTF trace
+readers.
+
A named variant declaration followed by its definition within a structure
declaration:
include all event timestamps assigned to events contained within the packet.
- Events discarded count
- Snapshot of a per-stream free-running counter, counting the number of
- events discarded that were supposed to be written in the stream prior to
- the first event in the event packet.
- * Note: producer-consumer buffer full condition should fill the current
+ events discarded that were supposed to be written in the stream after
+ the last event in the event packet.
+ * Note: producer-consumer buffer full condition can fill the current
event packet with padding so we know exactly where events have been
- discarded.
+ discarded. However, if the buffer full condition chooses not
+ to fill the current event packet with padding, all we know
+ about the timestamp range in which the events have been
+ discarded is that it is somewhere between the beginning and
+ the end of the packet.
- Lossless compression scheme used for the event packet content. Applied
directly to raw data. New types of compression can be added in following
versions of the format.
7.3.1 Lexical Scope
-Each of "trace", "stream", "event", "struct" and "variant" have their own
-nestable declaration scope, within which types can be declared using "typedef"
-and "typealias". A root declaration scope also contains all declarations
-located outside of any of the aforementioned declarations. An inner
-declaration scope can refer to type declared within its container
-lexical scope prior to the inner declaration scope. Redefinition of a
-typedef or typealias is not valid, although hiding an upper scope
-typedef or typealias is allowed within a sub-scope.
+Each of "trace", "env", "stream", "event", "struct" and "variant" have
+their own nestable declaration scope, within which types can be declared
+using "typedef" and "typealias". A root declaration scope also contains
+all declarations located outside of any of the aforementioned
+declarations. An inner declaration scope can refer to type declared
+within its container lexical scope prior to the inner declaration scope.
+Redefinition of a typedef or typealias is not valid, although hiding an
+upper scope typedef or typealias is allowed within a sub-scope.
7.3.2 Static and Dynamic Scopes
The dynamic scope prefixes are thus:
+ - Trace Environment: <env. >,
- Trace Packet Header: <trace.packet.header. >,
- Stream Packet Context: <stream.packet.context. >,
- Event Header: <stream.event.header. >,
not permitted as field names. It is recommended that field names
clashing with CTF and C99 reserved keywords use an underscore prefix to
eliminate the risk of generating a description containing an invalid
-field name.
+field name. Consequently, fields starting with an underscore should have
+their leading underscore removed by the CTF trace readers.
+
The information available in the dynamic scopes can be thought of as the
current tracing context. At trace production, information about the
in a stream.
trace {
- major = value; /* Trace format version */
- minor = value;
+ major = value; /* CTF spec version major number */
+ minor = value; /* CTF spec version minor number */
uuid = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"; /* Trace UUID */
byte_order = be OR le; /* Endianness (required) */
packet.header := struct {
};
};
+/*
+ * The "env" (environment) scope contains assignment expressions. The
+ * field names and content are implementation-defined.
+ */
+env {
+ pid = value; /* example */
+ proc_name = "name"; /* example */
+ ...
+};
+
stream {
id = stream_id;
/* Type 1 - Few event IDs; Type 2 - Many event IDs. See section 6.1. */
name = "event_name";
id = value; /* Numeric identifier within the stream */
stream_id = stream_id;
- loglevel.identifier = "loglevel_identifier";
- loglevel.value = value;
+ loglevel = value;
context := struct {
...
};
the clock and clock topology should be described in a "clock"
description block, e.g.:
-typealias integer { size = 32; align = 32; signed = true } := uint32_t;
-
-enum clocks : uint32_t {
- cycle_counter,
-};
-
-clock[cycle_counter] {
+clock {
+ name = cycle_counter_sync;
uuid = "62189bee-96dc-11e0-91a8-cfa3d89f3923";
- description = "Local CPU cycle counter";
+ description = "Cycle counter synchronized across CPUs";
freq = 1000000000; /* frequency, in Hz */
/* precision in seconds is: 1000 * (1/freq) */
precision = 1000;
- /* clock value offset from Epoch is: offset * (1/freq) */
- offset = 1326476837897235420;
+ /*
+ * clock value offset from Epoch is:
+ * offset_s + (offset * (1/freq))
+ */
+ offset_s = 1326476837;
+ offset = 897235420;
+ absolute = FALSE;
};
-The optional field "uuid" is the unique identifier of the clock. It can
-be used to correlate different traces that use the same clock. An
-optional textual description string can be added with the "description"
-field. The "freq" field is the initial frequency of the clock, in Hz. If
-the "freq" field is not present, the frequency is assumed to be
-1000000000 (providing clock increment of 1 ns). The optional "precision"
-field details the uncertainty on the clock measurements, in (1/freq)
-units. The "offset" field indicates the offset from POSIX.1 Epoch,
-1970-01-01 00:00:00 +0000 (UTC), to the zero of value of the clock, in
-(1/freq) units. If the "offset" field is not present, it is assigned the
-0 value.
+The mandatory "name" field specifies the name of the clock identifier,
+which can later be used as a reference. The optional field "uuid" is the
+unique identifier of the clock. It can be used to correlate different
+traces that use the same clock. An optional textual description string
+can be added with the "description" field. The "freq" field is the
+initial frequency of the clock, in Hz. If the "freq" field is not
+present, the frequency is assumed to be 1000000000 (providing clock
+increment of 1 ns). The optional "precision" field details the
+uncertainty on the clock measurements, in (1/freq) units. The "offset_s"
+and "offset" fields indicate the offset from POSIX.1 Epoch, 1970-01-01
+00:00:00 +0000 (UTC), to the zero of value of the clock. The "offset_s"
+field is in seconds. The "offset" field is in (1/freq) units. If any of
+the "offset_s" or "offset" field is not present, it is assigned the 0
+value. The field "absolute" is TRUE if the clock is a global reference
+across different clock uuid (e.g. NTP time). Otherwise, "absolute" is
+FALSE, and the clock can be considered as synchronized only with other
+clocks that have the same uuid.
+
Secondly, a reference to this clock should be added within an integer
type:
typealias integer {
size = 64; align = 1; signed = false;
- map = clock[cycle_counter].value;
+ map = clock.cycle_counter_sync.value;
} := uint64_ccnt_t;
Thirdly, stream declarations can reference the clock they use as a
clock
double
enum
+env
event
floating_point
float
2.3) CTF-specific declarations
ctf-specifier:
+ clock { ctf-assignment-expression-list-opt }
event { ctf-assignment-expression-list-opt }
stream { ctf-assignment-expression-list-opt }
+ env { ctf-assignment-expression-list-opt }
trace { ctf-assignment-expression-list-opt }
typealias declaration-specifiers abstract-declarator-list type-assignment-operator declaration-specifiers abstract-declarator-list
typealias declaration-specifiers abstract-declarator-list type-assignment-operator declarator-list