/* CTF 1.8 */ typealias integer {size = 8;} := uint8_t; typealias integer {size = 16;} := uint16_t; typealias integer {size = 32;} := uint32_t; typealias integer {size = 64;} := uint64_t; clock { name = tracing_clock; freq = 1000000000; /* tick = 1 ns */ }; typealias integer { size = 64; map = clock.tracing_clock.value; } := tracing_clock_int_t; /* Main trace description, major and minor refers to the CTF version being used. The packet header must contain at the very least a stream id and the CTF magic number. We only use one stream for now, and CTF magic number is 0xc1fc1fc1. We add an extra field ocaml_trace_version to enable simpler transition if we add or remove metrics in the future. */ trace { major = 1; minor = 8; byte_order = @endianness@; packet.header := struct { uint32_t magic; /* required: must contain CTF magic number */ uint16_t ocaml_trace_version; /* our own trace format versioning */ uint16_t stream_id; /* required, although we have only one. */ }; }; /* We use only one stream at the moment. Each event payload must contain a header with a timestamp and a pid. The id field refers to the various event kinds defined further down this file. */ stream { id = 0; event.header := struct { /* for each event */ tracing_clock_int_t timestamp; uint32_t id; }; event.context := struct { uint32_t tid; uint8_t is_backup_thread; }; }; /* These enumerations are mostly following the instrumented runtime datapoints. gc_phase aims to track the entry and exit time of each of the following events during collection. */ enum gc_phase : uint16_t { "compact/main" = 0, "compact/recompact", "explicit/gc_set", "explicit/gc_stat", "explicit/gc_minor", "explicit/gc_major", "explicit/gc_full_major", "explicit/gc_compact", "major", "major/roots", "major/sweep", "major/mark/roots", "major/mark/main", "major/mark/final", "major/mark", "major/mark/global_roots_slice", "major_roots/global", "major_roots/dynamic_global", "major_roots/local", "major_roots/C", "major_roots/finalised", "major_roots/memprof", "major_roots/hook", "major/check_and_compact", "minor", "minor/local_roots", "minor/ref_tables", "minor/copy", "minor/update_weak", "minor/finalized", "explicit/gc_major_slice", "domain/spawn", "domain/send_interrupt", "domain/idle_wait", "finalise/update_first", "finalise/update_last", "interrupt/gc", "interrupt/remote", "major/ephe_mark", "major/ephe_sweep", "major/finish_marking", "major_gc/cycle_domains", "major_gc/phase_change", "major_gc/stw", "major/mark_opportunistic", "major/slice", "minor/clear", "minor/finalizers/oldify", "minor/global_roots", "minor/leave_barrier", "stw/api_barrier", "stw/handler", "stw/leader", "minor/clear", "minor_finalized", "minor_finalizers_oldify", "minor_global_roots", "minor_leave_barrier", "minor_local_roots", "minor_ref_tables", "minor_update_weak", "stw_api_barrier", "stw_handler", "stw_leader", "major_finish_sweeping", "minor_finalizers_admin", "domain/condition_wait" }; /* Miscellaneous GC counters */ enum gc_counter : uint16_t { "alloc_jump", "force_minor/alloc_small", "force_minor/make_vect", "force_minor/set_minor_heap_size", "force_minor/weak", "force_minor/memprof", "major/mark/slice/remain", "major/mark/slice/fields", "major/mark/slice/pointers", "major/work/extra", "major/work/mark", "major/work/sweep", "minor/promoted", "request_major/alloc_shr", "request_major/adjust_gc_speed", "request_minor/realloc_ref_table", "request_minor/realloc_ephe_ref_table", "request_minor/realloc_custom_table" }; /* Block allocation counters, per size buckets. */ enum alloc_bucket : uint8_t { "alloc 01" = 1, "alloc 02", "alloc 03", "alloc 04", "alloc 05", "alloc 06", "alloc 07", "alloc 08", "alloc 09", "alloc 10-19", "alloc 20-29", "alloc 30-39", "alloc 40-49", "alloc 50-59", "alloc 60-69", "alloc 70-79", "alloc 80-89", "alloc 90-99", "alloc large" }; /* Each event is comprised of the previously defined event.header and the fields defined here. An entry event marks the start of a gc phase. */ event { id = 0; name = "entry"; stream_id = 0; fields := struct { enum gc_phase phase; }; }; /* exit counterparts to entry events */ event { id = 1; name = "exit"; stream_id = 0; fields := struct { enum gc_phase phase; }; }; event { id = 2; name = "counter"; stream_id = 0; fields := struct { uint64_t count; enum gc_counter kind; }; }; event { id = 3; name = "alloc"; stream_id = 0; fields := struct { uint64_t count; enum alloc_bucket bucket; }; }; /* Flush events are used to track the time spent by the tracing runtime flushing data to disk, useful to remove flushing overhead for other runtime measurements in the trace. */ event { id = 4; name = "flush"; stream_id = 0; fields := struct { tracing_clock_int_t duration; }; };