Memoize the CPU stats. Error if CPU fingerprinting fails.

This commit is contained in:
Sean Chittenden
2016-06-17 12:13:53 -07:00
parent e42f7d5c23
commit e26606acfd
2 changed files with 72 additions and 63 deletions

View File

@@ -5,8 +5,8 @@ import (
"log"
"github.com/hashicorp/nomad/client/config"
"github.com/hashicorp/nomad/helper/stats"
"github.com/hashicorp/nomad/nomad/structs"
"github.com/shirou/gopsutil/cpu"
)
// CPUFingerprint is used to fingerprint the CPU
@@ -22,55 +22,32 @@ func NewCPUFingerprint(logger *log.Logger) Fingerprint {
}
func (f *CPUFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
cpuInfo, err := cpu.Info()
if err != nil {
f.logger.Println("[WARN] Error reading CPU information:", err)
if err := stats.Init(); err != nil {
f.logger.Printf("[FATAL] fingerprint.cpu: unable to obtain CPU information: %v", err)
return false, err
}
// Assume all CPUs found have same Model and MHz. If cpu.Info()
// returns nil above, this loop is still safe.
var mhz float64
var modelName string
for _, c := range cpuInfo {
mhz = c.Mhz
modelName = c.ModelName
break
}
// Allow for a little precision slop
if mhz < 1.0 {
f.logger.Println("[WARN] fingerprint.cpu: Unable to obtain the CPU Mhz")
} else {
node.Attributes["cpu.frequency"] = fmt.Sprintf("%.6f", mhz)
f.logger.Printf("[DEBUG] fingerprint.cpu: frequency: %02.1f MHz", mhz)
}
var numCores int
if numCores, err = cpu.Counts(true); err != nil {
numCores = 1
f.logger.Println("[WARN] Unable to obtain the number of CPUs, defaulting to %d CPU", numCores)
}
if numCores > 0 {
node.Attributes["cpu.numcores"] = fmt.Sprintf("%d", numCores)
f.logger.Printf("[DEBUG] fingerprint.cpu: core count: %d", numCores)
}
if mhz > 0 && numCores > 0 {
tc := float64(numCores) * mhz
node.Attributes["cpu.totalcompute"] = fmt.Sprintf("%.6f", tc)
if node.Resources == nil {
node.Resources = &structs.Resources{}
}
node.Resources.CPU = int(tc)
}
modelName := stats.CPUModelName()
if modelName != "" {
node.Attributes["cpu.modelname"] = modelName
}
mhz := stats.CPUMHzPerCore()
node.Attributes["cpu.frequency"] = fmt.Sprintf("%.6f", mhz)
f.logger.Printf("[DEBUG] fingerprint.cpu: frequency: %02.1f MHz", mhz)
numCores := stats.CPUNumCores()
node.Attributes["cpu.numcores"] = fmt.Sprintf("%d", numCores)
f.logger.Printf("[DEBUG] fingerprint.cpu: core count: %d", numCores)
tt := stats.TotalTicksAvailable()
node.Attributes["cpu.totalcompute"] = fmt.Sprintf("%.6f", tt)
if node.Resources == nil {
node.Resources = &structs.Resources{}
}
node.Resources.CPU = int(tt)
return true, nil
}

View File

@@ -1,30 +1,62 @@
package stats
import (
"github.com/shirou/gopsutil/cpu"
"fmt"
"sync"
"github.com/shirou/gopsutil/cpu"
)
var (
clkSpeed float64
ticksLock sync.Mutex
cpuMhzPerCore float64
cpuModelName string
cpuNumCores int
cpuTotalTicks float64
onceLer sync.Once
)
// TotalTicksAvailable calculates the total frequency available across all cores
func TotalTicksAvailable() float64 {
ticksLock.Lock()
defer ticksLock.Unlock()
if clkSpeed == 0.0 {
var cpuInfo []cpu.InfoStat
var err error
var totalTicks float64
if cpuInfo, err = cpu.Info(); err == nil {
for _, cpu := range cpuInfo {
totalTicks += cpu.Mhz
}
clkSpeed = totalTicks
func Init() error {
var err error
onceLer.Do(func() {
if cpuNumCores, err = cpu.Counts(true); err != nil {
err = fmt.Errorf("Unable to determine the number of CPU cores available: %v", err)
return
}
}
return clkSpeed
var cpuInfo []cpu.InfoStat
if cpuInfo, err = cpu.Info(); err != nil {
err = fmt.Errorf("Unable to obtain CPU information: %v", err)
return
}
for _, cpu := range cpuInfo {
cpuModelName = cpu.ModelName
cpuMhzPerCore = cpu.Mhz
break
}
cpuTotalTicks = float64(cpuNumCores) * cpuMhzPerCore
})
return err
}
// CPUModelName returns the number of CPU cores available
func CPUNumCores() int {
return cpuNumCores
}
// CPUMHzPerCore returns the MHz per CPU core
func CPUMHzPerCore() float64 {
return cpuMhzPerCore
}
// CPUModelName returns the model name of the CPU
func CPUModelName() string {
return cpuModelName
}
// TotalTicksAvailable calculates the total frequency available across all
// cores
func TotalTicksAvailable() float64 {
return cpuTotalTicks
}