Class IncrementalCacheBuilder
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
sinkICacheChunkSinkWhere flushed chunks land. FileCacheSink for replay,
AppendOnlyChunkSinkfor live.ownsSinkboolIf
true, the builder disposes the sink in its own Dispose().headerProfilerHeaderSource profiler header (used for
TimestampFrequencyand version stamping).sourceFingerprintReadOnlySpan<byte>32-byte source fingerprint to embed in the cache header. Live: arbitrary 32-byte session ID.
spanNamesIReadOnlyDictionary<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).
queueNamesIReadOnlyDictionary<ushort, string>Queue-id → display-name map from the source's
EventQueueCatalog. Pre-populated for replay traces (the engine writes every queue atInittime, 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 emptyQueueNameTablecache 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
Properties
ChunkManifest
Read-only view of flushed chunks. Grows as the builder flushes chunks.
public IReadOnlyList<ChunkManifestEntry> ChunkManifest { get; }
Property Value
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
FoldedCount
Folded-completion count (kickoff/completion async fold). Mirrors FoldedCount.
public long FoldedCount { get; }
Property Value
PostTickSummaries
Read-only view of finalized per-tick post-tick markers.
public IReadOnlyList<PostTickSummary> PostTickSummaries { get; }
Property Value
PreTickDroppedBytes
Bytes that were dropped because the pre-tick buffer was at PreTickBufferCap. Diagnostic only.
public long PreTickDroppedBytes { get; }
Property Value
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
QueueTickSummaries
Read-only view of finalized per-(tick, queue) rows.
public IReadOnlyList<QueueTickSummary> QueueTickSummaries { get; }
Property Value
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
SystemArchetypeTouches
Read-only view of finalized per-(tick, system, archetype) rows.
public IReadOnlyList<SystemArchetypeTouchSummary> SystemArchetypeTouches { get; }
Property Value
SystemTickSummaries
Read-only view of finalized per-(tick, system) rows.
public IReadOnlyList<SystemTickSummary> SystemTickSummaries { get; }
Property Value
TickSummaries
Read-only view of finalized tick summaries. Grows over time as the builder finalizes ticks.
public IReadOnlyList<TickSummary> TickSummaries { get; }
Property Value
TotalEvents
Total event count across all chunks (matches the value reported in TotalEvents).
public long TotalEvents { get; }
Property Value
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
sourcePathstringcachePathstringprogressIProgress<TraceFileCacheBuilder.BuildProgress>
Returns
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
recordsReadOnlySpan<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
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
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
Events
ChunkFlushed
Raised every time a chunk is flushed (added to ChunkManifest). Live mode subscribes; replay ignores.
public event Action<ChunkManifestEntry> ChunkFlushed
Event Type
TickFinalized
Raised every time a tick is finalized (added to TickSummaries). Live mode subscribes; replay ignores.
public event Action<TickSummary> TickFinalized