Implemented nomad cpu percentage calculator

This commit is contained in:
Diptanu Choudhury 2016-05-20 02:05:48 -07:00
parent 2f06fa8e63
commit 22c3f6fee0
5 changed files with 53 additions and 58 deletions

View file

@ -130,6 +130,11 @@ type ProcessState struct {
Time time.Time
}
type NomadPid struct {
pid int
cpuStats *stats.CpuStats
}
// SyslogServerState holds the address and islation information of a launched
// syslog server
type SyslogServerState struct {
@ -154,7 +159,7 @@ type UniversalExecutor struct {
ctx *ExecutorContext
command *ExecCommand
pids []int
pids []*NomadPid
taskDir string
exitState *ProcessState
processExited chan interface{}
@ -181,10 +186,7 @@ func NewExecutor(logger *log.Logger) Executor {
exec := &UniversalExecutor{
logger: logger,
processExited: make(chan interface{}),
}
if cpuStats, err := stats.NewCpuStats(); err == nil {
exec.cpuStats = cpuStats
cpuStats: stats.NewCpuStats(logger),
}
return exec
@ -483,31 +485,27 @@ func (e *UniversalExecutor) PidStats() (map[int]*cstructs.TaskResourceUsage, err
stats := make(map[int]*cstructs.TaskResourceUsage)
ts := time.Now()
for _, pid := range e.pids {
p, err := process.NewProcess(int32(pid))
p, err := process.NewProcess(int32(pid.pid))
if err != nil {
e.logger.Printf("[DEBUG] executor: unable to create new process with pid: %v", pid)
e.logger.Printf("[DEBUG] executor: unable to create new process with pid: %v", pid.pid)
continue
}
memInfo, err := p.MemoryInfo()
if err != nil {
e.logger.Printf("[DEBUG] executor: unable to get memory stats for process: %v", pid)
}
cpuStats, err := p.Times()
if err != nil {
e.logger.Printf("[DEBUG] executor: unable to get cpu stats for process: %v", pid)
}
ms := &cstructs.MemoryStats{
RSS: memInfo.RSS,
Swap: memInfo.Swap,
ms := &cstructs.MemoryStats{}
if memInfo, err := p.MemoryInfo(); err == nil {
ms.RSS = memInfo.RSS
ms.Swap = memInfo.Swap
}
percent, _ := p.Percent(0)
cs := &cstructs.CpuUsage{
SystemMode: cpuStats.System,
UserMode: cpuStats.User,
Percent: percent,
cs := &cstructs.CpuUsage{}
if cpuStats, err := p.Times(); err == nil {
cs.SystemMode = cpuStats.System
cs.UserMode = cpuStats.User
// calculate cpu usage percent
cs.Percent = pid.cpuStats.Percent(cpuStats.Total())
e.logger.Printf("DIPTANU CPU PERCENT for pid %v: %v", pid.pid, cs.Percent)
}
stats[pid] = &cstructs.TaskResourceUsage{MemoryStats: ms, CpuStats: cs, Timestamp: ts}
stats[pid.pid] = &cstructs.TaskResourceUsage{MemoryStats: ms, CpuStats: cs, Timestamp: ts}
}
return stats, nil
@ -698,7 +696,7 @@ func (e *UniversalExecutor) collectPids() {
// scanPids scans all the pids on the machine running the current executor and
// returns the child processes of the executor.
func (e *UniversalExecutor) scanPids() ([]int, error) {
func (e *UniversalExecutor) scanPids() ([]*NomadPid, error) {
processFamily := make(map[int]struct{})
processFamily[os.Getpid()] = struct{}{}
pids, err := ps.Processes()
@ -712,9 +710,9 @@ func (e *UniversalExecutor) scanPids() ([]int, error) {
processFamily[pid.Pid()] = struct{}{}
}
}
res := make([]int, 0, len(processFamily))
res := make([]*NomadPid, 0, len(processFamily))
for pid := range processFamily {
res = append(res, pid)
res = append(res, &NomadPid{pid, stats.NewCpuStats(e.logger)})
}
return res, nil
}

View file

@ -35,6 +35,6 @@ func (e *UniversalExecutor) Stats() (*cstructs.TaskResourceUsage, error) {
return e.resourceUsagePids()
}
func (e *UniversalExecutor) getAllPids() ([]int, error) {
func (e *UniversalExecutor) getAllPids() ([]*NomadPid, error) {
return e.scanPids()
}

View file

@ -18,6 +18,7 @@ import (
"github.com/hashicorp/nomad/client/allocdir"
cstructs "github.com/hashicorp/nomad/client/driver/structs"
"github.com/hashicorp/nomad/client/stats"
"github.com/hashicorp/nomad/nomad/structs"
)
@ -164,7 +165,7 @@ func (e *UniversalExecutor) Stats() (*cstructs.TaskResourceUsage, error) {
ThrottledTime: stats.CpuStats.ThrottlingData.ThrottledTime,
}
if e.cpuStats != nil {
cs.Percent = e.cpuStats.Percent(totalProcessCPUUsage)
cs.Percent = e.cpuStats.Percent(float64(totalProcessCPUUsage))
}
return &cstructs.TaskResourceUsage{MemoryStats: ms, CpuStats: cs, Timestamp: time.Now()}, nil
}
@ -239,10 +240,18 @@ func (e *UniversalExecutor) removeChrootMounts() error {
return e.ctx.AllocDir.UnmountAll()
}
func (e *UniversalExecutor) getAllPids() ([]int, error) {
func (e *UniversalExecutor) getAllPids() ([]*NomadPid, error) {
if e.command.ResourceLimits {
manager := getCgroupManager(e.groups, e.cgPaths)
return manager.GetAllPids()
pids, err := manager.GetAllPids()
if err != nil {
return nil, err
}
np := make([]*NomadPid, len(pids))
for idx, pid := range pids {
np[idx] = &NomadPid{pid, stats.NewCpuStats(e.logger)}
}
return np, nil
}
return e.scanPids()
}

View file

@ -1,41 +1,29 @@
package stats
import (
"github.com/shirou/gopsutil/cpu"
"log"
"runtime"
"time"
)
type CpuStats struct {
prevSystemUsage float64
prevProcessUsage uint64
prevProcessUsage float64
prevTime time.Time
totalCpus int
logger *log.Logger
}
func NewCpuStats() (*CpuStats, error) {
cpuInfo, err := cpu.Info()
if err != nil {
return nil, err
}
return &CpuStats{totalCpus: len(cpuInfo)}, nil
func NewCpuStats(logger *log.Logger) *CpuStats {
numCpus := runtime.NumCPU()
return &CpuStats{totalCpus: numCpus, logger: logger}
}
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
func (c *CpuStats) Percent(currentProcessUsage float64) float64 {
procDelta := float64(currentProcessUsage) - float64(c.prevProcessUsage)
delta := (time.Now().Sub(c.prevTime).Seconds()) * float64(c.totalCpus)
percent := ((procDelta / delta) * 1000) * float64(c.totalCpus)
c.prevProcessUsage = currentProcessUsage
return percent
}

View file

@ -137,7 +137,7 @@ func (f *StatsCommand) printTaskResourceUsage(task string, resourceUsage map[str
out = make([]string, 2)
out[0] = "Percent|Throttled Periods|Throttled Time"
percent := strconv.FormatFloat(tu.CpuStats.Percent, 'f', 2, 64)
out[1] = fmt.Sprintf("%v|%v|%v|%v", percent,
out[1] = fmt.Sprintf("%v|%v|%v", percent,
tu.CpuStats.ThrottledPeriods, tu.CpuStats.ThrottledTime)
f.Ui.Output(formatList(out))
}