imztop

package
v0.0.13 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 12, 2026 License: MIT Imports: 39 Imported by: 0

Documentation

Overview

Package imztop is a btop-style desktop resource monitor built on ImZero2 + egui2, consuming the in-repo `observability/sysmetrics` data layer. Wired as the imzero2 demo subcommand `appCode == 7`.

The package is read-only against sysmetrics. There is no process write-side (kill / nice / signal) by design — see ADR-0020 SD11.

Architecture

One sampler goroutine owns a *sysmetrics.Bundle and ticks at SamplerOptions.UpdateInterval (default 1 s). Each tick it calls Bundle.Sample, appends the result to per-series ring buffers, then publishes a fresh PublishedSnapshot via atomic.Pointer. The egui frame loop reads the latest snapshot via atomic.Load and re-slices stable ring backing memory — no allocation on the hot path.

See also

  • doc/adr/0020-imzero2-imztop-resource-monitor.md — accepted decision and milestone plan.
  • public/observability/sysmetrics/ — data source.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type App

type App struct {
	// contains filtered or unexported fields
}

App is the per-window imztop instance. The registry's factory ctor allocates a fresh App per Open() so two windows have independent UI state (currently just the selected network interface; more fields land here as user-visible per-window state grows).

func (*App) Frame

func (inst *App) Frame(ctx app.FrameContextI) (err error)

Frame renders one frame of the imztop window body. The host has already pre-pushed a window-unique salt onto inst.ids via c.IdScope (windowhost.renderWindowBody), so widget ids derived from inst.ids are scoped under that salt — no further package-level coordination is needed (every render helper is a method on *App).

func (*App) Manifest

func (inst *App) Manifest() (m app.Manifest)

func (*App) Mount

func (inst *App) Mount(ctx app.MountContextI) (err error)

func (*App) Unmount

func (inst *App) Unmount(ctx app.MountContextI) (err error)

type NamedSeries

type NamedSeries struct {
	Name string
	Y    []float64
}

NamedSeries is one labelled history series in a published snapshot (e.g. "sda" → read rates over the last 10 minutes). The slice is a fresh copy of the sampler's ring backing memory; mutating it does not affect future ticks.

type NamedValue

type NamedValue struct {
	Name  string
	Value float64
}

NamedValue is a (key, value) pair for namedWindowSet.push.

type ProcSortByE

type ProcSortByE uint8

ProcSortByE selects which column the process panel sorts on.

const (
	// ProcSortByCPU keys on the EWMA-smoothed CPU% (sampler's
	// ProcCPUSmoothed slice). Default sort key: order is stable
	// across transient spikes, matching the column the heatmap palette
	// is tinted onto.
	ProcSortByCPU ProcSortByE = iota
	// ProcSortByCPURaw keys on the raw sampler-interval CPU% value.
	// Useful when the user is hunting transient spikes that the
	// smoothed view dampens. When selected, the raw column is tinted
	// instead of the smoothed one.
	ProcSortByCPURaw
	ProcSortByMem
	ProcSortByPID
	ProcSortByUser
	ProcSortByName
)

type PublishedSnapshot

type PublishedSnapshot struct {
	SampledAtUnixMs int64

	HistoryTimeUnixSec []float64
	HistoryCPUTotal    []float64
	HistoryMemUsed     []float64
	HistoryDiskRead    []float64 // MiB/s (sum across block devices)
	HistoryDiskWrite   []float64 // MiB/s
	HistoryNetRx       []float64 // MiB/s (sum across interfaces)
	HistoryNetTx       []float64 // MiB/s
	HistoryBatteryPct  []float64

	HistoryCPUPerCore     [][]float64   // [core][time] percent
	HistoryGPUBusyPerDev  [][]float64   // [device][time] percent
	HistoryDiskReadByDev  []NamedSeries // MiB/s per block device, ordered by name
	HistoryDiskWriteByDev []NamedSeries // MiB/s per block device
	HistoryNetRxByIface   []NamedSeries // MiB/s per interface
	HistoryNetTxByIface   []NamedSeries // MiB/s per interface

	LatestCPU       *sysmsnap.CPUSnapshot
	LatestMem       *sysmsnap.MemSnapshot
	LatestDisk      *sysmsnap.DiskSnapshot
	LatestNet       *sysmsnap.NetSnapshot
	LatestBattery   *sysmsnap.BatterySnapshot
	LatestGPU       *sysmsnap.GPUSnapshot
	LatestContainer *sysmsnap.ContainerInfo
	LatestPSI       *sysmsnap.PSISnapshot
	Sensors         []sysmsnap.TempReading
	Procs           []sysmsnap.ProcInfo

	// ProcCPUSmoothed is the per-process EWMA-smoothed CPU% (α=
	// procCPUEWMAAlpha), parallel to Procs by index. Drives the
	// process-table sort key and the CPU%-cell background tint;
	// the raw Procs[i].CPUPercent stays untouched so the displayed
	// value still reflects the latest sampler-interval average.
	// Smoothing is per-PID and persists across ticks via the
	// Sampler's procCPUEWMA map (evicted when a PID disappears).
	ProcCPUSmoothed []float32

	// Topology is the static CPU containment hierarchy, delivered on the metric
	// plane (ADR-0090 SD6) rather than read in-process by the consumer. nil until
	// the first topology-bearing snapshot arrives (or if the scraper could not
	// read it); the topology panel builds its treemap from it once.
	Topology *sysmsnap.Topology

	Errors map[sysmsnap.Domain]error
}

