From 0b463d427f7758cca9478bfa6d2c2f8eec758740 Mon Sep 17 00:00:00 2001 From: "Sean E. Russell" Date: Fri, 12 Jun 2020 10:22:23 -0500 Subject: [PATCH 1/6] Fixme comment --- devices/temp_linux.go | 1 + 1 file changed, 1 insertion(+) diff --git a/devices/temp_linux.go b/devices/temp_linux.go index 6967232..0bd480f 100644 --- a/devices/temp_linux.go +++ b/devices/temp_linux.go @@ -15,6 +15,7 @@ func devs() []string { } sensors, err := host.SensorsTemperatures() if err != nil { + // FIXME report the error return []string{} } rv := make([]string, 0, len(sensors)) From 050b62a20a6250bac7bf1549e7cfeaf2bb7c5494 Mon Sep 17 00:00:00 2001 From: "Sean E. Russell" Date: Tue, 23 Jun 2020 07:12:09 -0500 Subject: [PATCH 2/6] Fixes #134, caused by a divide by zero error on systems with no batteries --- widgets/batterygauge.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/widgets/batterygauge.go b/widgets/batterygauge.go index 135f223..02a8866 100644 --- a/widgets/batterygauge.go +++ b/widgets/batterygauge.go @@ -51,6 +51,10 @@ func (b *BatteryGauge) update() { } return } + if len(bats) < 1 { + b.Label = fmt.Sprintf("N/A") + return + } mx := 0.0 cu := 0.0 charging := "%d%% ⚡%s" From 9b176e678e8535bc72bede4f4b95318ce207644a Mon Sep 17 00:00:00 2001 From: "Sean E. Russell" Date: Fri, 26 Jun 2020 11:50:15 -0500 Subject: [PATCH 3/6] Work-around for bug shirou/gopsutil#849, addressing #135 --- devices/cpu_cpu.go | 2 +- devices/cpu_linux.go | 23 +++++++++++++++++++++++ devices/cpu_other.go | 9 +++++++++ widgets/proc.go | 5 ++--- widgets/proc_linux.go | 1 + 5 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 devices/cpu_linux.go create mode 100644 devices/cpu_other.go diff --git a/devices/cpu_cpu.go b/devices/cpu_cpu.go index 0c1f9c1..bd2f891 100644 --- a/devices/cpu_cpu.go +++ b/devices/cpu_cpu.go @@ -9,7 +9,7 @@ import ( // FIXME: broken % under Linux. Doesn't reflect reality *at all*. func init() { f := func(cpus map[string]int, l bool) map[string]error { - cpuCount, err := psCpu.Counts(l) + cpuCount, err := CpuCount() if err != nil { return nil } diff --git a/devices/cpu_linux.go b/devices/cpu_linux.go new file mode 100644 index 0000000..4e836d5 --- /dev/null +++ b/devices/cpu_linux.go @@ -0,0 +1,23 @@ +// +build linux + +package devices + +import "github.com/shirou/gopsutil/cpu" + +func CpuCount() (int, error) { + cpuCount, err := cpu.Counts(false) + if err != nil { + return 0, err + } + if cpuCount == 0 { + is, err := cpu.Info() + if err != nil { + return 0, err + } + if is[0].Cores > 0 { + return len(is) / 2, nil + } + return len(is), nil + } + return cpuCount, nil +} diff --git a/devices/cpu_other.go b/devices/cpu_other.go new file mode 100644 index 0000000..95d183f --- /dev/null +++ b/devices/cpu_other.go @@ -0,0 +1,9 @@ +// +build !linux + +package devices + +import "github.com/shirou/gopsutil/cpu" + +func CpuCount() (int, error) { + return cpu.Counts(false) +} diff --git a/widgets/proc.go b/widgets/proc.go index f47f646..218ba63 100644 --- a/widgets/proc.go +++ b/widgets/proc.go @@ -9,9 +9,8 @@ import ( "strings" "time" - psCPU "github.com/shirou/gopsutil/cpu" - tui "github.com/gizak/termui/v3" + "github.com/xxxserxxx/gotop/v4/devices" ui "github.com/xxxserxxx/gotop/v4/termui" "github.com/xxxserxxx/gotop/v4/utils" ) @@ -49,7 +48,7 @@ type ProcWidget struct { } func NewProcWidget() *ProcWidget { - cpuCount, err := psCPU.Counts(false) + cpuCount, err := devices.CpuCount() if err != nil { log.Printf("failed to get CPU count from gopsutil: %v", err) } diff --git a/widgets/proc_linux.go b/widgets/proc_linux.go index 164319d..8fb53a0 100644 --- a/widgets/proc_linux.go +++ b/widgets/proc_linux.go @@ -19,6 +19,7 @@ func getProcs() ([]Proc, error) { procs := []Proc{} for _, line := range linesOfProcStrings { + log.Printf("line is '%s', pid is '%s', cpu is '%s', mem is '%s'", line, strings.TrimSpace(line[0:10]), strings.TrimSpace(line[63:68]), strings.TrimSpace(line[69:74])) pid, err := strconv.Atoi(strings.TrimSpace(line[0:10])) if err != nil { log.Printf("failed to convert PID to int: %v. line: %v", err, line) From fc7e19d991bfdcbec11f2ccfd595379e939d7064 Mon Sep 17 00:00:00 2001 From: "Sean E. Russell" Date: Wed, 1 Jul 2020 15:57:50 -0500 Subject: [PATCH 4/6] Closes #140 -- include instructions in the README for properly setting the version. --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b8be2df..eb69fac 100644 --- a/README.md +++ b/README.md @@ -62,9 +62,18 @@ gotop should build with most versions of Go. If you have a version other than 1 git clone https://github.com/xxxserxxx/gotop.git cd gotop sed -i '/^go/d' go.mod # Do this if you have go != 1.14 -go build -o gotop ./cmd/gotop +VERS="$(git tag -l --sort=-v:refname | sed 's/v\([^-].*\)/\1/g' | head -1 | tr -d '-' ).$(git describe --long --tags | sed 's/\([^-].*\)-\([0-9]*\)-\(g.*\)/r\2.\3/g' | tr -d '-')" +DAT=$(date +%Y%m%dT%H%M%S) +go build -o gotop \ + -ldflags "-X main.Version=v${VERS} -X main.BuildDate=${DAT}" \ + ./cmd/gotop ``` + go build \ + -gcflags "all=-trimpath=${PWD}" \ + -asmflags "all=-trimpath=${PWD}" \ + -ldflags "-X main.Version=v${VERSION} -X main.BuildDate=${BUILDDATE} -extldflags ${LDFLAGS}" \ + ./cmd/gotop Move `gotop` to somewhere in your `$PATH`. If Go is not installed or is the wrong version, and you don't have root access or don't want to upgrade Go, a script is provided to download Go and the gotop sources, compile gotop, and then clean up. See `scripts/install_without_root.sh`. From b767f7fbda1f63a14b00284994afc5894bfb6a17 Mon Sep 17 00:00:00 2001 From: "Sean E. Russell" Date: Wed, 1 Jul 2020 16:03:40 -0500 Subject: [PATCH 5/6] Cleaned up previous commit. --- README.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/README.md b/README.md index eb69fac..6956921 100644 --- a/README.md +++ b/README.md @@ -69,11 +69,6 @@ go build -o gotop \ ./cmd/gotop ``` - go build \ - -gcflags "all=-trimpath=${PWD}" \ - -asmflags "all=-trimpath=${PWD}" \ - -ldflags "-X main.Version=v${VERSION} -X main.BuildDate=${BUILDDATE} -extldflags ${LDFLAGS}" \ - ./cmd/gotop Move `gotop` to somewhere in your `$PATH`. If Go is not installed or is the wrong version, and you don't have root access or don't want to upgrade Go, a script is provided to download Go and the gotop sources, compile gotop, and then clean up. See `scripts/install_without_root.sh`. From fa9357d1ed084529e75fe7e04457c45d30843601 Mon Sep 17 00:00:00 2001 From: "Sean E. Russell" Date: Sat, 25 Jul 2020 07:21:15 -0500 Subject: [PATCH 6/6] Closes #32. Average is really average, over time. Boldify the AVRG label. Remove spurious sync lock. --- cmd/gotop/main.go | 1 - config_test.go | 1 - devices/cpu_cpu.go | 1 - go.mod | 1 + go.sum | 2 ++ termui/linegraph.go | 10 ++++++-- widgets/cpu.go | 58 +++++++++++++++++++-------------------------- 7 files changed, 36 insertions(+), 38 deletions(-) diff --git a/cmd/gotop/main.go b/cmd/gotop/main.go index c917fc7..f9f6618 100644 --- a/cmd/gotop/main.go +++ b/cmd/gotop/main.go @@ -332,7 +332,6 @@ func eventLoop(c gotop.Config, grid *layout.MyGrid) { } } -// TODO: state:merge #135 linux console font (cmatsuoka/console-font) func main() { // TODO: Make this an option, for performance testing //go func() { diff --git a/config_test.go b/config_test.go index 4afb44d..1f4ecb0 100644 --- a/config_test.go +++ b/config_test.go @@ -9,7 +9,6 @@ import ( "github.com/xxxserxxx/gotop/v4/widgets" ) -// FIXME This is totally broken since the updates func TestParse(t *testing.T) { tests := []struct { i string diff --git a/devices/cpu_cpu.go b/devices/cpu_cpu.go index bd2f891..9847572 100644 --- a/devices/cpu_cpu.go +++ b/devices/cpu_cpu.go @@ -6,7 +6,6 @@ import ( psCpu "github.com/shirou/gopsutil/cpu" ) -// FIXME: broken % under Linux. Doesn't reflect reality *at all*. func init() { f := func(cpus map[string]int, l bool) map[string]error { cpuCount, err := CpuCount() diff --git a/go.mod b/go.mod index 70e6a96..1e07313 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/xxxserxxx/gotop/v4 require ( github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect github.com/VictoriaMetrics/metrics v1.11.2 + github.com/VividCortex/ewma v1.1.1 github.com/distatus/battery v0.9.0 github.com/gizak/termui/v3 v3.1.0 github.com/go-ole/go-ole v1.2.4 // indirect diff --git a/go.sum b/go.sum index fd648f6..575a44b 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUW github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VictoriaMetrics/metrics v1.11.2 h1:t/ceLP6SvagUqypCKU7cI7+tQn54+TIV/tGoxihHvx8= github.com/VictoriaMetrics/metrics v1.11.2/go.mod h1:LU2j9qq7xqZYXz8tF3/RQnB2z2MbZms5TDiIg9/NHiQ= +github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM= +github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= github.com/cjbassi/drawille-go v0.0.0-20190126131713-27dc511fe6fd h1:XtfPmj9tQRilnrEmI1HjQhxXWRhEM+m8CACtaMJE/kM= github.com/cjbassi/drawille-go v0.0.0-20190126131713-27dc511fe6fd/go.mod h1:vjcQJUZJYD3MeVGhtZXSMnCHfUNZxsyYzJt90eCYxK4= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= diff --git a/termui/linegraph.go b/termui/linegraph.go index db15822..fa8a3ae 100644 --- a/termui/linegraph.go +++ b/termui/linegraph.go @@ -25,6 +25,7 @@ type LineGraph struct { HorizontalScale int LineColors map[string]Color + LabelStyles map[string]Modifier DefaultLineColor Color } @@ -37,7 +38,8 @@ func NewLineGraph() *LineGraph { HorizontalScale: 5, - LineColors: make(map[string]Color), + LineColors: make(map[string]Color), + LabelStyles: make(map[string]Modifier), } } @@ -136,6 +138,10 @@ func (self *LineGraph) Draw(buf *Buffer) { if !ok { seriesLineColor = self.DefaultLineColor } + seriesLabelStyle, ok := self.LabelStyles[seriesName] + if !ok { + seriesLabelStyle = ModifierClear + } // render key ontop, but let braille be drawn over space characters str := seriesName + " " + self.Labels[seriesName] @@ -145,7 +151,7 @@ func (self *LineGraph) Draw(buf *Buffer) { for k, char := range str { if char != ' ' { buf.SetCell( - NewCell(char, NewStyle(seriesLineColor)), + NewCell(char, NewStyle(seriesLineColor, ColorClear, seriesLabelStyle)), image.Pt(xoff+self.Inner.Min.X+2+k, yoff+self.Inner.Min.Y+i+1), ) } diff --git a/widgets/cpu.go b/widgets/cpu.go index d8d9a50..2668b3a 100644 --- a/widgets/cpu.go +++ b/widgets/cpu.go @@ -2,12 +2,13 @@ package widgets import ( "fmt" - "sync" "time" "github.com/VictoriaMetrics/metrics" + "github.com/VividCortex/ewma" "github.com/xxxserxxx/gotop/v4/devices" + "github.com/gizak/termui/v3" ui "github.com/xxxserxxx/gotop/v4/termui" ) @@ -17,8 +18,8 @@ type CPUWidget struct { ShowAverageLoad bool ShowPerCPULoad bool updateInterval time.Duration - updateLock sync.Mutex cpuLoads map[string]float64 + average ewma.MovingAverage } var cpuLabels []string @@ -31,7 +32,9 @@ func NewCPUWidget(updateInterval time.Duration, horizontalScale int, showAverage ShowAverageLoad: showAverageLoad, ShowPerCPULoad: showPerCPULoad, cpuLoads: make(map[string]float64), + average: ewma.NewMovingAverage(), } + self.LabelStyles[AVRG] = termui.ModifierBold self.Title = " CPU Usage " self.HorizontalScale = horizontalScale @@ -44,7 +47,7 @@ func NewCPUWidget(updateInterval time.Duration, horizontalScale int, showAverage } if self.ShowAverageLoad { - self.Data["AVRG"] = []float64{0} + self.Data[AVRG] = []float64{0} } if self.ShowPerCPULoad { @@ -91,38 +94,27 @@ func (cpu *CPUWidget) Scale(i int) { } func (cpu *CPUWidget) update() { - if cpu.ShowAverageLoad { - go func() { - cpus := make(map[string]int) - devices.UpdateCPU(cpus, cpu.updateInterval, false) - cpu.Lock() - defer cpu.Unlock() - cpu.updateLock.Lock() - defer cpu.updateLock.Unlock() - var val float64 - for _, v := range cpus { - val = float64(v) - break - } - cpu.Data[AVRG] = append(cpu.Data[AVRG], val) - cpu.Labels[AVRG] = fmt.Sprintf("%3.0f%%", val) - cpu.cpuLoads[AVRG] = val - }() - } - - if cpu.ShowPerCPULoad { - go func() { - cpus := make(map[string]int) - devices.UpdateCPU(cpus, cpu.updateInterval, true) - cpu.Lock() - defer cpu.Unlock() - cpu.updateLock.Lock() - defer cpu.updateLock.Unlock() - for key, percent := range cpus { + go func() { + cpus := make(map[string]int) + devices.UpdateCPU(cpus, cpu.updateInterval, true) + cpu.Lock() + defer cpu.Unlock() + // AVG = ((AVG*i)+n)/(i+1) + var sum int + for key, percent := range cpus { + sum += percent + if cpu.ShowPerCPULoad { cpu.Data[key] = append(cpu.Data[key], float64(percent)) cpu.Labels[key] = fmt.Sprintf("%d%%", percent) cpu.cpuLoads[key] = float64(percent) } - }() - } + } + if cpu.ShowAverageLoad { + cpu.average.Add(float64(sum) / float64(len(cpus))) + avg := cpu.average.Value() + cpu.Data[AVRG] = append(cpu.Data[AVRG], avg) + cpu.Labels[AVRG] = fmt.Sprintf("%3.0f%%", avg) + cpu.cpuLoads[AVRG] = avg + } + }() }