Table of Contents

Class IncrementalCacheBuilder

Namespace
Typhon.Profiler
Assembly
Typhon.Profiler.dll

Incremental, instance-based variant of TraceFileCacheBuilder. The replay path constructs an instance, pumps the trace file's record bytes through FeedRawRecords(ReadOnlySpan<byte>), and disposes (which writes the trailer when the sink supports it). The live path constructs an instance from the engine's Init-frame metadata, pumps each Block frame's decompressed records through FeedRawRecords(ReadOnlySpan<byte>), calls FlushCurrentChunk() on a 200 ms timer for in-flight chunk visibility, and disposes when the engine sends Shutdown.

public sealed class IncrementalCacheBuilder : IDisposable
Inheritance
IncrementalCacheBuilder
Implements
Inherited Members

Remarks

Behaviorally identical to TraceFileCacheBuilder for replay traces — Build(string, string, IProgress<BuildProgress>) is the static façade that pumps a file through an instance and disposes. Parity tests assert byte-identical sidecar output across the old static builder, the new static façade, and arbitrary record-span splits driven manually.

All record-walking state is held in instance fields (formerly method-locals). The FeedRawRecords(ReadOnlySpan<byte>) entry point expects raw record bytes back-to-back exactly matching the inner-loop format consumed by TraceFileCacheBuilder: each record begins with a u16 size prefix followed by a u8 kind byte. Multiple records may be passed in a single span and are walked sequentially. Partial records ARE NOT supported across calls — the caller must pass complete records (the engine's block frames already align on record boundaries).

Constructors

IncrementalCacheBuilder(ICacheChunkSink, bool, in ProfilerHeader, ReadOnlySpan<byte>, IReadOnlyDictionary<int, string>, IReadOnlyDictionary<ushort, string>)

Construct a builder. Caller is responsible for parsing the source's header / system tables / archetypes / component types up front (replay: via TraceFileReader; live: via the engine's Init frame which carries the same data).

public IncrementalCacheBuilder(ICacheChunkSink sink, bool ownsSink, in ProfilerHeader header, ReadOnlySpan<byte> sourceFingerprint, IReadOnlyDictionary<int, string> spanNames, IReadOnlyDictionary<ushort, string> queueNames)

Parameters

sink ICacheChunkSink

Where flushed chunks land. FileCacheSink for replay, AppendOnlyChunkSink for live.

ownsSink bool

If true, the builder disposes the sink in its own Dispose().

header ProfilerHeader

Source profiler header (used for TimestampFrequency and version stamping).

sourceFingerprint ReadOnlySpan<byte>

32-byte source fingerprint to embed in the cache header. Live: arbitrary 32-byte session ID.

spanNames IReadOnlyDictionary<int, string>

Span-name intern table from the source. Pre-populated for replay traces; empty / lazily-grown for live (live appends spans through the same buffer).

queueNames IReadOnlyDictionary<ushort, string>

Queue-id → display-name map from the source's EventQueueCatalog. Pre-populated for replay traces (the engine writes every queue at Init time, so the catalog is complete before any block). Empty for live attach until the engine ships the equivalent catalog over the wire — at which point RegisterQueueName(ushort, string) fills in the gaps. Required (not optional) so a forgotten call site fails the compile instead of silently shipping an empty QueueNameTable cache section (which caused #?? where the Workbench's aggregate endpoint couldn't resolve queue names declared in topology).

Fields

PreTickBufferCap

Cap on the pre-tick buffer's size. Pre-tick events are records that arrive before the first TickStart (engine-startup memory events, GC suspensions, ThreadInfo records). Past this cap, additional pre-tick events are dropped and counted in PreTickDroppedBytes.

public const int PreTickBufferCap = 16777216

Field Value

int

Properties

ChunkManifest

Read-only view of flushed chunks. Grows as the builder flushes chunks.

public IReadOnlyList<ChunkManifestEntry> ChunkManifest { get; }

Property Value

IReadOnlyList<ChunkManifestEntry>

CurrentGlobalMetrics

Snapshot of the global metrics computed from the current state. Recomputed on each access — caller should cache for per-frame use. Live SSE delta emission throttles to ~1 Hz.

public GlobalMetricsFixed CurrentGlobalMetrics { get; }

Property Value

GlobalMetricsFixed

FoldedCount

Folded-completion count (kickoff/completion async fold). Mirrors FoldedCount.

public long FoldedCount { get; }

Property Value

long

PostTickSummaries

Read-only view of finalized per-tick post-tick markers.

public IReadOnlyList<PostTickSummary> PostTickSummaries { get; }

Property Value

IReadOnlyList<PostTickSummary>

PreTickDroppedBytes

Bytes that were dropped because the pre-tick buffer was at PreTickBufferCap. Diagnostic only.

public long PreTickDroppedBytes { get; }

Property Value

long

QueueIdToName