PublishedSnapshot is the read-only frame the renderer consumes. Built once per Sampler tick and replaced atomically; slices are owned by the snapshot and never mutated after publication, so concurrent readers see a coherent view.

All byte/sec history fields (disk/net) are stored in MiB/s so the renderer can label plot axes "MiB/s" without per-frame scaling. Sub-MiB/s rates appear as small fractional values; raw counters at the byte level remain available on the Latest* fields.

type Sampler

type Sampler struct {
	// contains filtered or unexported fields
}

Sampler runs a goroutine that periodically calls Bundle.Sample and publishes a PublishedSnapshot via atomic.Pointer.

func NewSampler

func NewSampler(opts SamplerOptions, bus app.BusI) (inst *Sampler, err error)

NewSampler builds a pure-consumer Sampler (ADR-0090): it subscribes to the system-metrics plane on the host-provided bus and folds what arrives into sliding-window history + per-process EWMA. The /proc reader is a separate scraper (the carousel host's co-located one, the tour's, or an external sysmetricsd), so imztop builds no collectors and holds no system-state capability. bus is MountCtx.Bus() in the app; tests and the tour pass an inprocbus client fed by StartScraper. A nil bus degrades to NoopBus.

func (*Sampler) Close

func (inst *Sampler) Close() (err error)

func (*Sampler) Interval

func (inst *Sampler) Interval() (d time.Duration)

Interval returns the most recent observed sample cadence (the scraper's real rate; see intervalNs). There is no setter — imztop does not control the cadence; it observes it from consecutive samples (ADR-0090 SD5).

func (*Sampler) IntervalLabel

func (inst *Sampler) IntervalLabel() (out string)

IntervalLabel returns the observed sample cadence as a short human-readable label for the top-bar status row (the scraper's real rate; see intervalNs).

func (*Sampler) IsPaused

func (inst *Sampler) IsPaused() (p bool)

func (*Sampler) Latest

func (inst *Sampler) Latest() (snap *PublishedSnapshot)

func (*Sampler) Pause

func (inst *Sampler) Pause(p bool)

func (*Sampler) Start

func (inst *Sampler) Start(_ context.Context)

type SamplerI

type SamplerI interface {
	Start(ctx context.Context)
	Latest() (snap *PublishedSnapshot)
	Pause(p bool)
	IsPaused() (p bool)
	Close() (err error)
}

SamplerI is the public surface a Sampler implements.

type SamplerOptions

type SamplerOptions struct {
	UpdateInterval time.Duration
	HistoryWindow  time.Duration
}

SamplerOptions configures a Sampler.

type SlidingWindow

type SlidingWindow[T any] = slidingwindow.Window[T]

SlidingWindow aliases the shared observability sliding-window buffer, lifted out of imztop + imzrt per ADR-0061 SD13. See slidingwindow.Window for semantics (memmove-on-full, stable backing, per-tick copy-out; not safe for concurrent use).

func NewSlidingWindow

func NewSlidingWindow[T any](capacity int32) *SlidingWindow[T]

NewSlidingWindow constructs a SlidingWindow holding at most capacity values (clamped to a minimum of 1).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL