1package cpu 2 3import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "math" 8 "strconv" 9 "strings" 10 "sync" 11 "time" 12 13 "github.com/shirou/gopsutil/internal/common" 14) 15 16// TimesStat contains the amounts of time the CPU has spent performing different 17// kinds of work. Time units are in USER_HZ or Jiffies (typically hundredths of 18// a second). It is based on linux /proc/stat file. 19type TimesStat struct { 20 CPU string `json:"cpu"` 21 User float64 `json:"user"` 22 System float64 `json:"system"` 23 Idle float64 `json:"idle"` 24 Nice float64 `json:"nice"` 25 Iowait float64 `json:"iowait"` 26 Irq float64 `json:"irq"` 27 Softirq float64 `json:"softirq"` 28 Steal float64 `json:"steal"` 29 Guest float64 `json:"guest"` 30 GuestNice float64 `json:"guestNice"` 31} 32 33type InfoStat struct { 34 CPU int32 `json:"cpu"` 35 VendorID string `json:"vendorId"` 36 Family string `json:"family"` 37 Model string `json:"model"` 38 Stepping int32 `json:"stepping"` 39 PhysicalID string `json:"physicalId"` 40 CoreID string `json:"coreId"` 41 Cores int32 `json:"cores"` 42 ModelName string `json:"modelName"` 43 Mhz float64 `json:"mhz"` 44 CacheSize int32 `json:"cacheSize"` 45 Flags []string `json:"flags"` 46 Microcode string `json:"microcode"` 47} 48 49type lastPercent struct { 50 sync.Mutex 51 lastCPUTimes []TimesStat 52 lastPerCPUTimes []TimesStat 53} 54 55var lastCPUPercent lastPercent 56var invoke common.Invoker = common.Invoke{} 57 58func init() { 59 lastCPUPercent.Lock() 60 lastCPUPercent.lastCPUTimes, _ = Times(false) 61 lastCPUPercent.lastPerCPUTimes, _ = Times(true) 62 lastCPUPercent.Unlock() 63} 64 65// Counts returns the number of physical or logical cores in the system 66func Counts(logical bool) (int, error) { 67 return CountsWithContext(context.Background(), logical) 68} 69 70func (c TimesStat) String() string { 71 v := []string{ 72 `"cpu":"` + c.CPU + `"`, 73 `"user":` + strconv.FormatFloat(c.User, 'f', 1, 64), 74 `"system":` + strconv.FormatFloat(c.System, 'f', 1, 64), 75 `"idle":` + strconv.FormatFloat(c.Idle, 'f', 1, 64), 76 `"nice":` + strconv.FormatFloat(c.Nice, 'f', 1, 64), 77 `"iowait":` + strconv.FormatFloat(c.Iowait, 'f', 1, 64), 78 `"irq":` + strconv.FormatFloat(c.Irq, 'f', 1, 64), 79 `"softirq":` + strconv.FormatFloat(c.Softirq, 'f', 1, 64), 80 `"steal":` + strconv.FormatFloat(c.Steal, 'f', 1, 64), 81 `"guest":` + strconv.FormatFloat(c.Guest, 'f', 1, 64), 82 `"guestNice":` + strconv.FormatFloat(c.GuestNice, 'f', 1, 64), 83 } 84 85 return `{` + strings.Join(v, ",") + `}` 86} 87 88// Total returns the total number of seconds in a CPUTimesStat 89func (c TimesStat) Total() float64 { 90 total := c.User + c.System + c.Nice + c.Iowait + c.Irq + c.Softirq + 91 c.Steal + c.Idle 92 return total 93} 94 95func (c InfoStat) String() string { 96 s, _ := json.Marshal(c) 97 return string(s) 98} 99 100func getAllBusy(t TimesStat) (float64, float64) { 101 busy := t.User + t.System + t.Nice + t.Iowait + t.Irq + 102 t.Softirq + t.Steal 103 return busy + t.Idle, busy 104} 105 106func calculateBusy(t1, t2 TimesStat) float64 { 107 t1All, t1Busy := getAllBusy(t1) 108 t2All, t2Busy := getAllBusy(t2) 109 110 if t2Busy <= t1Busy { 111 return 0 112 } 113 if t2All <= t1All { 114 return 100 115 } 116 return math.Min(100, math.Max(0, (t2Busy-t1Busy)/(t2All-t1All)*100)) 117} 118 119func calculateAllBusy(t1, t2 []TimesStat) ([]float64, error) { 120 // Make sure the CPU measurements have the same length. 121 if len(t1) != len(t2) { 122 return nil, fmt.Errorf( 123 "received two CPU counts: %d != %d", 124 len(t1), len(t2), 125 ) 126 } 127 128 ret := make([]float64, len(t1)) 129 for i, t := range t2 { 130 ret[i] = calculateBusy(t1[i], t) 131 } 132 return ret, nil 133} 134 135// Percent calculates the percentage of cpu used either per CPU or combined. 136// If an interval of 0 is given it will compare the current cpu times against the last call. 137// Returns one value per cpu, or a single value if percpu is set to false. 138func Percent(interval time.Duration, percpu bool) ([]float64, error) { 139 return PercentWithContext(context.Background(), interval, percpu) 140} 141 142func PercentWithContext(ctx context.Context, interval time.Duration, percpu bool) ([]float64, error) { 143 if interval <= 0 { 144 return percentUsedFromLastCall(percpu) 145 } 146 147 // Get CPU usage at the start of the interval. 148 cpuTimes1, err := Times(percpu) 149 if err != nil { 150 return nil, err 151 } 152 153 time.Sleep(interval) 154 155 // And at the end of the interval. 156 cpuTimes2, err := Times(percpu) 157 if err != nil { 158 return nil, err 159 } 160 161 return calculateAllBusy(cpuTimes1, cpuTimes2) 162} 163 164func percentUsedFromLastCall(percpu bool) ([]float64, error) { 165 cpuTimes, err := Times(percpu) 166 if err != nil { 167 return nil, err 168 } 169 lastCPUPercent.Lock() 170 defer lastCPUPercent.Unlock() 171 var lastTimes []TimesStat 172 if percpu { 173 lastTimes = lastCPUPercent.lastPerCPUTimes 174 lastCPUPercent.lastPerCPUTimes = cpuTimes 175 } else { 176 lastTimes = lastCPUPercent.lastCPUTimes 177 lastCPUPercent.lastCPUTimes = cpuTimes 178 } 179 180 if lastTimes == nil { 181 return nil, fmt.Errorf("error getting times for cpu percent. lastTimes was nil") 182 } 183 return calculateAllBusy(lastTimes, cpuTimes) 184} 185