summaryrefslogtreecommitdiff
path: root/internal/ior.go
AgeCommit message (Collapse)Author
2026-05-20fix(task-17): prevent aggregate double-count and flush on shutdownPaul Buetow
2026-05-20feat: add syscall aggregate sampling infrastructure (task 17)Paul Buetow
2026-05-13refactor: break down functions exceeding 50 lines into smaller helpersPaul Buetow
Split 22 production files across the codebase — event loop, TUI models, probe manager, dashboard, export, flag parsing, code generation, and ioworkload scenarios — so that no function body exceeds 50 lines. Each extracted helper carries its own comment explaining its role. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13introduce Accumulator interface in statsengine to separate ingestion from ↵Paul Buetow
snapshot-building Define statsengine.Accumulator (Ingest + Reset) to represent the event-accumulation responsibility separately from runtime.SnapshotSource (Snapshot), which handles the read side. This reduces the SRP violation in Engine: callers that only push events now hold an Accumulator; callers that only read statistics hold a SnapshotSource. - Add Accumulator interface and compile-time assertion in statsengine/engine.go - Add EventIngester type alias (= statsengine.Accumulator) in runtime/runtime.go with a compile-time assertion, so callers in the runtime layer can reference the ingestion contract without importing statsengine directly - Split tuiRuntime.engine field into accumulator + snapSource so the event-loop callback holds Accumulator and wireRuntimeBindings passes SnapshotSource to SetDashboardSnapshotSource — making each consumer's dependency explicit - Simplify resetDashboardSnapshotSource in tui.go to cast for interface{ Reset() } independently of Snapshot(), removing the combined ad-hoc interface check Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13fix: stop BPF ring-buffer polling goroutine on trace end to prevent leakPaul Buetow
setupEventChannel now returns the *bpf.RingBuffer handle alongside the event channel. Both callers (runTraceWithContext, runHeadlessParquet) defer rb.Stop() so the libbpfgo polling goroutine and C ring_buffer struct are released promptly when the trace context is cancelled, rather than waiting for bpfModule.Close() to eventually call rb.Close(). rb.Stop() and rb.Close() are both idempotent, so the double-call from the defer and from bpfModule.Close() is safe. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13refactor: move TraceFilter and tracepoint selector logic out of flags.ConfigPaul Buetow
- Add tracepoints.Selector type with ShouldAttach method and ParseSelector constructor, replacing the raw TracepointsToAttach/TracepointsToExclude regex slices on flags.Config. - Add flags.BuildTraceFilter as a standalone function replacing the Config.TraceFilter() method, keeping filter-building logic out of the config struct. - Remove stale ShouldIAttachTracepoint noise-filter entry from Magefile. - Add selector_test.go with full coverage of ParseSelector and ShouldAttach. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13fix: avoid int64->int truncation in NumericFilter.EqValue on 32-bit archPaul Buetow
EqValue() previously returned int, silently truncating int64 values that exceed math.MaxInt32 on 32-bit architectures. Change the return type to int64 and update callers (ior.go, filterstack.go) with explicit int() casts that are safe because Linux PID/TID values never exceed 4194304. Add TestEqValueReturnsInt64PreservesLargeValues to guard the fix. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13fix: prevent goroutine leak in tuiTraceStarterFromRunTrace via done channelPaul Buetow
Replace the buffered errCh (capacity 1) with an unbuffered channel plus a dedicated done channel that is closed via defer when the outer function returns for any reason (ctx cancellation, startedCh signal, or startup error). The trace goroutine selects on both errCh and done when delivering its result, guaranteeing it can always exit and is never left blocked waiting on a channel that nobody will drain. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13fix: log swallowed defer mgr.Close errors for BPF resourcesPaul Buetow
Wrap the bare `defer mgr.Close()` calls in runTraceWithContext (ior.go) and runHeadlessParquet (ior_parquet_sink.go) in a closure that checks the returned error and logs it via logln, so BPF probe-detach failures and map-cleanup errors are no longer silently discarded. bpfModule.Close() has no return value and is unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13replace package-level test doubles in ior.go with constructor injection (DIP)Paul Buetow
Introduce runnerDeps struct to bundle all injectable function dependencies (getEUID, runTrace, runParquet, runTraceWithContext, runTUI*) that were previously package-level vars overridden in tests. The modeRegistry now carries a runnerDeps instance and passes it to each handler's run() method, eliminating global state mutation in tests. - Add runnerDeps struct and defaultRunnerDeps() constructor in ior_mode_registry.go - Convert modeRegistry from a []modeHandler slice type to a struct with handlers + deps fields; add newModeRegistry(deps) constructor - Update modeHandler.run() signature to accept runnerDeps; handlers call deps.getEUID / deps.runTrace etc. instead of globals - Update SetTUIRunners to write into defaultRegistry.deps instead of package-level vars - Add dispatchRunWithDeps helper for test isolation without global mutation - Remove root-privilege check from runTraceWithContext and runHeadlessParquet; each mode handler owns the EUID gate via deps.getEUID - Rewrite ior_mode_test.go: replace save/restore patterns with stubDeps() helper and dispatchRunWithDeps; add three new root-privilege tests replacing the removed TestRunTraceWithContextRequiresRoot Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12refactor dispatchRun/validateRunConfig into ModeRegistry for OCP compliancePaul Buetow
Introduce a ModeRegistry pattern so new execution modes can be added without modifying the dispatch or validation switch/if chains. Each mode is a self-contained modeHandler (match + validate + run); the ordered defaultRegistry replaces the open if-chains in dispatchRun and validateRunConfig, which become thin wrappers. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12introduce RuntimeBuilder to separate construction from orchestration in ior.goPaul Buetow
RuntimeBuilder encapsulates allocation of per-trace-session components (statsengine.Engine, streamrow.RingBuffer, Sequencer, flamegraph.LiveTrie); buildTUIRuntime, buildTestFlamesRuntime, and buildTestLiveFlamesRuntime now delegate construction to RuntimeBuilder.Build() and focus only on wiring. wireRuntimeBindings is extracted to isolate the context-binding wiring step. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12invert dependency: internal no longer imports internal/tuiPaul Buetow
Introduce internal/runtime as a neutral contract package that both the core engine (internal) and the TUI layer (internal/tui) depend on. - internal/runtime: defines TraceStarter, StreamSource, EventSink, LiveTrieSource, SnapshotSource, ProbeManager, RuntimePublisher, RuntimeState, TraceRuntimeBindings, and all context key/helper functions (RuntimeBindingsFromContext, RuntimePublisherFromContext, ContextWithRuntimeBindings, ContextWithTraceFilters, TraceFiltersFromContext). These were previously defined in internal/tui, forcing the core package to import the TUI layer. - internal/streamrow: add RingBuffer (moved from internal/tui/eventstream) so the core tracing engine can use the ring buffer without importing the TUI layer. - internal/tui/eventstream/ringbuffer.go: change to a thin re-export of streamrow.RingBuffer via a type alias, preserving the existing API for all callers within the TUI layer. - internal/tui/tui.go: replace locally-defined interface declarations (TraceStarter, SnapshotSource, ProbeManager, RuntimePublisher, RuntimeState, TraceRuntimeBindings) with type aliases from internal/runtime. Delegate all context helper functions to runtime. - internal/ior.go, internal/ior_bpfsetup.go: remove imports of internal/tui and internal/tui/eventstream; use internal/runtime and internal/streamrow instead. Add SetTUIRunners injection point so the concrete TUI runner functions are wired in by cmd/ior/main.go. - cmd/ior/main.go: call internal.SetTUIRunners with the concrete TUI runner functions before internal.Run, completing the wiring without creating a cycle. - Test files (internal/ior_mode_test.go, internal/bench_pipeline_test.go): updated to use runtime.* and streamrow.* types in place of tui.* and eventstream.* types. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12refactor tuiTraceStarterFromRunTrace and runTraceWithContext to comply with ↵Paul Buetow
50-line limit Extract buildTUIRuntime and makeTUIEventLoopConfigurer from the monolithic tuiTraceStarterFromRunTrace closure, and extract maybePrependFlamegraphConfigure and finaliseTrace from runTraceWithContext. All functions are now <= 50 lines. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08swap global filter in place to skip BPF reattachPaul Buetow
Changing the global filter used to call stopTrace + beginTraceCmd, which detached and re-attached every tracepoint and re-loaded the BPF object. On heavily loaded I/O systems that took several seconds and showed an 'Attaching tracepoints...' overlay each time. The probe set never depends on the global filter (ShouldIAttachTracepoint only reads CLI regex flags), so the restart was gratuitous. Now the eventloop holds its filter behind atomic.Pointer with SetFilter / Filter accessors, and the trace starter registers el.SetFilter via the runtime bindings as a SetLiveFilterSetter callback. applyGlobalFilter and undoGlobalFilter call runtime.applyLiveFilter first; only if no trace is running do they fall back to the full restart path.
2026-05-07update docs and ascii bannerPaul Buetow
2026-04-24fix task 38: plug profiling fd leak on setup failure pathsPaul Buetow
runTraceWithContext and runHeadlessParquet opened cpu/mem/exec-trace profile files via setupProfiling, then relied on the shutdown watcher goroutine (registered later) to close them. If any intervening step (newEventLoop, recorder.Start) returned an error, the watcher was never registered and the profile fds leaked until process exit. Add a defer profiling.stop(logln) immediately after setupProfiling so the fds are released on every return path. profiling.stop is idempotent via sync.Once so the watcher and defer can both run harmlessly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-03-18refactor: split TraceRuntimeBindings into RuntimePublisher and RuntimeState ↵Paul Buetow
(task 427/ISP) TraceRuntimeBindings mixed 4 setter methods (injecting data into TUI) with 4 getter methods (reading persistent TUI-owned state), violating ISP. Split into two focused interfaces: - RuntimePublisher: SetDashboardSnapshotSource, SetEventStreamSource, SetLiveTrie, SetProbeManager — the write/inject side - RuntimeState: StreamBuffer, Recorder, StreamSequencer, FilterEpoch — the read/persistent-state side TraceRuntimeBindings now embeds both, preserving all existing call sites. RuntimePublisherFromContext() added so callers that only inject data do not see the getter surface. Three such callers are narrowed: setupBPFModule, tuiTestFlamesStarter, tuiTestLiveFlamesStarter. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-03-18refactor: split ior.go mega-file into focused files (task 427)Paul Buetow
ior.go had 763 lines covering 9+ concerns. Follow the eventloop_*.go pattern and extract into three focused files: - ior_bpfsetup.go: libbpfTracepoint{Program,Module} adapter types, setupBPFModule, setupBPFModuleError, setupEventChannel - ior_profiling.go: profilingControl type, setupProfiling, profilingFilesForMode, stop() - ior_parquet_sink.go: headlessParquetSink type, runHeadlessParquet, isHeadlessParquetMode, hasHeadlessParquetContentFilters, headlessParquetTraceConfig; inline parquetMetadata one-liner ior.go shrinks from 763 → 453 lines, retaining entry, dispatch, TUI wiring, and core trace execution. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-03-18refactor: pass flags.Config explicitly, remove flags.Get() from library code ↵Paul Buetow
(task 429) flags.Get() (global mutable singleton) was called inside library packages, coupling them to global state and making tests fragile (DIP violation). - internal.Run() now takes an explicit flags.Config; main.go calls flags.Get() once at the CLI boundary and passes it in. - tui.Run(), RunWithTraceStarter(), RunTestFlamesWithTraceStarter() removed; callers already used the WithConfig variants directly. - tui.NewModel() preserved for test ergonomics but now uses flags.NewFlags() (pure defaults) instead of flags.Get() (global state). - Tests updated to use NewModelWithConfig() with explicit config structs instead of flags.Set*() + NewModel(), eliminating all test-level global-state mutation. flags.Get() is now called only in cmd/ior/main.go, the correct boundary. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-03-13perf: remove tui stream relay channelPaul Buetow
2026-03-13feat: add headless parquet recording modePaul Buetow
2026-03-12feat: persist parquet recording across TUI restartsPaul Buetow
2026-03-12refactor: extract shared syscall stream row modelPaul Buetow
2026-03-12fix: restore legacy flamegraph trace output modePaul Buetow
2026-03-12internal: embed BPF object into ior binaryPaul Buetow
2026-03-10config: centralize default buffer sizes (task 388)Paul Buetow
2026-03-10tui: hide stream buffer behind source interface (task 428)Paul Buetow
2026-03-10task 434: unify trace filter plumbingPaul Buetow
2026-03-10task 433: lock in pair recycle safetyPaul Buetow
2026-03-10internal: add context to BPF setup failures (task 416)Paul Buetow
2026-03-08task 373: preserve stream history across filter restartPaul Buetow
2026-03-08task 368: filter live pairs before TUI ingestionPaul Buetow
2026-03-08task 367: carry full trace filters through TUI contextPaul Buetow
2026-03-06refactor: rename flags.Flags to flags.Config (task 383)Paul Buetow
2026-03-06refactor: make livetrie caller-owned for pair recycling (task 382)Paul Buetow
2026-03-06refactor: remove dead tracepoint attach abstractions (task 383)Paul Buetow
2026-03-06refactor: decompose runTraceWithContext orchestration (task 388)Paul Buetow
2026-03-06refactor: thread runtime flags through ior and tui (task 385)Paul Buetow
2026-03-06fix: preserve error chains in tracepoint attach (task 384)Paul Buetow
2026-03-06fix: return errors for invalid event filters (task 382)Paul Buetow
2026-03-06refactor: remove web flamegrapher and keep TUI-onlyPaul Buetow
2026-03-06Add live flamegraph test modes and dynamic synthetic live feedPaul Buetow
2026-03-05Enable TUI-mode pprof artifacts and trace capturePaul Buetow
2026-03-05task 353: wire LiveTrie into TUI trace startupPaul Buetow
2026-03-03Add watch mode for dynamic flamegraph updatesPaul Buetow
2026-03-03Add WASM-ready flamegraph JSON exportPaul Buetow
2026-03-02Make --open a command template with no defaultsPaul Buetow
2026-03-02Add --open support for live flamegraph browser launchPaul Buetow
2026-03-02Replace TUI service-locator globals with runtime bindingsPaul Buetow