| Age | Commit message (Collapse) | Author |
|
Add fastRefreshMs parameter to NewModelWithConfig so callers can supply
the high-frequency tick cadence for stream and flame tabs. Convert the
streamTickCmd/flameTickCmd package-level functions to model methods that
honour fastRefreshEvery (falling back to the 200 ms constants when zero
for backward-compatibility). Add SetFastRefreshInterval setter so
RunWithTraceStarterConfig can apply cfg.TUIFastRefreshInterval after
construction. Update all 68 test call sites to pass fastRefreshMs=200
and add three new tests covering zero-fallback, stored value, and setter
behaviour.
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>
|
|
- 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>
|
|
Replace sync.WaitGroup with errgroup.Group in buildSubSnapshots so errors from
sub-builders (buildSyscallSnapshots, buildFileSnapshots, buildProcessSnapshots,
buildHistogramSnapshot) are captured and propagated rather than silently dropped.
Change Engine.Snapshot() to return (*Snapshot, error), update runtime.SnapshotSource
and dashboard.SnapshotSource interfaces accordingly, and adjust all callers in
tui.go, dashboard/model.go, and the test helpers.
Each sub-builder now returns (result, error); the error return is currently
always nil but establishes the contract for future validation. The per-type
Snapshot() convenience methods (histogram, syscall, file, process) panic on
error since they are internal helpers where failure would be a programming bug.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Add var _ Interface = (*ConcreteType)(nil) assertions for:
- *flamegraph.LiveTrie → runtime.{Snapshotter,Configurator,LiveTrieSource}
and tui/flamegraph.{Snapshotter,Configurator,LiveTrieSource}
- *probemanager.Manager → runtime.ProbeManager
- *statsengine.Engine → runtime.SnapshotSource
- *streamrow.RingBuffer → runtime.EventSink
- *runtimeBindings (tui) → runtime.TraceRuntimeBindings
- *lateBoundDashboardSource → dashboard.SnapshotSource
- libbpfTracepointProgram/Module → probemanager.{Program,Attacher}
Assertions are grouped close to their interface definitions to avoid
introducing new import cycles (runtime already imports all affected
packages; tui/flamegraph already imports coreflamegraph).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Split the 1389-line tui.go Model into three focused sub-controllers
that each own a single concern:
- filterstack.go (filterStack): owns the filter chain, undo history,
and label stack; provides push/pop/rebindProcessFilters API so the
Model never manipulates filter slices directly.
- tracelifecycle.go (traceLifecycle): owns trace start/stop and the
active context.CancelFunc; provides beginCmd/stop API; also houses
the recorder helpers (recorderStart/Stop/Active/Status) and the
auto-reset cycle logic (nextAutoResetInterval, autoResetCycle).
- screenrouter.go (screenRouter): owns the picker-return bookmark
(pickerReturn) and the applyWindowSizeToPicker helper so screen
transition code in tui.go delegates to it.
The Model.Update switch is split into dispatchTypedMsg (framework
messages) and dispatchAppMsg (app messages) to keep each helper
under the 50-line limit. View is split into viewPickerScreen and
viewDashboardScreen for the same reason.
All functions are ≤50 lines. go test ./internal/tui/... passes.
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>
|
|
Extract handleHelpOverlayKeyPress, handleQuitKeyPress, routeQuitAsEsc, and
handleDashboardShortcutKeys from the 89-line handleGlobalKeyPress to comply
with the project's 50-line function limit. All existing behaviour is preserved.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Two follow-up refinements to the auto-reset timer added in 8da473a.
- Hotkey cycle now goes off -> 10s -> 30s -> 60s -> 2m -> 5m -> off,
giving the user finer control between 60s and 5m and a quicker
starting cadence.
- The timer now pauses while the TUI is blurred. SetFocused returns a
tea.Cmd that re-arms a fresh tick on focus regain, and bumps the
generation counter on every focus change so any tick scheduled before
blur is dropped on arrival. autoResetTickCmd and handleAutoResetTick
also gate on m.focused as defense in depth.
- Dashboard chrome shows 'auto-reset: 30s (paused)' while the timer is
enabled but blurred, distinguishing it from the disabled 'off' state.
Tests cover the full preset cycle (including custom-value passthrough)
and the pause-on-blur lifecycle: stale ticks ignored, current-gen ticks
ignored while blurred, focus regain re-arms and fires the reset, no-op
focus calls don't churn the generation counter, and the chrome label
flips to '(paused)' as expected.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
|
Live flamegraph trie and stats engine grow unboundedly during long
traces. Add a periodic auto-reset (same effect as the 'r' key) so they
stay bounded.
- New CLI flag -resetTimer=30s (default 30s, 0 disables).
- Hotkey I cycles the cadence: off -> 15s -> 30s -> 60s -> 5m -> off.
Custom intervals (e.g. -resetTimer=47s) advance to the first preset
greater than the current value, then wrap to off.
- autoResetTickMsg carries a generation counter so changing the cadence
drops in-flight ticks scheduled under the previous interval.
- Dashboard chrome shows 'auto-reset: 30s' or 'auto-reset: off'.
|
|
PrepareForTraceRestart was designed for the full-restart path, where the
dashboard's live-trie reference is rebound when TracingStartedMsg fires.
The in-place filter swap skips that message, leaving the flamegraph tab
stuck on 'Flame: waiting for data...' until the next real trace restart.
Re-bind via SetLiveTrie immediately after PrepareForTraceRestart in both
applyGlobalFilter and undoGlobalFilter.
|
|
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.
|
|
tui.Model (task 429)
tui.Model had 33 fields mixing keyboard tracking, filter chain, process
selection, and UI presentation concerns (SRP violation).
Extract three focused sub-structs:
- keyboardState (kb): enhancements, lastEvent{ID,At,WasPress},
suppress{ID,Until} — 7 fields managed by keys_normalize.go
- filterState (filter): global filter, history slice, label stack
— 3 fields for the trace filter chain
- processState (proc): pid, tid, pickerReturn
— 3 fields for PID/TID selection and picker navigation
Model drops from 33 to 23 top-level fields. All field accesses in
tui.go, keys_normalize.go, and tui_test.go are updated accordingly.
Co-Authored-By: Claude Sonnet 4.6 (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>
|
|
(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>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|