Skip to main content

chronon::observe::PerfettoTraceWriter

Perfetto trace writer for the small TracePacket subset chronon needs. More...

#include <PerfettoTraceWriter.hpp>

Public Classes

Name
structOptions
structAnnotation
Typed debug annotation (SDK-free view; names are interned).

Public Functions

Name
~PerfettoTraceWriter()
voidwallInstant(uint64_t track_uuid, std::string_view category, std::string_view name, uint64_t ts_ns)
Emit an instant event at ts_ns on the wall-clock sequence.
voidwallInstant(uint64_t track_uuid, std::string_view category, std::string_view name, uint64_t ts_ns, uint64_t cycle, std::string_view detail ={})
voidsliceEnd(uint64_t track_uuid, uint64_t cycle)
Close the innermost open span on track_uuid at cycle.
voidsliceComplete(uint64_t track_uuid, std::string_view category, std::string_view name, uint64_t ts_ns, uint64_t dur_ns, uint64_t cycle, std::string_view detail ={})
Emit a complete wall-clock slice (paired SLICE_BEGIN / SLICE_END packets).
voidsliceBeginWithFlow(uint64_t track_uuid, std::string_view category, std::string_view name, uint64_t cycle, uint64_t flow_id, std::span< const Annotation > annotations)
Open a span with an explicit flow id; unlike sliceBegin(), flow id 0 is emitted.
voidsliceBegin(uint64_t track_uuid, std::string_view category, std::string_view name, uint64_t cycle, uint64_t flow_id, std::span< const Annotation > annotations)
Open a span at cycle on the simulation cycle clock.
PerfettoTraceWriter &operator=(const PerfettoTraceWriter & ) =delete
boolopen(const std::filesystem::path & path, const Options & options)
Opens path for writing; sequence-start packets are emitted lazily.
boolopen(const std::filesystem::path & path)
boolisOpen() const
voidinstant(uint64_t track_uuid, std::string_view category, std::string_view name, uint64_t cycle)
Emit an instant event at cycle on the simulation cycle clock.
voidinstant(uint64_t track_uuid, std::string_view category, std::string_view name, uint64_t cycle, uint64_t flow_id, std::span< const Annotation > annotations)
Instant with flow id (0 = none) and typed annotations (cycle clock).
voidflush()
uint64_tfirstClockOutputNanoseconds() const
Host time since open() until the first event-containing packet batch is written.
uint64_teventsWritten() const
voidcounterValue(uint64_t track_uuid, uint64_t cycle, int64_t value)
Emit a counter sample at cycle on a counter track.
voidclose()
voidclockInstant(uint32_t stream, uint64_t track_uuid, std::string_view category, std::string_view name, uint64_t local_cycle, uint64_t flow_id, std::span< const Annotation > annotations ={})
uint64_tclockBufferPeakRecords() const
uint64_tclockBufferPeakBytes() const
uint64_tbytesWritten() const
voidadvanceClockWatermark(uint64_t exclusive_ns)
uint64_taddTrack(std::string_view name, uint64_t parent_uuid =0, int32_t sibling_order_rank =-1)
uint64_taddProcessTrack(std::string_view process_name, int32_t pid)
uint64_taddCounterTrack(std::string_view name, std::string_view unit_name, uint64_t parent_uuid =0, int32_t sibling_order_rank =-1)
uint32_taddClockStream(const ClockDomain & domain)
PerfettoTraceWriter()
PerfettoTraceWriter(const PerfettoTraceWriter & ) =delete

Detailed Description

class chronon::observe::PerfettoTraceWriter;

Perfetto trace writer for the small TracePacket subset chronon needs.

Thin wrapper over the Perfetto SDK's protozero message writers: TrackDescriptor (process / plain / counter tracks) and TrackEvent (complete slices, instants, counter samples). Output opens directly in ui.perfetto.dev and trace_processor. The SDK is an implementation detail (pimpl) and does not leak into chronon headers; no tracing session or category registration is involved — packets are written straight to the file.

Events are split across two packet sequences by time domain:

  • Simulation domain (instant(), counterValue()): timestamps are cycles on a custom incremental clock (sequence-scoped clock id 64) declared via ClockSnapshot and TracePacketDefaults. The clock is paired 1:1 with the builtin boot clock, so the rendered axis is unchanged (1 cycle = 1 ns) but packets carry varint deltas instead of absolute timestamps. Out-of-order cycles fall back to an absolute boot-clock timestamp on that packet so the incremental state never corrupts.
  • Wall-clock domain (sliceComplete(), wallInstant()): real nanoseconds since the recorder's base time on the default trace clock (used by the scheduler execution timeline). The cycle debug annotation carries the simulation cycle for slices where the two domains differ.

Both sequences intern event names, categories, and debug-annotation names (InternedData + SEQ_NEEDS_INCREMENTAL_STATE). Incremental state is checkpointed (SEQ_INCREMENTAL_STATE_CLEARED + fresh clock snapshot) every Options::checkpoint_interval_packets packets and whenever an intern table reaches Options::max_interned_strings, which bounds reader memory and keeps crash-truncated traces decodable.

Packets buffer in memory and flush to disk past a threshold, so the file is written incrementally and remains parseable after a crash (Perfetto traces need no footer). With Options::compress, each flushed batch is wrapped in a TracePacket.compressed_packets (zlib deflate) — handled natively by ui.perfetto.dev and trace_processor. NOT thread-safe; intended for a single backend thread.

