Class TraceFileWriter
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
streamStreamOutput stream for the
.typhon-tracefile.
Exceptions
- ArgumentNullException
streamisnull.
Fields
CpuSampleSectionMagic
Magic marker for the trailing CpuSampleSection (interned CPU stack samples). "CPUS" LE (#351).
public const uint CpuSampleSectionMagic = 1398100035
Field Value
FileTableMagic
Magic marker for the trailing FileTable (interned source-file paths). "SFLB" LE.
public const uint FileTableMagic = 1112294995
Field Value
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
QueryDefinitionTableMagic
Magic marker for the trailing QueryDefinitionTable (materialized definition catalog). "QDFT" LE (#342).
public const uint QueryDefinitionTableMagic = 1413891153
Field Value
QuerySourceStringTableMagic
Magic marker for the trailing QuerySourceStringTable (deduped query source-file paths + method names). "QSST" LE (#342).
public const uint QuerySourceStringTableMagic = 1414746961
Field Value
SourceLocationManifestMagic
Magic marker for the trailing SourceLocationManifest. "SLMN" LE.
public const uint SourceLocationManifestMagic = 1313688659
Field Value
SpanNameTableMagic
Magic marker for the trailing span-name table (distinguishes it from an event block header).
public const uint SpanNameTableMagic = 1312903251
Field Value
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
headerTraceFileHeader
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
archetypesReadOnlySpan<ArchetypeDefinitionRecord>
WriteArchetypes(ReadOnlySpan<ArchetypeRecord>)
Writes the archetype table. Must be called once after system definitions.
public void WriteArchetypes(ReadOnlySpan<ArchetypeRecord> archetypes)
Parameters
archetypesReadOnlySpan<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
componentsReadOnlySpan<ComponentDefinitionRecord>
WriteComponentTypes(ReadOnlySpan<ComponentTypeRecord>)
Writes the component type table. Must be called once after the archetype table.
public void WriteComponentTypes(ReadOnlySpan<ComponentTypeRecord> componentTypes)
Parameters
componentTypesReadOnlySpan<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
samplesIReadOnlyList<CpuSampleRecord>stacksIReadOnlyList<ushort[]>frameSymbolsIReadOnlyList<CpuFrameSymbol>
Returns
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
dagsReadOnlySpan<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
queuesReadOnlySpan<EventQueueRecord>
WriteHeader(in TraceFileHeader)
Writes the file header. Must be called exactly once before any other writes.
public void WriteHeader(in TraceFileHeader header)
Parameters
headerTraceFileHeader
WriteIndexCatalog(ReadOnlySpan<IndexCatalogEntry>)
Writes the flat (componentTypeId, fieldId) → index variant catalog (v7+).
public void WriteIndexCatalog(ReadOnlySpan<IndexCatalogEntry> indexes)
Parameters
indexesReadOnlySpan<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
stringsIReadOnlyList<string>
Returns
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
recordsReadOnlySpan<byte>recordCountint
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
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
configRuntimeConfigRecord
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
filesIReadOnlyList<string>entriesIReadOnlyList<SourceLocationManifestEntry>
Returns
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
spanNamesIReadOnlyDictionary<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
systemsReadOnlySpan<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
tracksReadOnlySpan<TrackRecord>