summaryrefslogtreecommitdiff
AgeCommit message (Collapse)Author
2026-05-13fix: use shell-aware tokenizer in resolveEditorCommand to handle EDITOR ↵Paul Buetow
paths with spaces Replace strings.Fields with a new shellSplit function that implements POSIX-like quoting rules (single-quotes, double-quotes, backslash escapes), so EDITOR values such as '/My Editor/hx' or "/path/with spaces/hx" --wait are correctly parsed rather than mangled into multiple path components. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13fix: reject negative and zero -duration flag values with a clear errorPaul Buetow
A negative or zero -duration was silently accepted, causing the trace context to be cancelled immediately (time.Duration(N) * time.Second with N <= 0 yields a non-positive timeout), so no events were ever captured. parseFromFlagSet now returns an error for Duration <= 0, matching the existing pattern used for -resetTimer validation. Three new tests cover the negative, zero, and valid positive cases. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13fix: guard Pair.CalculateDurations against uint64 underflow on clock skewPaul Buetow
BPF timestamps can be non-monotonic across CPUs (NTP step, TSC skew). When exit < enter or enter < prevPairTime the uint64 subtraction wraps to a huge value, corrupting latency histograms and flamegraph weights. Clamp both Duration and DurationToPrev to 0 instead of underflowing. Add TestPairCalculateDurationsNegativeDelta to cover this case. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13fix: add 1s context timeout to commResolver procfs reads to prevent ↵Paul Buetow
indefinite blocking Frozen cgroup entries in /proc could stall a lookup worker goroutine forever, preventing clean shutdown because shutdown() waits on workersWG.Wait(). Changed resolveFn signature to accept context.Context and wrap each call in context.WithTimeout(1s) in both lookupWorker and seedTrackedPidComm. Added TestCommResolverLookupWorkerRespectsTimeout to verify the pending entry is cleared after a timeout. 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-13fix: wrap SetMaxEntries and GetMap errors in resizeBPFMap with map name contextPaul Buetow
Raw errors from GetMap and SetMaxEntries gave no indication of which BPF map failed. Wrap both with fmt.Errorf including the map name (and target size for SetMaxEntries) so callers can immediately identify the offending map. Also simplify resizeBPFMaps to return directly since resizeBPFMap now carries full context, removing the redundant outer wrap. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13fix: add 30s startup timeout to startTraceCmd to prevent indefinite hang on ↵Paul Buetow
BPF attach failure If kernel lock contention or another issue causes BPF probe attachment to stall, the TUI previously remained in the 'Attaching tracepoints...' spinner state forever. startTraceCmdWithTimeout now races the starter goroutine against a configurable deadline (defaultStartupTimeout = 30s) and returns a TracingErrorMsg with a clear message when the deadline expires. The stuck goroutine is cleaned up when the caller cancels the trace context on the next user action (e.g. traceLifecycle.stop). Two new tests cover the timeout and context-cancel paths. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13fix: log pprof.WriteHeapProfile error instead of silently ignoring itPaul Buetow
Silent disk-full or permission-denied failures when writing the heap profile are now surfaced via logln so the operator can diagnose them. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13replace panic with os.Exit and error log in cmd/filewriterPaul Buetow
Panics in non-setup code violate the AGENTS.md convention. Replace all three panic(err) calls with fmt.Fprintf(os.Stderr, ...) + os.Exit(1) so the process exits cleanly with a human-readable message instead of a stack trace. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13fix ignored file.Close error in iordata serialization error pathPaul Buetow
On serialization failure the deferred close was called but its error silently discarded, potentially masking filesystem issues such as a full-disk condition detected only at close time. Capture the close error and join it with the existing retErr via errors.Join so callers see the full picture. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13Revert "fix: surface rb.Poll errors instead of silently dropping them"Paul Buetow
This reverts commit 66956756ba018ed32a455aa57f04517af2c7357f.
2026-05-13fix: surface rb.Poll errors instead of silently dropping themPaul Buetow
The libbpfgo RingBuffer.Poll() previously launched a background goroutine that could fail with a fatal C-level errno (e.g. EBADF, EPERM) and silently exit, causing BPF events to stop flowing with no diagnostic. Changes: - Patch ../libbpfgo (replace directive) so RingBuffer.Poll() returns a buffered <-chan error that the background goroutine sends to on failure. - In setupEventChannel, capture the error channel and spawn a monitoring goroutine that logs any poll error to stderr. - Update go.mod with the replace directive and drop the now-unused remote checksum entries from go.sum. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13split globalfilter presentation and parsing into sub-packagesPaul Buetow
Move ParseDurationNs to globalfilter/parser and move CompareOpSymbol, AppendStringSummary, AppendNumericSummary, FilterSummary to globalfilter/presenter. The domain Filter type retains only matching, equality, clone, and active-predicate logic. All callers updated; tests for the new sub-packages added. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13replace global flags singleton with Parse() returning Config valuePaul Buetow
Remove the global atomic.Pointer[Config], sync.Once, and parseErr fields from the flags package. Parse() now returns (Config, error) directly, eliminating all global-state accessors (Get, SetPidFilter, SetTidFilter, SetTUIExportEnable, setCurrent, updateCurrent). The internal parse logic is factored into parseFromFlagSet so tests can inject a fresh FlagSet without touching os.Args or package-level state. 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-13unify filter summary rendering by reusing globalfilter helpersPaul Buetow
Export AppendStringSummary and AppendNumericSummary from globalfilter so filterstack.go can delegate to the canonical token-formatting logic instead of reimplementing fmt.Sprintf("%s~%s") and fmt.Sprintf("%sOP%s") in appendStringFilterChange / appendNumericFilterChange. Drop the now-unused fmt, strconv, and time imports from filterstack.go. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12extract generic trimLRU helper to eliminate DRY violation in eventloop_state.goPaul Buetow
Replace three near-identical trimOldest* functions with a single generic trimLRU[K comparable, V any] helper; the three wrappers now delegate to it, with trimOldestPendingPairs passing a cleanup callback for Recycle. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12add DefaultTopN constant to statsengine and replace hard-coded 64 capacity ↵Paul Buetow
values Introduces statsengine.DefaultTopN = 64 as the canonical named constant for the top-N capacity used when constructing an Engine. Removes the local defaultEngineCapacity constant from runtime_builder.go and updates all call sites to reference statsengine.DefaultTopN instead of bare 64. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12add compile-time interface satisfaction assertions for public typesPaul Buetow
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>
2026-05-12rename ShouldIAttachTracepoint receiver from flags to fPaul Buetow
The receiver name flags shadowed the package name flags, making the package inaccessible inside the method body. Rename to f to match all other receivers in flags.go and add a doc comment. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12add Go doc comments to exported fields on flags.Config and globalfilter.FilterPaul Buetow
Document every exported field in Config (flags package) and Filter, NumericFilter, StringFilter (globalfilter package) with a concise one-line doc comment describing its purpose and behaviour. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12split LiveTrieSource into Snapshotter and Configurator (ISP)Paul Buetow
Applies the Interface Segregation Principle to LiveTrieSource in both internal/runtime and internal/tui/flamegraph. The monolithic interface is replaced by two focused sub-interfaces — Snapshotter (read-only: Version, SnapshotJSON, SnapshotTree) and Configurator (mutating: Fields, CountField, Reconfigure, SetCountField, Reset) — which LiveTrieSource then embeds so all existing consumers continue to compile unchanged. The buildSnapshotMsg helper is narrowed to Snapshotter since it only reads snapshot data, preventing accidental mutation from the background goroutine. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12extract dashboard tab framework into Tab registry for OCP compliancePaul Buetow
Introduce tabDescriptor struct and tabDescriptors map in new tabregistry.go. Each tab registers its name, short name, ordered position, allowed viz modes, render function, scroll handler, and optional init tick command. Adding a new tab now requires only a single registry entry — no existing switch/if chains need editing. Key changes: - Tab.String() and tabLabel() use lookupTab() instead of a switch - renderActiveTabContent() dispatches via d.Render (replaces renderActiveTab switch) - handleScrollKey() dispatches via d.HandleScroll (replaces tab switch) - Init() and postKeyTransitionCmd() use d.InitCmd (replaces stream/flame tab checks) - allowedVizModes() delegates to tabAllowedVizModes() from registry - orderedTabs() replaces hardcoded allTabs slice, derived from Position field - bubbleChartFor() helper eliminates 5 repeated switch-on-tab for chart ops - toggleBubbleMetric, tickActiveBubbleChart, moveBubbleSelection, activeBubbleChartHasNodes all use bubbleChartFor() - refreshBubbleData split into two focused functions under 50 lines - Two pre-existing test functions over 50 lines refactored All tests pass; go build ./internal/tui/... clean. 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-12extract TUI Model god class into focused sub-controllersPaul Buetow
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>
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-12refactor flamegraph TUI model into focused sub-controllersPaul Buetow
Break the god-class Model in internal/tui/flamegraph/model.go into four focused sub-controllers that each own a single concern: - ZoomNavigator : zoom path, stack, root node, and reset/undo logic - SelectionManager: selected frame index, clamp, traversal, navigation - FrameAnimator : spring animation, frame layout swap, ancestry index - SearchController: search query, match indices, filter-visible set All four are embedded in Model so existing field access (m.selectedIdx, m.zoomPath, etc.) is promoted unchanged, keeping tests and callers intact. Model methods now delegate to the sub-controllers rather than holding all logic inline. Also split RenderTerminalView (88 lines) into computeRenderParams, buildToolbar, buildFilteredStatus, and buildNormalStatus helpers, and extracted buildSnapshotMsg from RefreshFromLiveTrieCmd. All functions are now ≤ 50 lines. All tests pass. 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 renderActiveContent to stay under 50-line limitPaul Buetow
Extract renderActiveContentViz (treemap/icicle/bubble dispatch) and renderActiveContentTable (table-with-sort dispatch) from the original 56-line renderActiveContent, reducing it to 15 lines of code. 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-12refactor: split handleGlobalKeyPress into focused helpers under 50 linesPaul Buetow
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>
2026-05-12refactor: split Snapshot in statsengine to comply with 50-line limitPaul Buetow
Extract captureSnapshotInputs (lock-guarded state copy), buildSubSnapshots (concurrent per-category builders), and populateSnapshotFields (scalar field assignment) from the monolithic Snapshot method. The method itself is now 18 lines; all three helpers are well under 30 lines each. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12refactor Magefile: split runGoTestWithProgress and runParquetChecks below ↵Paul Buetow
50-line limit Extract buildGoTestCmd, startProgressTicker, and drainTestEvents from runGoTestWithProgress; extract parquetSchemaCheck, parquetRowCountCheck, and parquetSanityCheck from runParquetChecks. All six new helpers and both top-level functions are now well under 50 lines. No behavior changed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12refactor flamegraph model.go: split Update and frameIndexAt below 50-line limitPaul Buetow
Extract handleSearchInput and handleKeyNavigation from Update (111 lines → 33), then split handleKeyNavigation into handleModeKey and handleMovementKey. Extract frameCoordToTargetRow and findFrameAtRow from frameIndexAt (66 lines → 32). All new helpers are ≤ 29 lines; behavior is preserved. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11speed up flame graph TUI under heavy event loadPaul Buetow
Move the per-tick snapshot refresh off the Bubble Tea update goroutine, add a frame ancestry index so navigation and filter helpers run in O(subtree) instead of O(frames), skip refresh and animation while the user is actively pressing keys, and memoize View() output. Keystrokes (pause, filter, navigate) now land within one frame even when the live trie ingests thousands of events per tick. - new SnapshotTree() on LiveTrie bypasses JSON marshal+unmarshal - RefreshFromLiveTrieCmd runs SnapshotTree + layout + ancestry on a background goroutine, coalesced via refreshInFlight, and returns a flameSnapshotReadyMsg the Update loop applies cheaply - driveWindow gate (250 ms after last key press) skips refresh dispatch and snaps frames directly to target without animation while the user is driving - View() caches its rendered string keyed on the inputs that affect output; cache is bypassed during animation Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09show auto-reset countdown and document the cyclePaul Buetow
Renders the next-tick countdown ("12s/30s") in the dashboard chrome so users can see when aggregates will clear, and adds a dedicated H-help line spelling out the cycle keys (off → 10s → 30s → 1m → 2m → 5m). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09refine auto-reset timer cycle and pause on blurPaul Buetow
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>
2026-05-09add auto-reset timer for dashboard aggregatesPaul Buetow
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'.
2026-05-08reconnect flamegraph live trie after in-place filter swapPaul Buetow
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.
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-08add duration metric, tolerate missing tracepoints, ship el8 buildPaul Buetow
- Bubbles, treemap, icicle, and the live flamegraph 'b' cycle now include syscall duration (sum) as a third metric alongside events and bytes. Statsengine snapshots expose TotalLatencyNs to support this. - AttachAll takes an optional warn callback. Production passes one so older kernels that lack newer tracepoints log a warning and keep going instead of aborting startup. - Dockerfile.el8 + scripts/build-with-docker-el8.sh + mage buildDockerEl8 produce ior.el8, a static binary built against Rocky Linux 8 glibc for RHEL/Rocky/Alma 8 hosts. - README.md documents installing mage and the new el8 target.
2026-05-07add link to blog post seriesPaul Buetow
2026-05-07release 1.0.0v1.0.0Paul Buetow
2026-05-07update docs and ascii bannerPaul Buetow
2026-05-06pin Docker build to linux/amd64 for cross-compilationPaul Buetow
Adds --platform=linux/amd64 to the Dockerfile FROM directive and to the docker build/run invocations in scripts/build-with-docker.sh so the ior binary is always cross-compiled for amd64 regardless of host arch.
2026-05-06updatesPaul Buetow
2026-05-06fixPaul Buetow
2026-05-06move demo/ to docs/tutorial/, commit assets, consolidate TUI docsPaul Buetow
- demo/ renamed to docs/tutorial/ (tapes, scripts, TUTORIAL.md) - docs/tutorial/assets/ added to git (51 MB of GIFs + PNGs); removed /demo/assets/ from .gitignore so images render on Codeberg - docs/tui-reference.md removed; its hotkey tables merged into a new "Hotkey Quick Reference" section at the end of TUTORIAL.md - TUTORIAL.md: updated install section (mage buildDocker, no GOTOOLCHAIN=auto), fixed README relative path (../../README.md), updated internal tapes/scripts/assets path prose - README.md: updated all demo/ image paths and links to docs/tutorial/; TUI and recording-modes links now point to TUTORIAL.md anchors - AGENTS.md: updated demo/ references to docs/tutorial/ - Magefile.go: updated demoDir/demoTapesDir/demoScriptsDir/demoRunTape/ demoSudoKeepers constants to docs/tutorial/ paths Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06add Dockerfile and Rocky Linux 9 build docsPaul Buetow
Introduces a Docker-based build path so ior can be compiled on any Linux host without a native Rocky 9 toolchain setup: - Dockerfile: Rocky 9 minimal image with Go (version from ARG, default from go.mod), static libelf/libzstd built from source, libbpfgo at v0.9.2-libbpf-1.5.1, and mage; CMD runs mage generate + mage all against the repo root mounted as a volume. - scripts/build-with-docker.sh: reads GO_VERSION from go.mod, passes it as --build-arg to docker build, mounts tracefs and BTF into the container, writes the binary to the repo root. - Magefile.go: adds BuildDocker target that wraps the script. - README.md: simplified to the two build paths (Docker + native) with links to docs/; removed GOTOOLCHAIN=auto throughout. - docs/build-rocky-linux-9.md: full manual Rocky 9 steps, libbpfgo toolchain setup/rollback, compile-once-run-everywhere explanation, and timing semantics. - docs/tui-reference.md: complete TUI hotkey reference, recording mode details, and the .ior.zst vs Parquet trade-off table. - AGENTS.md: removed GOTOOLCHAIN=auto from all build commands. - internal/c/generated_tracepoints.c: regenerated against the host kernel. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02add demo sources: VHS tapes, helper scripts, and tutorialPaul Buetow
Tracks the inputs that drive `mage demo` so the GIFs and screenshots under demo/assets/ can be reproduced from a checkout. The generated assets themselves (~50 MB of GIFs and PNGs) are excluded via gitignore since they're fully reproducible from the tapes in ~10 min. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>