cpu.go 5.3 KB

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