| Age | Commit message (Collapse) | Author |
|
|
|
|
|
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>
|
|
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>
|
|
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>
|
|
- 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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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.
|
|
|
|
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>
|
|
(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>
|
|
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>
|
|
(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>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|