summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AGENTS.md6
-rw-r--r--README.md12
-rw-r--r--cmd/loadbars/main.go8
-rw-r--r--internal/config/config.go6
-rw-r--r--internal/display/display.go185
-rw-r--r--internal/display/display_test.go80
-rw-r--r--internal/version/version.go2
7 files changed, 140 insertions, 159 deletions
diff --git a/AGENTS.md b/AGENTS.md
index ab005e5..28af89c 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -51,15 +51,15 @@ Default when no hosts are given: `localhost`. No SSH required for local use.
## Display and hotkeys
- **Display** (`internal/display`): One loop – poll events, snapshot from store, count bars, clear only when layout/size changes, draw CPU then mem then net per host, present. Bar width = `winW / numBars`; no gap between bars (avoids 1px artifacts).
-- **Hotkeys:** 1=cores, 2=mem, 3=net, e=extended (peak line), h=help, n=cycle net iface, q=quit, w=write config, a/y=cpu avg, d/c=net avg, arrows=resize. See README “Hotkeys” table.
+- **Hotkeys:** 1=cores, 2=mem, 3=net, e=extended (peak line), h=help, q=quit, w=write config, a/y=cpu avg, d/c=net avg, f/v=link scale, arrows=resize. See README "Hotkeys" table.
-Network interface: chosen by `netint` config or first non-`lo`; press `n` to cycle. When net is toggled on, stdout prints which interface is used and how to set `netint`/`netlink`.
+Network bars aggregate RX/TX across all non-`lo` interfaces per host. Link speed is set via `netlink` config or `--netlink` flag.
## Conventions
- Prefer the existing `internal/*` package layout; avoid adding new toplevel Go packages unless necessary.
- Version is the single source in `internal/version/version.go`.
-- Config keys are lowercase in `~/.loadbarsrc` (e.g. `netint=eth0`, `netlink=gbit`).
+- Config keys are lowercase in `~/.loadbarsrc` (e.g. `netlink=gbit`).
- No text/font rendering in the SDL window in the current design; keep feedback on stdout unless the user explicitly asks for in-window labels.
## Testing
diff --git a/README.md b/README.md
index 5fe02ea..3c2c6cf 100644
--- a/README.md
+++ b/README.md
@@ -109,10 +109,9 @@ Press these keys while loadbars is running (see also `h` for a short list on std
|-----|--------|
| **1** | Toggle CPU cores (one bar per core vs one aggregate bar per host) |
| **2** | Toggle memory bars (RAM left, Swap right per host) |
-| **3** | Toggle network bars (RX/TX per host); stdout shows which interface is used |
+| **3** | Toggle network bars (RX/TX summed across all non-lo interfaces per host) |
| **e** | Toggle extended display (1px peak line on CPU bars: max system+user over last samples) |
| **h** | Print hotkey list to stdout |
-| **n** | Cycle to next network interface (per host); only when net bars are shown |
| **q** | Quit |
| **w** | Write current settings to ~/.loadbarsrc |
| **a** | Increase CPU average samples (affects extended peak history length) |
@@ -148,13 +147,9 @@ Press these keys while loadbars is running (see also `h` for a short list on std
- `Rxb` = Incoming (received) traffic in %, Color: Light green, normal green if >100% while using low netlink reference. Bar comes from top and is half width.
- `Txb` = Outgoing (transmitted) traffic in %, Color: Light green, normal green if >100% while using low netlink reference. Bar comes from bottom and is half width.
-When network bar is red: The interface does not exist on the specific remote host.
+When network bar is red: No non-loopback interface exists on the specific remote host.
-**Choosing the network interface:** By default loadbars uses the first non-loopback interface (e.g. `eth0`, `enp0s3`). If stats never change, you may be watching the wrong interface (e.g. `docker0` with little traffic). Set the interface explicitly:
-
-- In **~/.loadbarsrc**: `netint=eth0` (use the name from `/proc/net/dev` or `ip link`)
-- On the command line: `loadbars --netint eth0 --hosts localhost`
-- In-app: press **3** to show net bars (stdout will print which interface is used), then **n** to cycle to the next interface.
+**Aggregated interfaces:** Loadbars sums RX/TX across all non-loopback interfaces (e.g. `eth0`, `wlan0`, `enp0s3`) and shows the combined total. Loopback (`lo`) is always excluded.
**Link speed** (`netlink`): Used to compute utilization %. Default is `gbit`. Set e.g. `netlink=100mbit` or `netlink=10gbit` in ~/.loadbarsrc or `--netlink 100mbit`.
@@ -164,7 +159,6 @@ Loadbars tries to read ~/.loadbarsrc and it's possible to configure any option y
```
showcores=1 # Always show cores on startup
-netint=eth0 # Interface for network bars (optional)
netlink=gbit # Link speed for utilization % (optional)
```
diff --git a/cmd/loadbars/main.go b/cmd/loadbars/main.go
index cd834ab..3d7fe77 100644
--- a/cmd/loadbars/main.go
+++ b/cmd/loadbars/main.go
@@ -26,7 +26,6 @@ func main() {
flag.IntVar(&cfg.MaxWidth, "maxwidth", cfg.MaxWidth, "Set max width")
flag.IntVar(&cfg.CPUAverage, "cpuaverage", cfg.CPUAverage, "Num of CPU samples for avg")
flag.IntVar(&cfg.NetAverage, "netaverage", cfg.NetAverage, "Num of net samples for avg")
- flag.StringVar(&cfg.NetInt, "netint", cfg.NetInt, "Interface to show netstats for")
flag.StringVar(&cfg.NetLink, "netlink", cfg.NetLink, "Link speed (mbit, 10mbit, 100mbit, gbit, 10gbit or number)")
flag.BoolVar(&cfg.ShowCores, "showcores", cfg.ShowCores, "Toggle core display")
flag.BoolVar(&cfg.ShowMem, "showmem", cfg.ShowMem, "Toggle mem display")
@@ -119,16 +118,13 @@ Options:
--height <n> Window height (default 150)
--showcores Show per-CPU bars
--showmem Show memory bars
- --shownet Show network bars
- --netint <iface> Network interface for net bars (e.g. eth0, enp0s3).
- Default: first non-lo. Press 'n' in-app to cycle.
+ --shownet Show network bars (aggregates all non-lo interfaces)
--netlink <speed> Link speed for %% (gbit, 10gbit, mbit, 100mbit, or number).
Default: gbit.
--extended Extended display (peak line)
--help This help
--version Print version
-Config: netint and netlink can be set in ~/.loadbarsrc. Press '3' then see
-stdout for which interface is used; press 'n' to cycle. Press 'h' for hotkeys.
+Config: netlink can be set in ~/.loadbarsrc. Press 'h' for hotkeys.
`, version.Version, constants.CSSHConfFile)
}
diff --git a/internal/config/config.go b/internal/config/config.go
index e523372..0fc80d4 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -23,7 +23,6 @@ type Config struct {
Height int
MaxWidth int
NetAverage int
- NetInt string
NetLink string
ShowCores bool
ShowMem bool
@@ -104,7 +103,7 @@ func (c *Config) parseReader(f *os.File) error {
validKeys := map[string]bool{
"title": true, "barwidth": true, "cpuaverage": true, "extended": true,
"hasagent": true, "height": true, "maxwidth": true, "netaverage": true,
- "netint": true, "netlink": true, "showcores": true, "showmem": true,
+ "netlink": true, "showcores": true, "showmem": true,
"shownet": true, "sshopts": true, "cluster": true,
}
scanner := bufio.NewScanner(f)
@@ -158,8 +157,6 @@ func (c *Config) set(key, val string) {
if n, err := strconv.Atoi(val); err == nil {
c.NetAverage = n
}
- case "netint":
- c.NetInt = val
case "netlink":
c.NetLink = val
case "showcores":
@@ -198,7 +195,6 @@ func (c *Config) writeTo(f *os.File) error {
writeInt("height", c.Height)
writeInt("maxwidth", c.MaxWidth)
writeInt("netaverage", c.NetAverage)
- writeStr("netint", c.NetInt)
writeStr("netlink", c.NetLink)
writeBool("showcores", c.ShowCores)
writeBool("showmem", c.ShowMem)
diff --git a/internal/display/display.go b/internal/display/display.go
index b5ed092..3b4dd42 100644
--- a/internal/display/display.go
+++ b/internal/display/display.go
@@ -21,40 +21,35 @@ const smoothFactor = 0.12 // blend toward target each frame; lower = smoother
// runState holds mutable state across the display loop (hotkeys, window size, smoothed data).
type runState struct {
- showCores bool
- showMem bool
- showNet bool
- extended bool
- winW int32
- winH int32
- prevCPU map[string]collector.CPULine
- smoothedCPU map[string]*[9]float64
- smoothedMem map[string]*struct{ ramUsed, swapUsed float64 }
- smoothedNet map[string]*struct{ rxPct, txPct float64 }
- prevNet map[string]stats.NetStamp
- netIntIndex map[string]int
- cycleNetNext bool
- printNetInfoOnce bool
- peakHistory map[string][]float64
+ showCores bool
+ showMem bool
+ showNet bool
+ extended bool
+ winW int32
+ winH int32
+ prevCPU map[string]collector.CPULine
+ smoothedCPU map[string]*[9]float64
+ smoothedMem map[string]*struct{ ramUsed, swapUsed float64 }
+ smoothedNet map[string]*struct{ rxPct, txPct float64 }
+ prevNet map[string]stats.NetStamp // aggregated (summed) previous net stamp per host
+ peakHistory map[string][]float64
}
// newRunState builds initial run state from config.
func newRunState(cfg *config.Config, winW, winH int32) *runState {
return &runState{
- showCores: cfg.ShowCores,
- showMem: cfg.ShowMem,
- showNet: cfg.ShowNet,
- extended: cfg.Extended,
- winW: winW,
- winH: winH,
- prevCPU: make(map[string]collector.CPULine),
- smoothedCPU: make(map[string]*[9]float64),
- smoothedMem: make(map[string]*struct{ ramUsed, swapUsed float64 }),
- smoothedNet: make(map[string]*struct{ rxPct, txPct float64 }),
- prevNet: make(map[string]stats.NetStamp),
- netIntIndex: make(map[string]int),
- printNetInfoOnce: cfg.ShowNet,
- peakHistory: make(map[string][]float64),
+ showCores: cfg.ShowCores,
+ showMem: cfg.ShowMem,
+ showNet: cfg.ShowNet,
+ extended: cfg.Extended,
+ winW: winW,
+ winH: winH,
+ prevCPU: make(map[string]collector.CPULine),
+ smoothedCPU: make(map[string]*[9]float64),
+ smoothedMem: make(map[string]*struct{ ramUsed, swapUsed float64 }),
+ smoothedNet: make(map[string]*struct{ rxPct, txPct float64 }),
+ prevNet: make(map[string]stats.NetStamp),
+ peakHistory: make(map[string][]float64),
}
}
@@ -152,9 +147,6 @@ func handleKey(sym sdl.Keycode, window *sdl.Window, cfg *config.Config, state *r
case sdl.K_3:
state.showNet = !state.showNet
fmt.Println("==> Toggled show net:", state.showNet)
- if state.showNet {
- state.printNetInfoOnce = true
- }
case sdl.K_e:
state.extended = !state.extended
fmt.Println("==> Toggled extended (peak line):", state.extended)
@@ -180,11 +172,6 @@ func handleKey(sym sdl.Keycode, window *sdl.Window, cfg *config.Config, state *r
scaleLinkDown(cfg)
case sdl.K_h:
printHotkeys()
- case sdl.K_n:
- state.cycleNetNext = true
- if state.showNet {
- fmt.Println("==> Cycling to next network interface (per host)")
- }
case sdl.K_w:
cfg.ShowCores = state.showCores
cfg.ShowMem = state.showMem
@@ -223,16 +210,6 @@ func handleKey(sym sdl.Keycode, window *sdl.Window, cfg *config.Config, state *r
// drawFrame updates state from snapshot, clears if layout changed, and draws all bars.
func drawFrame(renderer *sdl.Renderer, src stats.Source, cfg *config.Config, state *runState) {
snap := src.Snapshot()
- if state.cycleNetNext {
- for _, host := range sortedHosts(snap) {
- state.netIntIndex[host]++
- }
- state.cycleNetNext = false
- }
- if state.printNetInfoOnce && state.showNet {
- state.printNetInfoOnce = false
- printNetInterfaceHelp(snap, cfg, state.netIntIndex)
- }
numBars := countBars(snap, state.showCores, state.showMem, state.showNet)
barWidth := state.winW / int32(numBars)
if barWidth < 1 {
@@ -314,7 +291,7 @@ func drawHostBars(renderer *sdl.Renderer, h *stats.HostStats, host string, cfg *
if state.smoothedNet[host] == nil {
state.smoothedNet[host] = &struct{ rxPct, txPct float64 }{}
}
- state.prevNet[host] = drawNetBarSmoothed(renderer, h, cfg, state.smoothedNet[host], state.prevNet[host], state.netIntIndex, host, smoothFactor, barWidth, x, winH)
+ state.prevNet[host] = drawNetBarSmoothed(renderer, h, cfg, state.smoothedNet[host], state.prevNet[host], smoothFactor, barWidth, x, winH)
}
}
@@ -526,35 +503,9 @@ func drawMemBarSmoothed(renderer *sdl.Renderer, h *stats.HostStats, smoothed *st
}
func printHotkeys() {
- fmt.Println("=> Hotkeys: 1=cores 2=mem 3=net e=extended h=help n=next net q=quit w=write config a/y=cpu avg d/c=net avg f/v=link scale arrows=resize")
+ fmt.Println("=> Hotkeys: 1=cores 2=mem 3=net e=extended h=help q=quit w=write config a/y=cpu avg d/c=net avg f/v=link scale arrows=resize")
}
-// printNetInterfaceHelp prints which interface is used per host and how to set netint (when net view is toggled on).
-func printNetInterfaceHelp(snap map[string]*stats.HostStats, cfg *config.Config, netIntIndex map[string]int) {
- for _, host := range sortedHosts(snap) {
- h := snap[host]
- if h == nil || h.Net == nil || len(h.Net) == 0 {
- fmt.Printf("Net: %s => (no interfaces yet, wait for data)\n", host)
- continue
- }
- iface := chooseNetIface(h, cfg, host, netIntIndex)
- all := make([]string, 0, len(h.Net))
- for name := range h.Net {
- all = append(all, name)
- }
- sort.Strings(all)
- if iface == "" {
- fmt.Printf("Net: %s => (no non-lo interface; seen: %s)\n", host, strings.Join(all, ", "))
- continue
- }
- hint := "set netint=IFACE in ~/.loadbarsrc or --netint IFACE"
- if cfg.NetInt != "" {
- hint = "using netint=" + cfg.NetInt + " from config"
- }
- fmt.Printf("Net: %s => %s (all: %s). %s\n", host, iface, strings.Join(all, ", "), hint)
- }
- fmt.Println("=> Link speed: netlink=" + cfg.NetLink + " (gbit/mbit/10mbit/100mbit/10gbit or number). Change in ~/.loadbarsrc or --netlink")
-}
// netLinkBytesPerSec returns link speed in bytes/sec from cfg.NetLink (e.g. "gbit", "10gbit", "100mbit", or numeric mbit).
@@ -616,58 +567,54 @@ func netLinkBytesPerSec(cfg *config.Config) int64 {
return int64(constants.BytesGbit)
}
-// chooseNetIface returns the interface name to use for this host: cfg.NetInt if set and present, else first non-lo, cycling with n key.
-func chooseNetIface(h *stats.HostStats, cfg *config.Config, host string, netIntIndex map[string]int) string {
- if h.Net == nil || len(h.Net) == 0 {
- return ""
- }
- if cfg.NetInt != "" {
- if _, ok := h.Net[cfg.NetInt]; ok {
- return cfg.NetInt
- }
+// sumNonLoNet aggregates RX (B) and TX (Tb) bytes across all non-lo interfaces,
+// using the latest timestamp from any interface.
+func sumNonLoNet(h *stats.HostStats) (sum stats.NetStamp, hasIface bool) {
+ if h.Net == nil {
+ return sum, false
}
- names := make([]string, 0, len(h.Net))
- for iface := range h.Net {
+ for iface, ns := range h.Net {
if iface == "lo" {
continue
}
- names = append(names, iface)
- }
- sort.Strings(names)
- if len(names) == 0 {
- return ""
- }
- idx := netIntIndex[host] % len(names)
- if idx < 0 {
- idx += len(names)
+ hasIface = true
+ sum.B += ns.B
+ sum.Tb += ns.Tb
+ if ns.Stamp > sum.Stamp {
+ sum.Stamp = ns.Stamp
+ }
}
- return names[idx]
+ return sum, hasIface
}
-func drawNetBarSmoothed(renderer *sdl.Renderer, h *stats.HostStats, cfg *config.Config, smoothed *struct{ rxPct, txPct float64 }, prev stats.NetStamp, netIntIndex map[string]int, host string, factor float64, barW int32, x *int32, winH int32) stats.NetStamp {
+// drawNetBarSmoothed sums RX/TX across all non-lo interfaces, computes utilization
+// vs link speed, smooths toward target, and draws one net bar (RX left from top, TX right from bottom).
+// Smoothed values and prevNet are only updated when new collector data arrives
+// (cur.Stamp > prev.Stamp), so the bar holds steady between collector cycles
+// instead of decaying toward zero on frames with no new data.
+func drawNetBarSmoothed(renderer *sdl.Renderer, h *stats.HostStats, cfg *config.Config, smoothed *struct{ rxPct, txPct float64 }, prev stats.NetStamp, factor float64, barW int32, x *int32, winH int32) stats.NetStamp {
defer func() { *x += barW }()
// Clear this slot so we never leave previous (e.g. CPU/mem) content visible
renderer.SetDrawColor(constants.Black.R, constants.Black.G, constants.Black.B, 255)
renderer.FillRect(&sdl.Rect{X: *x, Y: 0, W: barW, H: winH})
- iface := chooseNetIface(h, cfg, host, netIntIndex)
- if iface == "" {
- renderer.SetDrawColor(constants.Red.R, constants.Red.G, constants.Red.B, 255)
- renderer.FillRect(&sdl.Rect{X: *x, Y: 0, W: barW, H: winH})
- return prev
- }
- cur, ok := h.Net[iface]
- if !ok {
+ cur, hasIface := sumNonLoNet(h)
+ if !hasIface {
+ // No non-lo interface: show red bar
renderer.SetDrawColor(constants.Red.R, constants.Red.G, constants.Red.B, 255)
renderer.FillRect(&sdl.Rect{X: *x, Y: 0, W: barW, H: winH})
return prev
}
- linkBps := netLinkBytesPerSec(cfg)
- if linkBps <= 0 {
- linkBps = int64(constants.BytesGbit)
- }
- var targetRx, targetTx float64
- if prev.Stamp > 0 && cur.Stamp > prev.Stamp {
- dt := float64(cur.Stamp-prev.Stamp) / 1e9
+ // Only recompute and smooth when the collector has provided new data.
+ // The collector updates net stamps every ~2.8s, but drawFrame runs every
+ // ~0.14s. Without this guard, the 19 intermediate frames would set
+ // target to 0 (no delta) and smooth the bar toward zero, making real
+ // traffic invisible.
+ if cur.Stamp > prev.Stamp && prev.Stamp > 0 {
+ linkBps := netLinkBytesPerSec(cfg)
+ if linkBps <= 0 {
+ linkBps = int64(constants.BytesGbit)
+ }
+ dt := cur.Stamp - prev.Stamp
if dt > 0 {
deltaB := cur.B - prev.B
deltaTb := cur.Tb - prev.Tb
@@ -677,12 +624,16 @@ func drawNetBarSmoothed(renderer *sdl.Renderer, h *stats.HostStats, cfg *config.
if deltaTb < 0 {
deltaTb = 0
}
- targetRx = 100 * float64(deltaB) / (float64(linkBps) * dt)
- targetTx = 100 * float64(deltaTb) / (float64(linkBps) * dt)
+ targetRx := 100 * float64(deltaB) / (float64(linkBps) * dt)
+ targetTx := 100 * float64(deltaTb) / (float64(linkBps) * dt)
+ smoothed.rxPct += (targetRx - smoothed.rxPct) * factor
+ smoothed.txPct += (targetTx - smoothed.txPct) * factor
}
+ prev = cur // only advance prev when we consumed new data
+ } else if prev.Stamp == 0 {
+ // First sample: record it but don't draw yet (no delta available)
+ prev = cur
}
- smoothed.rxPct += (targetRx - smoothed.rxPct) * factor
- smoothed.txPct += (targetTx - smoothed.txPct) * factor
halfW := barW / 2
barH := float64(winH) / 100.0
@@ -712,5 +663,5 @@ func drawNetBarSmoothed(renderer *sdl.Renderer, h *stats.HostStats, cfg *config.
renderer.SetDrawColor(constants.Black.R, constants.Black.G, constants.Black.B, 255)
renderer.FillRect(&sdl.Rect{X: *x + halfW, Y: 0, W: halfW, H: winH - txH})
}
- return cur
+ return prev
}
diff --git a/internal/display/display_test.go b/internal/display/display_test.go
index 841b1d4..94068f6 100644
--- a/internal/display/display_test.go
+++ b/internal/display/display_test.go
@@ -278,7 +278,7 @@ func TestNetBar_RxTx(t *testing.T) {
"cpu": {User: 100, System: 100, Idle: 800},
},
Net: map[string]stats.NetStamp{
- "eth0": {B: 12500000, Tb: 6250000, Stamp: 2e9}, // current sample
+ "eth0": {B: 12500000, Tb: 6250000, Stamp: 2.0}, // current sample
},
},
},
@@ -288,7 +288,7 @@ func TestNetBar_RxTx(t *testing.T) {
state.prevCPU["host1;cpu"] = collector.CPULine{}
// Pre-populate prevNet so delta calculation works:
// RX: delta=12500000 bytes in 1s = 10% of gbit, TX: 6250000 = 5% of gbit
- state.prevNet["host1"] = stats.NetStamp{B: 0, Tb: 0, Stamp: 1e9}
+ state.prevNet["host1"] = stats.NetStamp{B: 0, Tb: 0, Stamp: 1.0}
// Pre-populate smoothed net so first frame is near target
state.smoothedNet["host1"] = &struct{ rxPct, txPct float64 }{
rxPct: 10, txPct: 5,
@@ -307,6 +307,60 @@ func TestNetBar_RxTx(t *testing.T) {
assertPixelColor(t, surface, 85, 10, constants.Black, tol, "TX free area")
}
+func TestNetBar_AggregatesAllInterfaces(t *testing.T) {
+ const w, h int32 = 100, 100
+
+ renderer, surface, err := createTestRenderer(w, h)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer renderer.Destroy()
+ defer surface.Free()
+
+ cfg := defaultTestConfig()
+ cfg.ShowCores = false
+ cfg.ShowMem = false
+ cfg.ShowNet = true
+ cfg.NetLink = "gbit"
+
+ // Two non-lo interfaces: combined RX = 12500000+12500000 = 25000000 → 20% of gbit
+ src := &mockSource{
+ data: map[string]*stats.HostStats{
+ "host1": {
+ CPU: map[string]collector.CPULine{
+ "cpu": {User: 100, System: 100, Idle: 800},
+ },
+ Net: map[string]stats.NetStamp{
+ "eth0": {B: 12500000, Tb: 6250000, Stamp: 2.0},
+ "wlan0": {B: 12500000, Tb: 6250000, Stamp: 2.0},
+ "lo": {B: 99999999, Tb: 99999999, Stamp: 2.0}, // lo must be excluded
+ },
+ },
+ },
+ }
+
+ state := newRunState(cfg, w, h)
+ state.prevCPU["host1;cpu"] = collector.CPULine{}
+ // Previous aggregated stamp: all zeros at t=1
+ state.prevNet["host1"] = stats.NetStamp{B: 0, Tb: 0, Stamp: 1.0}
+ // Pre-populate smoothed to 20% RX, 10% TX (the expected combined values)
+ state.smoothedNet["host1"] = &struct{ rxPct, txPct float64 }{
+ rxPct: 20, txPct: 10,
+ }
+
+ drawFrame(renderer, src, cfg, state)
+
+ const tol = 5
+ // Net bar: 1 CPU + 1 net = 2 bars, each 50px. Net bar at x=50, halfW=25
+ // Left half (RX from top): 20% = 20px of LightGreen from top
+ assertPixelColor(t, surface, 60, 5, constants.LightGreen, tol, "aggregated RX at top")
+ assertPixelColor(t, surface, 60, 45, constants.Black, tol, "RX free area")
+
+ // Right half (TX from bottom): 10% = 10px of LightGreen from bottom
+ assertPixelColor(t, surface, 85, 98, constants.LightGreen, tol, "aggregated TX at bottom")
+ assertPixelColor(t, surface, 85, 10, constants.Black, tol, "TX free area")
+}
+
func TestMultiHost_BarCount(t *testing.T) {
const w, h int32 = 600, 100
@@ -332,12 +386,12 @@ func TestMultiHost_BarCount(t *testing.T) {
"alpha": {
CPU: map[string]collector.CPULine{"cpu": alphaCur},
Mem: map[string]int64{"MemTotal": 100, "MemFree": 50, "SwapTotal": 0, "SwapFree": 0},
- Net: map[string]stats.NetStamp{"eth0": {B: 0, Tb: 0, Stamp: 1e9}},
+ Net: map[string]stats.NetStamp{"eth0": {B: 0, Tb: 0, Stamp: 1.0}},
},
"beta": {
CPU: map[string]collector.CPULine{"cpu": betaCur},
Mem: map[string]int64{"MemTotal": 100, "MemFree": 50, "SwapTotal": 0, "SwapFree": 0},
- Net: map[string]stats.NetStamp{"eth0": {B: 0, Tb: 0, Stamp: 1e9}},
+ Net: map[string]stats.NetStamp{"eth0": {B: 0, Tb: 0, Stamp: 1.0}},
},
},
}
@@ -443,7 +497,7 @@ func TestNetBar_NoInterface(t *testing.T) {
"cpu": {User: 100, System: 100, Idle: 800},
},
Net: map[string]stats.NetStamp{
- "lo": {B: 0, Tb: 0, Stamp: 1e9}, // only loopback
+ "lo": {B: 0, Tb: 0, Stamp: 1.0}, // only loopback
},
},
},
@@ -573,8 +627,8 @@ func newHotkeyTestEnv(t *testing.T, showCores, showMem, showNet bool) (
"SwapFree": 600,
},
Net: map[string]stats.NetStamp{
- "eth0": {B: 12500000, Tb: 6250000, Stamp: 2e9},
- "wlan0": {B: 1000000, Tb: 500000, Stamp: 2e9},
+ "eth0": {B: 12500000, Tb: 6250000, Stamp: 2.0},
+ "wlan0": {B: 1000000, Tb: 500000, Stamp: 2.0},
},
},
},
@@ -584,7 +638,7 @@ func newHotkeyTestEnv(t *testing.T, showCores, showMem, showNet bool) (
state.prevCPU["host1;cpu"] = prev
state.prevCPU["host1;cpu0"] = prev0
state.prevCPU["host1;cpu1"] = prev1
- state.prevNet["host1"] = stats.NetStamp{B: 0, Tb: 0, Stamp: 1e9}
+ state.prevNet["host1"] = stats.NetStamp{B: 0, Tb: 0, Stamp: 1.0}
state.smoothedNet["host1"] = &struct{ rxPct, txPct float64 }{
rxPct: 10, txPct: 5,
}
@@ -755,16 +809,6 @@ func TestHandleKey_NetAverage(t *testing.T) {
}
}
-func TestHandleKey_CycleNet(t *testing.T) {
- cfg := defaultTestConfig()
- state := newRunState(cfg, 200, 100)
-
- handleKey(sdl.K_n, nil, cfg, state)
- if !state.cycleNetNext {
- t.Error("expected cycleNetNext=true after pressing 'n'")
- }
-}
-
func TestHandleKey_WriteConfig(t *testing.T) {
// Set HOME to a temp dir so we don't touch real ~/.loadbarsrc
tmpDir := t.TempDir()
diff --git a/internal/version/version.go b/internal/version/version.go
index 2b4ace2..209fae7 100644
--- a/internal/version/version.go
+++ b/internal/version/version.go
@@ -1,4 +1,4 @@
package version
// Version is the application version (set at build time or here for development).
-const Version = "0.8.4"
+const Version = "0.9.0"