cpu.go 4.9 KB

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