Public Functions Documentation

function ~PerfettoTraceWriter

~PerfettoTraceWriter()

function wallInstant

void wallInstant(
uint64_t track_uuid,
std::string_view category,
std::string_view name,
uint64_t ts_ns
)

Emit an instant event at ts_ns on the wall-clock sequence.

function wallInstant

void wallInstant(
uint64_t track_uuid,
std::string_view category,
std::string_view name,
uint64_t ts_ns,
uint64_t cycle,
std::string_view detail ={}
)

function sliceEnd

void sliceEnd(
uint64_t track_uuid,
uint64_t cycle
)

Close the innermost open span on track_uuid at cycle.

function sliceComplete

void sliceComplete(
uint64_t track_uuid,
std::string_view category,
std::string_view name,
uint64_t ts_ns,
uint64_t dur_ns,
uint64_t cycle,
std::string_view detail ={}
)

Emit a complete wall-clock slice (paired SLICE_BEGIN / SLICE_END packets).

cycle is attached as a debug annotation; detail likewise when non-empty.

function sliceBeginWithFlow

void sliceBeginWithFlow(
uint64_t track_uuid,
std::string_view category,
std::string_view name,
uint64_t cycle,
uint64_t flow_id,
std::span< const Annotation > annotations
)

Open a span with an explicit flow id; unlike sliceBegin(), flow id 0 is emitted.

function sliceBegin

void sliceBegin(
uint64_t track_uuid,
std::string_view category,
std::string_view name,
uint64_t cycle,
uint64_t flow_id,
std::span< const Annotation > annotations
)

Open a span at cycle on the simulation cycle clock.

The matching sliceEnd() may come many cycles later; pairing is the caller's responsibility (the backend's open-span table).

function operator=

PerfettoTraceWriter & operator=(
const PerfettoTraceWriter &
) =delete

function open

bool open(
const std::filesystem::path & path,
const Options & options
)

Opens path for writing; sequence-start packets are emitted lazily.

function open

inline bool open(
const std::filesystem::path & path
)

function isOpen

bool isOpen() const

function instant

void instant(
uint64_t track_uuid,
std::string_view category,
std::string_view name,
uint64_t cycle
)

Emit an instant event at cycle on the simulation cycle clock.

function instant

void instant(
uint64_t track_uuid,
std::string_view category,
std::string_view name,
uint64_t cycle,
uint64_t flow_id,
std::span< const Annotation > annotations
)

Instant with flow id (0 = none) and typed annotations (cycle clock).

function flush

void flush()

Write encoded packets to the OS; open native buckets require a watermark. Throws on write/flush failure; close the failed writer before reopening it.

function firstClockOutputNanoseconds

uint64_t firstClockOutputNanoseconds() const

Host time since open() until the first event-containing packet batch is written.

function eventsWritten

inline uint64_t eventsWritten() const

function counterValue

void counterValue(
uint64_t track_uuid,
uint64_t cycle,
int64_t value
)

Emit a counter sample at cycle on a counter track.

function close

void close()

Finish remaining native buckets, flush and close. No temporary disk files. Throws on output failure after releasing the file.

function clockInstant

void clockInstant(
uint32_t stream,
uint64_t track_uuid,
std::string_view category,
std::string_view name,
uint64_t local_cycle,
uint64_t flow_id,
std::span< const Annotation > annotations ={}
)

function clockBufferPeakRecords

uint64_t clockBufferPeakRecords() const

function clockBufferPeakBytes

uint64_t clockBufferPeakBytes() const

function bytesWritten

inline uint64_t bytesWritten() const

Bytes in completely successful flushes (excludes any partially failed batch). This is OS write completion, not a durability guarantee from fsync.

function advanceClockWatermark

void advanceClockWatermark(
uint64_t exclusive_ns
)

Promise that every future native event has floor(time/ns) >= exclusive_ns. All earlier records must already have been submitted, across ALL streams. Emit closed buckets; equal-ns events remain buffered. Monotonic, single writer.

function addTrack

uint64_t addTrack(
std::string_view name,
uint64_t parent_uuid =0,
int32_t sibling_order_rank =-1
)

Return: Track UUID for a named track, optionally nested under parent_uuid.

function addProcessTrack

uint64_t addProcessTrack(
std::string_view process_name,
int32_t pid
)

Return: Track UUID for a process-scoped group track (ProcessDescriptor).

function addCounterTrack

uint64_t addCounterTrack(
std::string_view name,
std::string_view unit_name,
uint64_t parent_uuid =0,
int32_t sibling_order_rank =-1
)

Return: Track UUID for a counter track (rendered as a value graph).

function addClockStream

uint32_t addClockStream(
const ClockDomain & domain
)

Configure before events. Each stream gets its own sequence and local incremental/absolute clocks (64/65), mapped to TRACE_FILE simulation ns. Hardware frequencies are converted exactly before floor-to-ns encoding. Native clock streams cannot share a file with legacy or host-time events. Closed buckets are ordered before encoding: exact time, Uint "phase" (default 0), track name, Uint "ordinal" (default stream order). Stable unique track names identify simultaneous independent streams. Native records own metadata, at most 64 KiB each. Publish watermarks in bounded batches; late events and exhausted buckets throw, never spill to disk.

function PerfettoTraceWriter

PerfettoTraceWriter()

function PerfettoTraceWriter

PerfettoTraceWriter(
const PerfettoTraceWriter &
) =delete

Updated on 2026-09-20 at 14:23:39 +0000