mirror of
https://github.com/kemko/nomad.git
synced 2026-01-03 08:55:43 +03:00
Memoize the CPU stats. Error if CPU fingerprinting fails.
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user