From 30cbfe1f71fcc1d3fb3e696561373c5cf29391c2 Mon Sep 17 00:00:00 2001 From: Diptanu Choudhury Date: Thu, 19 May 2016 13:32:03 -0700 Subject: [PATCH] Implemented cpu stats --- client/driver/docker.go | 16 ++++++++- client/driver/executor/executor.go | 11 +++++-- client/driver/executor/executor_linux.go | 4 +++ client/stats/cpu.go | 41 ++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 client/stats/cpu.go diff --git a/client/driver/docker.go b/client/driver/docker.go index a91c7ceda..22f3042ed 100644 --- a/client/driver/docker.go +++ b/client/driver/docker.go @@ -990,7 +990,21 @@ func (h *DockerHandle) monitorUsage() { Swap: s.MemoryStats.Stats.Swap, MaxUsage: s.MemoryStats.MaxUsage, } - h.resourceUsage = &cstructs.TaskResourceUsage{MemoryStats: ms, Timestamp: s.Read} + + cs := &cstructs.CpuUsage{ + SystemMode: float64(s.CPUStats.CPUUsage.UsageInKernelmode), + UserMode: float64(s.CPUStats.CPUUsage.UsageInKernelmode), + ThrottledPeriods: s.CPUStats.ThrottlingData.ThrottledPeriods, + ThrottledTime: s.CPUStats.ThrottlingData.ThrottledTime, + } + // Calculate percentage + cs.Percent = 0.0 + cpuDelta := float64(s.CPUStats.CPUUsage.TotalUsage) - float64(s.PreCPUStats.CPUUsage.TotalUsage) + systemDelta := float64(s.CPUStats.SystemCPUUsage) - float64(s.PreCPUStats.SystemCPUUsage) + if cpuDelta > 0.0 && systemDelta > 0.0 { + cs.Percent = (cpuDelta / systemDelta) * float64(len(s.CPUStats.CPUUsage.PercpuUsage)) * 100.0 + } + h.resourceUsage = &cstructs.TaskResourceUsage{MemoryStats: ms, CpuStats: cs, Timestamp: s.Read} } case <-h.doneMonitoring: case <-h.doneCh: diff --git a/client/driver/executor/executor.go b/client/driver/executor/executor.go index 9b315deab..74fdfa4a9 100644 --- a/client/driver/executor/executor.go +++ b/client/driver/executor/executor.go @@ -24,6 +24,7 @@ import ( "github.com/hashicorp/nomad/client/driver/env" "github.com/hashicorp/nomad/client/driver/logging" cstructs "github.com/hashicorp/nomad/client/driver/structs" + "github.com/hashicorp/nomad/client/stats" "github.com/hashicorp/nomad/nomad/structs" ) @@ -171,15 +172,22 @@ type UniversalExecutor struct { consulService *consul.ConsulService consulCtx *ConsulContext + cpuStats *stats.CpuStats logger *log.Logger } // NewExecutor returns an Executor func NewExecutor(logger *log.Logger) Executor { - return &UniversalExecutor{ + exec := &UniversalExecutor{ logger: logger, processExited: make(chan interface{}), } + + if cpuStats, err := stats.NewCpuStats(); err == nil { + exec.cpuStats = cpuStats + } + + return exec } // Version returns the api version of the executor @@ -676,7 +684,6 @@ func (e *UniversalExecutor) collectPids() { select { case <-timer.C: pids, err := e.getAllPids() - e.logger.Printf("DIPTANU PIDS %#v", pids) timer.Reset(pidScanInterval) if err != nil { e.logger.Printf("[DEBUG] executor: error collecting pids: %v", err) diff --git a/client/driver/executor/executor_linux.go b/client/driver/executor/executor_linux.go index 513c6e2ea..2a77ad907 100644 --- a/client/driver/executor/executor_linux.go +++ b/client/driver/executor/executor_linux.go @@ -150,6 +150,7 @@ func (e *UniversalExecutor) Stats() (*cstructs.TaskResourceUsage, error) { } // CPU Related Stats + totalProcessCPUUsage := stats.CpuStats.CpuUsage.TotalUsage userModeTime := stats.CpuStats.CpuUsage.UsageInUsermode kernelModeTime := stats.CpuStats.CpuUsage.UsageInKernelmode @@ -162,6 +163,9 @@ func (e *UniversalExecutor) Stats() (*cstructs.TaskResourceUsage, error) { ThrottledPeriods: stats.CpuStats.ThrottlingData.ThrottledPeriods, ThrottledTime: stats.CpuStats.ThrottlingData.ThrottledTime, } + if e.cpuStats != nil { + cs.Percent = e.cpuStats.Percent(totalProcessCPUUsage) + } return &cstructs.TaskResourceUsage{MemoryStats: ms, CpuStats: cs, Timestamp: time.Now()}, nil } diff --git a/client/stats/cpu.go b/client/stats/cpu.go new file mode 100644 index 000000000..351f81dc5 --- /dev/null +++ b/client/stats/cpu.go @@ -0,0 +1,41 @@ +package stats + +import ( + "github.com/shirou/gopsutil/cpu" +) + +type CpuStats struct { + prevSystemUsage float64 + prevProcessUsage uint64 + + totalCpus int +} + +func NewCpuStats() (*CpuStats, error) { + cpuInfo, err := cpu.Info() + if err != nil { + return nil, err + } + return &CpuStats{totalCpus: len(cpuInfo)}, nil +} + +func (c *CpuStats) Percent(currentProcessUsage uint64) float64 { + percent := 0.0 + + sysCPUStats, err := cpu.Times(false) + if err != nil { + return 0 + } + currentSysUsage := 0.0 + for _, cpuStat := range sysCPUStats { + currentSysUsage += cpuStat.Total() * 1000000000 + } + + delta := float64(currentProcessUsage) - float64(c.prevProcessUsage) + sysDelta := float64(currentSysUsage) - float64(c.prevSystemUsage) + + percent = (delta / sysDelta) * float64(c.totalCpus) * 100.0 + c.prevSystemUsage = currentSysUsage + c.prevProcessUsage = currentProcessUsage + return percent +}