Note, dependency has to be pinned to a specific release version commit hashes since it doesn't follow Go module v2+ guidelines. see: https://github.com/shirou/gopsutil/issues/663 https://github.com/golang/go/issues/34402
		
			
				
	
	
		
			185 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			185 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package cpu
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"encoding/json"
 | 
						|
	"fmt"
 | 
						|
	"math"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
	"sync"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/shirou/gopsutil/internal/common"
 | 
						|
)
 | 
						|
 | 
						|
// TimesStat contains the amounts of time the CPU has spent performing different
 | 
						|
// kinds of work. Time units are in USER_HZ or Jiffies (typically hundredths of
 | 
						|
// a second). It is based on linux /proc/stat file.
 | 
						|
type TimesStat struct {
 | 
						|
	CPU       string  `json:"cpu"`
 | 
						|
	User      float64 `json:"user"`
 | 
						|
	System    float64 `json:"system"`
 | 
						|
	Idle      float64 `json:"idle"`
 | 
						|
	Nice      float64 `json:"nice"`
 | 
						|
	Iowait    float64 `json:"iowait"`
 | 
						|
	Irq       float64 `json:"irq"`
 | 
						|
	Softirq   float64 `json:"softirq"`
 | 
						|
	Steal     float64 `json:"steal"`
 | 
						|
	Guest     float64 `json:"guest"`
 | 
						|
	GuestNice float64 `json:"guestNice"`
 | 
						|
}
 | 
						|
 | 
						|
type InfoStat struct {
 | 
						|
	CPU        int32    `json:"cpu"`
 | 
						|
	VendorID   string   `json:"vendorId"`
 | 
						|
	Family     string   `json:"family"`
 | 
						|
	Model      string   `json:"model"`
 | 
						|
	Stepping   int32    `json:"stepping"`
 | 
						|
	PhysicalID string   `json:"physicalId"`
 | 
						|
	CoreID     string   `json:"coreId"`
 | 
						|
	Cores      int32    `json:"cores"`
 | 
						|
	ModelName  string   `json:"modelName"`
 | 
						|
	Mhz        float64  `json:"mhz"`
 | 
						|
	CacheSize  int32    `json:"cacheSize"`
 | 
						|
	Flags      []string `json:"flags"`
 | 
						|
	Microcode  string   `json:"microcode"`
 | 
						|
}
 | 
						|
 | 
						|
type lastPercent struct {
 | 
						|
	sync.Mutex
 | 
						|
	lastCPUTimes    []TimesStat
 | 
						|
	lastPerCPUTimes []TimesStat
 | 
						|
}
 | 
						|
 | 
						|
var lastCPUPercent lastPercent
 | 
						|
var invoke common.Invoker = common.Invoke{}
 | 
						|
 | 
						|
func init() {
 | 
						|
	lastCPUPercent.Lock()
 | 
						|
	lastCPUPercent.lastCPUTimes, _ = Times(false)
 | 
						|
	lastCPUPercent.lastPerCPUTimes, _ = Times(true)
 | 
						|
	lastCPUPercent.Unlock()
 | 
						|
}
 | 
						|
 | 
						|
// Counts returns the number of physical or logical cores in the system
 | 
						|
func Counts(logical bool) (int, error) {
 | 
						|
	return CountsWithContext(context.Background(), logical)
 | 
						|
}
 | 
						|
 | 
						|
func (c TimesStat) String() string {
 | 
						|
	v := []string{
 | 
						|
		`"cpu":"` + c.CPU + `"`,
 | 
						|
		`"user":` + strconv.FormatFloat(c.User, 'f', 1, 64),
 | 
						|
		`"system":` + strconv.FormatFloat(c.System, 'f', 1, 64),
 | 
						|
		`"idle":` + strconv.FormatFloat(c.Idle, 'f', 1, 64),
 | 
						|
		`"nice":` + strconv.FormatFloat(c.Nice, 'f', 1, 64),
 | 
						|
		`"iowait":` + strconv.FormatFloat(c.Iowait, 'f', 1, 64),
 | 
						|
		`"irq":` + strconv.FormatFloat(c.Irq, 'f', 1, 64),
 | 
						|
		`"softirq":` + strconv.FormatFloat(c.Softirq, 'f', 1, 64),
 | 
						|
		`"steal":` + strconv.FormatFloat(c.Steal, 'f', 1, 64),
 | 
						|
		`"guest":` + strconv.FormatFloat(c.Guest, 'f', 1, 64),
 | 
						|
		`"guestNice":` + strconv.FormatFloat(c.GuestNice, 'f', 1, 64),
 | 
						|
	}
 | 
						|
 | 
						|
	return `{` + strings.Join(v, ",") + `}`
 | 
						|
}
 | 
						|
 | 
						|