Queue-id → display-name map. Seeded at construction from the source's EventQueueCatalog (the engine registers every queue up-front during Init, so the catalog is complete before any record arrives). RegisterQueueName(ushort, string) stays available for late-arriving queues — the live attach path needs it if the engine ever ships a queue catalog mid-stream — but the replay path no longer relies on it.

public IReadOnlyDictionary<ushort, string> QueueIdToName { get; }

Property Value

IReadOnlyDictionary<ushort, string>

QueueTickSummaries

Read-only view of finalized per-(tick, queue) rows.

public IReadOnlyList<QueueTickSummary> QueueTickSummaries { get; }

Property Value

IReadOnlyList<QueueTickSummary>

SpanNames

Read-only view of the span-name intern table. Replay traces have this pre-populated; live attaches grow it lazily as records arrive.

public IReadOnlyDictionary<int, string> SpanNames { get; }

Property Value

IReadOnlyDictionary<int, string>

SystemArchetypeTouches

Read-only view of finalized per-(tick, system, archetype) rows.

public IReadOnlyList<SystemArchetypeTouchSummary> SystemArchetypeTouches { get; }

Property Value

IReadOnlyList<SystemArchetypeTouchSummary>

SystemTickSummaries

Read-only view of finalized per-(tick, system) rows.

public IReadOnlyList<SystemTickSummary> SystemTickSummaries { get; }

Property Value

IReadOnlyList<SystemTickSummary>

TickSummaries

Read-only view of finalized tick summaries. Grows over time as the builder finalizes ticks.

public IReadOnlyList<TickSummary> TickSummaries { get; }

Property Value

IReadOnlyList<TickSummary>

TotalEvents

Total event count across all chunks (matches the value reported in TotalEvents).

public long TotalEvents { get; }

Property Value

long

Methods

Build(string, string, IProgress<BuildProgress>)

Static convenience: build a sidecar cache from a trace file in one call. Behavior matches Build(string, string, IProgress<BuildProgress>); this overload is the implementation used by the static façade.

public static TraceFileCacheBuilder.BuildResult Build(string sourcePath, string cachePath, IProgress<TraceFileCacheBuilder.BuildProgress> progress = null)

Parameters

sourcePath string
cachePath string
progress IProgress<TraceFileCacheBuilder.BuildProgress>

Returns

TraceFileCacheBuilder.BuildResult

Dispose()

Disposes the builder. Flushes the trailing tick and any in-progress chunk, then writes the trailer if the sink supports it.

public void Dispose()

FeedRawRecords(ReadOnlySpan<byte>)

Feed one or more raw records (back-to-back, each prefixed with a u16 size) through the builder. Records must be complete — partial records across calls are NOT supported. The format matches the engine's block-frame payload exactly.

public void FeedRawRecords(ReadOnlySpan<byte> records)

Parameters

records ReadOnlySpan<byte>

FinalizePendingState()

Flush trailing tick / in-progress chunk so subsequent trailer writes see a consistent snapshot. Idempotent — safe to call before the live save-as-replay flow takes a snapshot of ChunkManifest + TickSummaries.

public void FinalizePendingState()

FlushCurrentChunk()

Force-flush the current in-progress chunk. Live mode calls this on a 200 ms timer so partial chunks become visible to clients without waiting for the chunk-cap trigger. Mid-tick: opens a new continuation chunk on the next emit.

public bool FlushCurrentChunk()

Returns

bool

FlushTrailingTick()

Finalize the open tick (uses event timestamps to derive durationUs if no TickEnd arrived). Idempotent — safe to call multiple times. Live mode calls this from a 250 ms fallback timer so the latest bar settles even when the next TickStart hasn't arrived yet.

public void FlushTrailingTick()

GetSystemAggregatesSnapshot()

Snapshot of accumulated per-system aggregate durations as a sorted-by-system-index array. Recomputed on each access — caller should cache for hot paths. Used by the live save flow to capture aggregates before disposal.

public SystemAggregateDuration[] GetSystemAggregatesSnapshot()

Returns

SystemAggregateDuration[]

RegisterQueueName(ushort, string)

Register a queue's display name. Idempotent (last write wins). Used only by paths that learn queue identities AFTER the constructor has run — e.g. a live engine that registers a new queue post-handshake. Replay traces hydrate the table via the constructor's queueNames parameter; calling this for those is unnecessary.

public void RegisterQueueName(ushort queueId, string name)

Parameters

queueId ushort
name string

Events

ChunkFlushed

Raised every time a chunk is flushed (added to ChunkManifest). Live mode subscribes; replay ignores.

public event Action<ChunkManifestEntry> ChunkFlushed

Event Type

Action<ChunkManifestEntry>

TickFinalized

Raised every time a tick is finalized (added to TickSummaries). Live mode subscribes; replay ignores.

public event Action<TickSummary> TickFinalized

Event Type

Action<TickSummary>