Table of Contents

Struct TraceFileHeader

Namespace
Typhon.Profiler
Assembly
Typhon.Profiler.dll

Version-stamped header at the start of a .typhon-trace file. Contains session-wide metadata that lets the viewer decode the record stream that follows. The on-disk size grows with the format version as trailer-offset fields are appended — readers parse it version-conditionally.

public struct TraceFileHeader
Inherited Members

Remarks

Version 3 (Tracy-style typed-event rewrite): file format uses variable-size self-describing records instead of a fixed 64 B struct. Block layout is size-prefixed records, LZ4-compressed per block. Older v1/v2 files are unreadable — the viewer and all tooling are updated in lockstep.

Fields

ArchetypeCount

Number of archetypes in the archetype table.

public ushort ArchetypeCount

Field Value

ushort

BaseTickRate

Target tick rate in Hz (e.g., 60.0 for 60 fps).

public float BaseTickRate

Field Value

float

ComponentTypeCount

Number of component types in the component type table.

public ushort ComponentTypeCount

Field Value

ushort

CpuSampleSectionOffset

Byte offset of the trailing CpuSampleSection (interned CPU stack samples captured by the in-process EventPipe sampler, #351). 0 when absent — no CPU sampling companion, or the parse produced nothing. v9 and earlier traces lack this on-disk field; the reader defaults it to 0.

public long CpuSampleSectionOffset

Field Value

long

CreatedUtcTicks

UTC timestamp when the trace was started (DateTime.UtcNow.Ticks).

public long CreatedUtcTicks

Field Value

long

CurrentVersion

Current format version. v3: variable-size typed-record layout (Tracy-style profiler rewrite). v4: ThreadInfo records gained the trailing ThreadKind byte (#289 follow-up). v5: trailer carries FileTable + SourceLocationManifest at offsets in the header (#302 — profiler source attribution). Reader accepts v4 files transparently — their new offset fields are absent in the on-disk header (51 bytes vs 71) and default to 0, which downstream readers interpret as "no source-location manifest". v6: SystemDefinitionTable carries RFC 07 access declarations (Phase, Reads, ReadsFresh, ReadsSnapshot, AdditionalReads, Writes, SideWrites, ReadsEvents, WritesEvents, ReadsResources, WritesResources, ExplicitAfter, ExplicitBefore, IsExclusivePhase). New PhasesTable section follows ComponentTypeTable, listing the RuntimeOptions.Phases names in order. Reader accepted v5 files transparently — RFC 07 fields default to empty arrays and PhasesTable was treated as absent. v7: rich static-structure tables follow PhasesTable so offline analysis (Workbench schema panels against trace sessions) has the same data a live engine offers — component definitions with full field layout, archetype definitions with parent/child + slot map + cluster info, index catalog, runtime config, event-queue catalog, and a resource-graph snapshot. v6 readers simply lacked the data; rather than synthesising empty defaults (which would silently render "no schema" for old traces), the reader now hard-rejects v6 — re-record against a v7-aware build. See the section writers in TraceFileWriter and the matching reader methods in TraceFileReader. v8 (2026-05-10): NamedSpan reassigned from value 200 to 246 to break a latent collision with EcsQueryMaskAnd. v7 traces with NamedSpan records (kind=200) would mis-decode as EcsQueryMaskAnd under a v8 reader; the reader hard-rejects v7 to surface the break loudly. Re-record against a v8-aware build. v9 (2026-05-11): Query Definition Export (#342). Adds two trailing sections: QuerySourceStringTable (deduped file paths + method names referenced by query events) at offset QuerySourceStringTableOffset, and QueryDefinitionTable (materialized definitions accumulated from QueryDefinitionDescribe events) at offset QueryDefinitionTableOffset. Adds two new instant kinds — QueryDefinitionDescribe (247) and QueryArgs (248) — and extends QueryPlan with 5 trailing fields (QueryInstanceKind, QueryInstanceLocalId, ExecutionSourceFileId, ExecutionSourceLine, ExecutionSourceMethodId). v8 traces continue to load: absent sections produce empty catalogs; v8 QueryPlan records (without the trailing fields) decode with zero/sentinel defaults for the new fields. See claude/design/Profiler/11-query-definition-export.md. v10 (2026-05-16): CPU Sampling Integration (#351). Adds one trailing section, CpuSampleSection (interned CPU stack samples from the in-process EventPipe sampler) at offset CpuSampleSectionOffset. v9 and earlier traces continue to load — the absent on-disk field defaults to 0, which downstream readers interpret as "no CPU samples". See claude/design/Profiler/11-cpu-sampling-integration.md. v11 (2026-05-17): Track→DAG partitioning hierarchy (#354). SystemDefinitionTable records gain a DagId field; the global PhasesTable is replaced by a TracksTable + DagsTable (each DAG carries its own ordered phase names). RuntimeConfigRecord drops Phases/DefaultPhase. v10-and-older traces are hard-rejected (layout-breaking SystemDefinitionTable change). v12 (2026-07-31): Self-describing captures (#614) — one revision covering four decisions of claude/design/Apps/Workbench/10-database-and-profiles.md. D-2: the header gains DatabaseId, DatabaseName and the TsnMin/TsnMax window, so a capture names the database it ran against instead of leaving the pairing to inference. D-3: RoutingId is added to the archetype table, giving every event's per-process catalog id a path to the database's durable identity — see the §5.3 warning on ArchetypeRecord. D-5: DurationTicks, TickCount and SchemaFingerprint join the existing CreatedUtcTicks so a list of captures renders from headers alone, with no sidecar cache built per row. D-9: Flags gains MultipleEnginesObserved. v11-and-older traces are hard-rejected — the ArchetypeTable layout change would otherwise mis-decode silently, which is precisely the class of bug this revision exists to close.

public const ushort CurrentVersion = 12

Field Value

ushort

DagCount

Number of DAGs in the DAGs table (v11+).

public ushort DagCount

Field Value

ushort

DatabaseId

Durable identity of the database this capture ran against (DatabaseEngine.DatabaseId), or Empty when the profiler ran with no engine attached. Survives the bundle being moved, renamed or restored — co-location is not provenance, so the trace records what it saw rather than relying on where it happens to sit (design D-2 / D-1).

public Guid DatabaseId

Field Value

Guid

DatabaseName

The database's bundle name ({name}.typhon without the extension), UTF-8, zero-padded, truncated to Length bytes. Empty when no engine was attached. Present so a trace opened outside its bundle still says something a human can act on — DatabaseId alone is the identity, but a GUID is not a readable answer to "which database is this?".

public TraceDatabaseName DatabaseName

Field Value

TraceDatabaseName

DurationTicks

Wall-clock length of the capture in Stopwatch ticks (divide by TimestampFrequency for seconds). Patched in at close.

public long DurationTicks

Field Value

long

FileTableOffset

Byte offset of the trailing FileTable (interned source-file paths). 0 when no source-location manifest was written (e.g., the source-attribution generator emitted nothing). See claude/design/Profiler/10-profiler-source-attribution.md §4.6.

public long FileTableOffset

Field Value

long

Flags

Flags (reserved for future use).

public ushort Flags

Field Value

ushort

Magic

File magic: ASCII "TYTR" (0x52_54_59_54 little-endian).

public uint Magic

Field Value

uint

MagicValue

File magic constant: ASCII "TYTR".

public const uint MagicValue = 1381259604

Field Value

uint

QueryDefinitionTableOffset

Byte offset of the trailing QueryDefinitionTable (materialized definition catalog accumulated from QueryDefinitionDescribe events, #342). 0 when absent. v8 reader compat: pre-v9 traces lack this on-disk field; the reader defaults it to 0.

public long QueryDefinitionTableOffset

Field Value

long

QuerySourceStringTableOffset

Byte offset of the trailing QuerySourceStringTable (deduped file paths + method names referenced by Query Definition Export events, #342). 0 when no Query Definition Export sections were written (e.g., the session emitted no QueryDefinitionDescribe events). v8 traces have this field absent on disk (the on-disk header pre-v9 ends after SourceLocationManifestOffset) and the reader fills it with 0.

public long QuerySourceStringTableOffset

Field Value

long

Reserved0

Padding to keep on-disk layout future-extension-friendly. Zero-initialized; readers must ignore.

public ushort Reserved0

Field Value

ushort

Reserved1

Padding (aligning the next field to 4 bytes); zero-initialized.

public ushort Reserved1

Field Value

ushort

SamplingSessionStartQpc

Stopwatch.GetTimestamp() captured when the host's EventPipe CPU-sampling session started, or 0 if no sampling companion is attached to this trace. The viewer correlates .nettrace CPU samples into the flame graph by mapping their relative milliseconds against this anchor in the same TimestampFrequency time base the record stream uses.

public long SamplingSessionStartQpc

Field Value

long

SchemaFingerprint

Order-independent 64-bit digest of the schema the capture ran against — FNV-1a over the ordinal-sorted (name, revision) pairs of every component and archetype. Equal fingerprints mean the schemas match; unequal means consult the database's SchemaHistoryR1 for what actually moved. 0 when no engine was attached.

public ulong SchemaFingerprint

Field Value

ulong

SourceLocationManifestOffset

Byte offset of the trailing SourceLocationManifest (id → file/line/method/kind table). 0 when absent. Bound to a non-zero FileTableOffset when the trace carries source attribution.

public long SourceLocationManifestOffset

Field Value

long

SystemCount

Number of systems in the DAG.

public ushort SystemCount

Field Value

ushort

TickCount

Number of runtime ticks the capture spans. Patched in at close; 0 when the capture ran without a scheduler.

public uint TickCount

Field Value

uint

TimestampFrequency

Stopwatch.Frequency — needed to convert timestamp ticks to real time.

public long TimestampFrequency

Field Value

long

TrackCount

Number of tracks in the tracks table (v11+).

public ushort TrackCount

Field Value

ushort

TsnMax

The engine's next-free TSN sampled when the capture closed. Patched in at close. 0 when no engine was attached. See TsnMin.

public long TsnMax

Field Value

long

TsnMin

The engine's next-free TSN sampled when the capture started. With TsnMax this bounds the transaction window the capture covers, and is the left-hand side of the drift readout ("this profile is N transactions behind the database"). 0 when no engine was attached.

public long TsnMin

Field Value

long

Remarks

This is the engine's global TSN counter, not a min over emitted events — a deliberate superset. It costs nothing on the hot path (two reads of an existing counter) and it is the exact quantity the drift measure compares against the database's persisted NextFreeTSN.

Version

Format version. See CurrentVersion for the current value and an evolution log.

public ushort Version

Field Value

ushort

WorkerCount

Number of worker threads in the DagScheduler.

public byte WorkerCount

Field Value

byte

Properties

MultipleEnginesObserved

True when MultipleEnginesObserved is set — routing ids in this trace are absent, not merely suspect.

public bool MultipleEnginesObserved { get; }

Property Value

bool

Methods

GetDatabaseName()

Decodes DatabaseName to a string, stopping at the first NUL. Returns an empty string when no name was recorded.

public string GetDatabaseName()

Returns

string

SetDatabaseName(string)

Encodes name into DatabaseName, truncating on a UTF-8 character boundary if it does not fit. Truncating a display name is harmless; splitting a multi-byte sequence would produce a mojibake name in the profiles list, so the encoder is asked not to.

public void SetDatabaseName(string name)

Parameters

name string