// Total returns the total number of seconds in a CPUTimesStat
 | 
						|
func (c TimesStat) Total() float64 {
 | 
						|
	total := c.User + c.System + c.Nice + c.Iowait + c.Irq + c.Softirq + c.Steal +
 | 
						|
		c.Guest + c.GuestNice + c.Idle
 | 
						|
	return total
 | 
						|
}
 | 
						|
 | 
						|
func (c InfoStat) String() string {
 | 
						|
	s, _ := json.Marshal(c)
 | 
						|
	return string(s)
 | 
						|
}
 | 
						|
 | 
						|
func getAllBusy(t TimesStat) (float64, float64) {
 | 
						|
	busy := t.User + t.System + t.Nice + t.Iowait + t.Irq +
 | 
						|
		t.Softirq + t.Steal + t.Guest + t.GuestNice
 | 
						|
	return busy + t.Idle, busy
 | 
						|
}
 | 
						|
 | 
						|
func calculateBusy(t1, t2 TimesStat) float64 {
 | 
						|
	t1All, t1Busy := getAllBusy(t1)
 | 
						|
	t2All, t2Busy := getAllBusy(t2)
 | 
						|
 | 
						|
	if t2Busy <= t1Busy {
 | 
						|
		return 0
 | 
						|
	}
 | 
						|
	if t2All <= t1All {
 | 
						|
		return 100
 | 
						|
	}
 | 
						|
	return math.Min(100, math.Max(0, (t2Busy-t1Busy)/(t2All-t1All)*100))
 | 
						|
}
 | 
						|
 | 
						|
func calculateAllBusy(t1, t2 []TimesStat) ([]float64, error) {
 | 
						|
	// Make sure the CPU measurements have the same length.
 | 
						|
	if len(t1) != len(t2) {
 | 
						|
		return nil, fmt.Errorf(
 | 
						|
			"received two CPU counts: %d != %d",
 | 
						|
			len(t1), len(t2),
 | 
						|
		)
 | 
						|
	}
 | 
						|
 | 
						|
	ret := make([]float64, len(t1))
 | 
						|
	for i, t := range t2 {
 | 
						|
		ret[i] = calculateBusy(t1[i], t)
 | 
						|
	}
 | 
						|
	return ret, nil
 | 
						|
}
 | 
						|
 | 
						|
// Percent calculates the percentage of cpu used either per CPU or combined.
 | 
						|
// If an interval of 0 is given it will compare the current cpu times against the last call.
 | 
						|
// Returns one value per cpu, or a single value if percpu is set to false.
 | 
						|
func Percent(interval time.Duration, percpu bool) ([]float64, error) {
 | 
						|
	return PercentWithContext(context.Background(), interval, percpu)
 | 
						|
}
 | 
						|
 | 
						|
func PercentWithContext(ctx context.Context, interval time.Duration, percpu bool) ([]float64, error) {
 | 
						|
	if interval <= 0 {
 | 
						|
		return percentUsedFromLastCall(percpu)
 | 
						|
	}
 | 
						|
 | 
						|
	// Get CPU usage at the start of the interval.
 | 
						|
	cpuTimes1, err := Times(percpu)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	time.Sleep(interval)
 | 
						|
 | 
						|
	// And at the end of the interval.
 | 
						|
	cpuTimes2, err := Times(percpu)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return calculateAllBusy(cpuTimes1, cpuTimes2)
 | 
						|
}
 | 
						|
 | 
						|
func percentUsedFromLastCall(percpu bool) ([]float64, error) {
 | 
						|
	cpuTimes, err := Times(percpu)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	lastCPUPercent.Lock()
 | 
						|
	defer lastCPUPercent.Unlock()
 | 
						|
	var lastTimes []TimesStat
 | 
						|
	if percpu {
 | 
						|
		lastTimes = lastCPUPercent.lastPerCPUTimes
 | 
						|
		lastCPUPercent.lastPerCPUTimes = cpuTimes
 | 
						|
	} else {
 | 
						|
		lastTimes = lastCPUPercent.lastCPUTimes
 | 
						|
		lastCPUPercent.lastCPUTimes = cpuTimes
 | 
						|
	}
 | 
						|
 | 
						|
	if lastTimes == nil {
 | 
						|
		return nil, fmt.Errorf("error getting times for cpu percent. lastTimes was nil")
 | 
						|
	}
 | 
						|
	return calculateAllBusy(lastTimes, cpuTimes)
 | 
						|
}
 |