Live TCP Streaming Export
Stream a running session over TCP so the Workbench can watch a process tick-by-tick, right now.
Status: โ Implemented ยท Visibility: Public ยท Level: ๐ต Core ยท Category: Profiler
๐ฏ What it solves
Waiting for a process to exit โ or crash โ before you can look at its trace doesn't work when you're chasing a live stall, watching memory climb during a soak test, or want to see a load test's behavior as it happens. Live export lets a Workbench viewer attach directly to a running process's socket and see events arrive as they're produced, with no file round-trip and no restart required.
โ๏ธ How it works (in brief)
TcpExporter listens on one TCP port โ IPv4 loopback unless told otherwise โ and accepts a single client at a
time. On connect it sends an Init frame (the same header + metadata tables as the file format, schema included โ component layouts, archetype
composition, the index catalog, the runtime config, the event-queue catalog and a resource-graph snapshot, so a viewer can name what it is watching)
and then a stream of Block frames, one per drained batch,
LZ4-compressed the same way as file export. It also re-sends a small catch-up frame โ currently-claimed thread
names โ about once a second, so a viewer that attaches mid-session still gets correct lane labels. Sends are
non-blocking: a frame that can't be written immediately is dropped rather than stalling the exporter thread. On
profiler stop, a Shutdown frame closes the session cleanly.
๐ป Usage
// typhon.telemetry.json โ zero code:
// { "Typhon": { "Telemetry": { "Enabled": true,
// "Profiler": { "Enabled": true, "Live": 9100, "LiveWaitMs": 5000 } } } }
using Typhon.Engine;
var runtime = TyphonRuntime.Create(dbe, schedule =>
{
schedule.PublicTrack.DeclareDag("Sim").CallbackSystem("Tick", ctx => RunGameLogic(ctx));
});
// LiveWaitMs > 0 blocks Create() until the first viewer connects (or the timeout elapses).
// ... run the workload; in the Workbench: File โ Connect Live โ "localhost:9100" ...
| Config key | Default | Effect |
|---|---|---|
Typhon:Profiler:Live |
unset (no live export) | TCP port to listen on; any non-numeric value falls back to port 9100 |
Typhon:Profiler:BindAddress |
127.0.0.1 |
Address the listener binds to. Anything else puts the unauthenticated stream on a routable interface โ see Guarantees & limits |
Typhon:Profiler:LiveWaitMs |
0 (don't wait) |
Milliseconds TyphonRuntime.Create blocks waiting for the first viewer to attach before returning |
โ ๏ธ Guarantees & limits
- Loopback by default, and no authentication at all โ the stream carries system, archetype and component
names, query text, timings and thread layout, with no handshake and no credential. Binding beyond
127.0.0.1hands all of that to anyone who can reach the port, so it is opt-in: setBindAddress(or pass--bind-address <addr>) and mean it. Remote profiling of a server process is a real use case; it just has to be asked for rather than inherited. - IPv4 loopback specifically โ the default is
127.0.0.1, not::1. The Workbench's attach path resolves IPv4 only, so a client dialling::1explicitly will not connect. - Single client only โ a second connection attempt while a viewer is attached is rejected outright; run a
second session on a different
Liveport if you need a second observer. - No persistence โ bytes never delivered over this socket cannot be replayed; a live-only session has no
equivalent of the file's completeness. Set both
TraceandLivetogether to keep a durable copy while also watching live. - Drop-on-backpressure, not stall โ a slow client causes individual frames to be dropped
(
SocketError.WouldBlock) rather than backing up the profiler consumer thread; expect gaps in a chronically slow viewer's feed rather than delay. - Silent disconnect handling โ if the viewer's connection drops, the engine keeps running and simply accepts the next client; there's no application-visible error.
LiveWaitMsonly gates startup once โ it blocksTyphonRuntime.Createfor the first connection; a later reconnect after the viewer disconnects does not re-block anything.- Plain TCP, no platform dependency โ works identically on Windows/Linux/macOS, unlike the ETW-based off-CPU scheduling extension.
๐งช Tests
- TcpExporterIntegrationTests โ Init/Block frame round-trip over a loopback socket, plus
LiveWaitMs/live-connect-timeout blocking-vs-non-blocking connect behavior - ProfilerLaunchConfigTests โ that the resolved default really is loopback, that
--bind-addressandTyphon:Profiler:BindAddressare honoured, and that a CLI layer omitting the flag does not erase a bind set in config
๐ Related
- Source:
src/Typhon.Engine/Profiler/internals/TcpExporter.cs - Parent feature: Trace Export
- Sibling: File-Based Trace Export (.typhon-trace) โ the other trace-export sink; both can attach to the same session at once