Table of Contents

Class TraceFileWriter

Namespace
Typhon.Profiler
Assembly
Typhon.Profiler.dll

Writes a .typhon-trace binary trace file — the variable-size typed-record layout introduced in the Tracy-style profiler rewrite (see CurrentVersion for the current format version). Owns the underlying stream; not thread-safe — callers must serialize writes (the profiler's exporter thread is the only writer).

public sealed class TraceFileWriter : IDisposable
Inheritance
TraceFileWriter
Implements
Inherited Members

Remarks

File layout:

[TraceFileHeader]           variable — grows with format version
[SystemDefinitionTable]     variable — system DAG definitions
[ArchetypeTable]            variable — archetype ID → name map
[ComponentTypeTable]        variable — component type ID → name map
[CompressedBlock]*          repeating: block header + LZ4-compressed raw record bytes
[SpanNameTable]             optional trailing table of runtime-interned NamedSpan names

Each compressed block wraps an LZ4-encoded byte run that is a concatenation of variable-size typed records as they come off the producer's ring buffer. The block header declares the record count and uncompressed byte count; the reader uses those to walk records one at a time via the u16 size field at the start of each.

Constructors

TraceFileWriter(Stream)

Wraps stream for writing a .typhon-trace file. Call WriteHeader(in TraceFileHeader) once, then the metadata-table writers and WriteRecords(ReadOnlySpan<byte>, int) block writers in order — see the type remarks for the layout. The writer takes ownership and disposes the stream in Dispose().

public TraceFileWriter(Stream stream)

Parameters

stream Stream

Output stream for the .typhon-trace file.

Exceptions

ArgumentNullException

stream is null.

Fields

CpuSampleSectionMagic

Magic marker for the trailing CpuSampleSection (interned CPU stack samples). "CPUS" LE (#351).

public const uint CpuSampleSectionMagic = 1398100035

Field Value

uint

FileTableMagic

Magic marker for the trailing FileTable (interned source-file paths). "SFLB" LE.

public const uint FileTableMagic = 1112294995

Field Value

uint

MaxBlockBytes

Maximum bytes per compressed block. Batches larger than this are split by the exporter before calling WriteRecords(ReadOnlySpan<byte>, int).

public const int MaxBlockBytes = 262144

Field Value

int

QueryDefinitionTableMagic

Magic marker for the trailing QueryDefinitionTable (materialized definition catalog). "QDFT" LE (#342).

public const uint QueryDefinitionTableMagic = 1413891153

Field Value

uint

QuerySourceStringTableMagic

Magic marker for the trailing QuerySourceStringTable (deduped query source-file paths + method names). "QSST" LE (#342).

public const uint QuerySourceStringTableMagic = 1414746961

Field Value

uint

SourceLocationManifestMagic

Magic marker for the trailing SourceLocationManifest. "SLMN" LE.

public const uint SourceLocationManifestMagic = 1313688659

Field Value

uint

SpanNameTableMagic

Magic marker for the trailing span-name table (distinguishes it from an event block header).

public const uint SpanNameTableMagic = 1312903251

Field Value

uint

Methods

Dispose()

Disposes the writer and closes the underlying stream. Idempotent.

public void Dispose()

Flush()

Flushes buffered bytes to the underlying stream.

public void Flush()

RewriteHeader(in TraceFileHeader)

Rewrite the file header at offset 0 with updated trailer offsets. Required to seek; throws on non-seekable streams. Used to record the trailing-section offsets after the manifest is appended.

public void RewriteHeader(in TraceFileHeader header)

Parameters

header TraceFileHeader

WriteArchetypeDefinitions(ReadOnlySpan<ArchetypeDefinitionRecord>)

Writes the rich archetype-definitions table (v7+). Variable-size per record — child id list and component-id list are length-prefixed; the cluster-info inline block is gated by the Flags 0x01 bit.

public void WriteArchetypeDefinitions(ReadOnlySpan<ArchetypeDefinitionRecord> archetypes)

Parameters

archetypes ReadOnlySpan<ArchetypeDefinitionRecord>

WriteArchetypes(ReadOnlySpan<ArchetypeRecord>)

Writes the archetype table. Must be called once after system definitions.

public void WriteArchetypes(ReadOnlySpan<ArchetypeRecord> archetypes)

Parameters

archetypes ReadOnlySpan<ArchetypeRecord>

WriteComponentDefinitions(ReadOnlySpan<ComponentDefinitionRecord>)

Writes the rich component-definitions table (v7+). One ComponentDefinitionRecord per registered component type — sits after WriteDags in the on-disk sequence. Empty array is valid (no components → 0 length prefix; the reader returns an empty list).

public void WriteComponentDefinitions(ReadOnlySpan<ComponentDefinitionRecord> components)

Parameters

components ReadOnlySpan<ComponentDefinitionRecord>

WriteComponentTypes(ReadOnlySpan<ComponentTypeRecord>)

Writes the component type table. Must be called once after the archetype table.

public void WriteComponentTypes(ReadOnlySpan<ComponentTypeRecord> componentTypes)

Parameters

componentTypes ReadOnlySpan<ComponentTypeRecord>

WriteCpuSampleSection(IReadOnlyList<CpuSampleRecord>, IReadOnlyList<ushort[]>, IReadOnlyList<CpuFrameSymbol>)

Append the CpuSampleSection trailer (#351, v10) and return the offset for the header patch. CPU samples reference an interned stack table; each stack references interned frame symbols, whose FileId indexes the same FileTable the source-location manifest uses. Empty input → no section written (return 0).

public long WriteCpuSampleSection(IReadOnlyList<CpuSampleRecord> samples, IReadOnlyList<ushort[]> stacks, IReadOnlyList<CpuFrameSymbol> frameSymbols)

Parameters

samples IReadOnlyList<CpuSampleRecord>
stacks IReadOnlyList<ushort[]>
frameSymbols IReadOnlyList<CpuFrameSymbol>

Returns

long

Remarks

Wire layout:

u32  Magic ("CPUS")
u32  SampleCount;     per sample: i64 qpc, u8 threadSlot (0xFF = unslotted), u8 sampleType, u32 stackIndex
u32  StackCount;      per stack:  u16 frameCount, u16 frameId * frameCount
u32  FrameSymbolCount; per symbol: u16 frameId, u16 fileId, u32 line, u8 methodLen, byte[methodLen] utf8

WriteDags(ReadOnlySpan<DagRecord>)

Writes the DAGs table (v11+, #354). One entry per DagRecord — each carries its owning track index and its own ordered phase names. Follows the TracksTable on disk. Empty array is valid; the reader returns an empty list.

public void WriteDags(ReadOnlySpan<DagRecord> dags)

Parameters

dags ReadOnlySpan<DagRecord>

WriteEmptyStaticStructures()

Convenience helper for fixtures + tests that don't care about populating the v7 static-structure tables — writes empty versions of all six (component definitions, archetype definitions, index catalog, runtime config, event queue catalog, resource graph snapshot). Production code should call the individual Write... methods with real data; this helper exists so test scaffolding stays readable.

public void WriteEmptyStaticStructures()

WriteEventQueueCatalog(ReadOnlySpan<EventQueueRecord>)

Writes the per-queue static-schema catalog (v7+).

public void WriteEventQueueCatalog(ReadOnlySpan<EventQueueRecord> queues)

Parameters

queues ReadOnlySpan<EventQueueRecord>

WriteHeader(in TraceFileHeader)

Writes the file header. Must be called exactly once before any other writes.

public void WriteHeader(in TraceFileHeader header)

Parameters

header TraceFileHeader

WriteIndexCatalog(ReadOnlySpan<IndexCatalogEntry>)

Writes the flat (componentTypeId, fieldId) → index variant catalog (v7+).

public void WriteIndexCatalog(ReadOnlySpan<IndexCatalogEntry> indexes)

Parameters

indexes ReadOnlySpan<IndexCatalogEntry>

WriteQuerySourceStringTable(IReadOnlyList<string>)

Append the QuerySourceStringTable trailer section (#342, v9) and return the offset for the header patch. The table is a packed array of length-prefixed UTF-8 strings indexed by 16-bit ID. Slot 0 is reserved as the "no source" sentinel and always serializes as the empty string. Empty input → no section written (return 0).

public long WriteQuerySourceStringTable(IReadOnlyList<string> strings)

Parameters

strings IReadOnlyList<string>

Returns

long

Remarks

Wire layout:

u32  Magic ("QSST")
u32  Count (including the index-0 sentinel)
for i in 0..Count: u16 length, byte[length] utf8

WriteRecords(ReadOnlySpan<byte>, int)

Writes a batch of raw trace records as one LZ4-compressed block. The caller guarantees records contains exactly recordCount valid size-prefixed records and is no larger than MaxBlockBytes.

public void WriteRecords(ReadOnlySpan<byte> records, int recordCount)

Parameters

records ReadOnlySpan<byte>
recordCount int

WriteResourceGraphSnapshot(ReadOnlySpan<ResourceGraphNodeRecord>)

Writes the resource-graph snapshot (v7+) — a pre-order tree walk; readers reconstruct the tree via ParentId (-1 for root).

public void WriteResourceGraphSnapshot(ReadOnlySpan<ResourceGraphNodeRecord> nodes)

Parameters

nodes ReadOnlySpan<ResourceGraphNodeRecord>

WriteRuntimeConfig(RuntimeConfigRecord)

Writes the runtime-config record (v7+). Single record. Wire format prefixes with a one-byte presence flag so the reader can distinguish "no runtime config available" (flag=0) from "default-valued config" (flag=1, all zero fields).

public void WriteRuntimeConfig(RuntimeConfigRecord config)

Parameters

config RuntimeConfigRecord

WriteSourceLocationManifest(IReadOnlyList<string>, IReadOnlyList<SourceLocationManifestEntry>)

Append the source-location manifest to the file. Returns the (fileTableOffset, manifestOffset) that the caller MUST patch into the file header via RewriteHeader(in TraceFileHeader). Phase 3 of the profiler-source-attribution feature (see claude/design/Profiler/10-profiler-source-attribution.md §4.6).

public (long fileTableOffset, long manifestOffset) WriteSourceLocationManifest(IReadOnlyList<string> files, IReadOnlyList<SourceLocationManifestEntry> entries)

Parameters

files IReadOnlyList<string>
entries IReadOnlyList<SourceLocationManifestEntry>

Returns

(long fileTableOffset, long manifestOffset)

WriteSpanNames(IReadOnlyDictionary<int, string>)

Writes the span name intern table. Called at shutdown with the runtime-interned NamedSpan names.

public void WriteSpanNames(IReadOnlyDictionary<int, string> spanNames)

Parameters

spanNames IReadOnlyDictionary<int, string>

WriteSystemDefinitions(ReadOnlySpan<SystemDefinitionRecord>)

Writes the system definition table. Must be called exactly once after the header.

public void WriteSystemDefinitions(ReadOnlySpan<SystemDefinitionRecord> systems)

Parameters

systems ReadOnlySpan<SystemDefinitionRecord>

Remarks

Each record carries the RFC 07 access declarations (v6+) and a trailing DagId (v11+). The reader only accepts v11-or-newer traces (see MinSupportedVersion), so all trailing fields are always present on read.

WriteTracks(ReadOnlySpan<TrackRecord>)

Writes the tracks table (v11+, #354). One entry per TrackRecord — the top level of the runtime partitioning hierarchy. Takes the on-disk slot the v6 PhasesTable used. Empty array is valid; the reader returns an empty list.

public void WriteTracks(ReadOnlySpan<TrackRecord> tracks)

Parameters

tracks ReadOnlySpan<TrackRecord>