diff options
| author | Paul Buetow <paul@buetow.org> | 2026-02-24 08:45:38 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-02-24 08:45:38 +0200 |
| commit | e5116514c33b2fce6ce2fc7904d6720c5236221f (patch) | |
| tree | e5bc8c9ba37836305ec1d095573535fb8344cbe7 /internal/tui/tui.go | |
| parent | b01e24374398eb3d343e9472f3262668039db56c (diff) | |
tui: wire eventloop stats engine into dashboard snapshots
Diffstat (limited to 'internal/tui/tui.go')
| -rw-r--r-- | internal/tui/tui.go | 62 |
1 files changed, 58 insertions, 4 deletions
diff --git a/internal/tui/tui.go b/internal/tui/tui.go index 49d2365..b54875a 100644 --- a/internal/tui/tui.go +++ b/internal/tui/tui.go @@ -5,7 +5,10 @@ import ( "errors" "fmt" "ior/internal/flags" + "ior/internal/statsengine" "ior/internal/tui/pidpicker" + "sync" + "time" "github.com/charmbracelet/bubbles/key" "github.com/charmbracelet/bubbles/spinner" @@ -26,6 +29,30 @@ const ( // Long-lived tracing work should continue in background goroutines. type TraceStarter func(context.Context) error +type snapshotSource interface { + Snapshot() *statsengine.Snapshot +} + +type dashboardTickMsg struct{} + +var dashboardSourceState struct { + mu sync.RWMutex + source snapshotSource +} + +// SetDashboardSnapshotSource sets the snapshot source used by dashboard mode. +func SetDashboardSnapshotSource(source snapshotSource) { + dashboardSourceState.mu.Lock() + dashboardSourceState.source = source + dashboardSourceState.mu.Unlock() +} + +func getDashboardSnapshotSource() snapshotSource { + dashboardSourceState.mu.RLock() + defer dashboardSourceState.mu.RUnlock() + return dashboardSourceState.source +} + // Run starts the TUI program in alternate screen mode. func Run() error { return RunWithTraceStarter(defaultTraceStarter) @@ -70,7 +97,7 @@ func NewModel(initialPID int, startTrace TraceStarter) Model { model := Model{ screen: ScreenPIDPicker, pidPicker: pidpicker.New(), - dashboard: newDashboardModel(), + dashboard: newDashboardModel(getDashboardSnapshotSource()), keys: Keys, spin: spin, startTrace: startTrace, @@ -111,11 +138,14 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m.handlePidSelected(msg) case TracingStartedMsg: m.attaching = false - return m, nil + return m, dashboardTickCmd() case TracingErrorMsg: m.attaching = false m.lastErr = msg.Err return m, nil + case dashboardTickMsg: + m.dashboard.refresh() + return m, dashboardTickCmd() } if m.attaching { @@ -216,10 +246,15 @@ func (m Model) View() string { type dashboardModel struct { selectedPID int + source snapshotSource + latest *statsengine.Snapshot } -func newDashboardModel() dashboardModel { - return dashboardModel{selectedPID: -1} +func newDashboardModel(source snapshotSource) dashboardModel { + return dashboardModel{ + selectedPID: -1, + source: source, + } } func (d dashboardModel) Init() tea.Cmd { @@ -231,8 +266,27 @@ func (d dashboardModel) Update(tea.Msg) (tea.Model, tea.Cmd) { } func (d dashboardModel) View() string { + if d.latest != nil { + return PanelStyle.Render( + fmt.Sprintf("Dashboard (%d syscalls, %.1f/s)", d.latest.TotalSyscalls, d.latest.SyscallRatePerSec), + ) + } if d.selectedPID > 0 { return PanelStyle.Render(fmt.Sprintf("Dashboard (PID %d)", d.selectedPID)) } return PanelStyle.Render("Dashboard (All PIDs)") } + +func (d *dashboardModel) refresh() { + if source := getDashboardSnapshotSource(); source != nil { + d.source = source + } + if d.source == nil { + return + } + d.latest = d.source.Snapshot() +} + +func dashboardTickCmd() tea.Cmd { + return tea.Tick(time.Second, func(time.Time) tea.Msg { return dashboardTickMsg{} }) +} |
