Browse Source

Properly report CPU Usage

Oz Tiram 5 years ago
parent
commit
e7006200df
3 changed files with 72 additions and 27 deletions
  1. 18 9
      cmd/main.go
  2. 43 14
      gupta.go
  3. 11 4
      gupta_test.go

+ 18 - 9
cmd/main.go

@@ -10,6 +10,17 @@ import (
 	"time"
 )
 
+func readProcStatLine() string {
+	f, err := os.Open("/proc/stat")
+	defer f.Close()
+	rd := bufio.NewReader(f)
+	line, err := rd.ReadString('\n')
+	if err != nil {
+		log.Fatalf("could not read /proc/stat, error: %v", err)
+	}
+	return line
+}
+
 func main() {
 	var freq int
 	var partition, netInterface string
@@ -24,19 +35,17 @@ func main() {
 	flag.StringVar(&netInterface, "n", "", "Network usage (interface)")
 
 	flag.Parse()
-	f, err := os.Open("/proc/stat")
-	defer f.Close()
-	rd := bufio.NewReader(f)
-	line, err := rd.ReadString('\n')
-	if err != nil {
-		log.Fatalf("could not read /proc/stat, error: %v", err)
-	}
 
 	fmt.Println(gupta.Hello())
+	line := readProcStatLine()
+	time.Sleep(time.Second)
+	lineNew := readProcStatLine()
 
 	for true {
-		cpustat := gupta.NewCPUStat(line)
-		fmt.Printf("cpustat %d\n", cpustat.User)
+		cpustat := gupta.NewCPUStat(line, lineNew)
+		fmt.Printf("cpustat %.2f\n", cpustat.CPUUsage())
 		time.Sleep(time.Duration(freq) * time.Second)
+		line = lineNew
+		lineNew = readProcStatLine()
 	}
 }

+ 43 - 14
gupta.go

@@ -31,19 +31,22 @@ func (g *GuptaReport) GetCPULoad() string {
 
 // collect all CPU stat from /proc/cpustat
 type CPUStat struct {
-	user       uint64
-	nice       uint64
-	system     uint64
-	idle       uint64
-	iowait     uint64
-	irq        uint64
-	softirq    uint64
-	steal      uint64
-	guest      uint64
-	guest_nice uint64
+	user         uint64
+	nice         uint64
+	system       uint64
+	idle         uint64
+	iowait       uint64
+	idleNew      uint64
+	iowaitNew    uint64
+	irq          uint64
+	softirq      uint64
+	steal        uint64
+	guest        uint64
+	guest_nice   uint64
+	totalTimeNew uint64
 }
 
-// parse the first line of /proc/cpustat
+// parse the first line of /proc/cpustat without the word cpu
 func (c *CPUStat) ReadInfo(rawInfo []string) {
 	if s, err := strconv.ParseUint(rawInfo[0], 10, 64); err == nil {
 		c.user = s
@@ -77,21 +80,47 @@ func (c *CPUStat) ReadInfo(rawInfo []string) {
 	}
 }
 
+func (c *CPUStat) ReadInfoNew(rawInfo []string) {
+	idleNew, _ := strconv.ParseUint(rawInfo[3], 10, 64)
+	iowaitNew, _ := strconv.ParseUint(rawInfo[4], 10, 64)
+	c.idleNew = idleNew
+	c.iowaitNew = iowaitNew
+
+	for _, s := range rawInfo {
+		u, _ := strconv.ParseUint(s, 10, 64)
+		c.totalTimeNew += u
+	}
+}
+
 func (c *CPUStat) TotalTime() uint64 {
 	return c.user + c.nice + c.system + c.idle + c.iowait + c.irq + c.softirq + c.steal
 }
 
+func (c *CPUStat) TotalTimeNew() uint64 {
+	return c.totalTimeNew
+}
+
 func (c *CPUStat) IdleTime() uint64 {
 	return c.idle + c.iowait
 }
 
-func (c *CPUStat) CPUUsage() uint64 {
-	return c.TotalTime() - c.IdleTime()
+func (c *CPUStat) IdleTimeNew() uint64 {
+	return c.idleNew + c.iowaitNew
+}
+
+func (c *CPUStat) CPUUsage() float64 {
+	deltaIdleTime := c.IdleTimeNew() - c.IdleTime()
+	deltaTotalTime := c.TotalTimeNew() - c.TotalTime()
+	cpuUsage := (1.0 - float64(deltaIdleTime)/float64(deltaTotalTime)) * 100
+	return cpuUsage
 }
 
-func NewCPUStat(procstatline string) CPUStat {
+func NewCPUStat(procstatline, procstatlineNew string) CPUStat {
 	cpustat := CPUStat{}
 	statline := strings.Fields(procstatline)
+	statlineNew := strings.Fields(procstatlineNew)
+
 	cpustat.ReadInfo(statline[1:])
+	cpustat.ReadInfoNew(statlineNew[1:])
 	return cpustat
 }

+ 11 - 4
gupta_test.go

@@ -36,7 +36,9 @@ func TestCPUStat(t *testing.T) {
 	//               0    1    2     3     4     5      6     7       8     9     10
 	//               cpu user nice system idle iowait  irq  softirq steal guest guest_nice
 	procstatLine := "cpu 4705 356  584    3699   23    23     0       0     0    0"
-	cpustat := NewCPUStat(procstatLine)
+	procstatLineNew := "cpu 4875 356  584    3779   23    23     0       0     0    0"
+
+	cpustat := NewCPUStat(procstatLine, procstatLineNew)
 
 	t.Run("Test that gupta hast Report", func(t *testing.T) {
 
@@ -104,10 +106,15 @@ func TestCPUStat(t *testing.T) {
 	})
 
 	t.Run("Test that CPUUsage calculates properly", func(t *testing.T) {
+		cpustat = NewCPUStat("cpu 657046 84 232824 4025519 2874 0 40555 0 0 0",
+			"cpu 657136 84 232952 4025695 2874 0 40555 0 0 0")
 
-		got := cpustat.CPUUsage()
-		want := uint64(5668)
-		assert(t, "CPUUsage", got, want)
+		got := fmt.Sprintf("%.2f", cpustat.CPUUsage())
+		want := "55.33"
+		name := "CPUUsate"
+		if got != want {
+			t.Errorf("got  %s %s want %s", name, got, want)
+		}
 
 	})
 }