cpu.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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/gofiber/fiber/v2/internal/gopsutil/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 (
  49. lastCPUPercent lastPercent
  50. invoke common.Invoker = common.Invoke{}
  51. )
  52. func init() {
  53. lastCPUPercent.Lock()
  54. lastCPUPercent.lastCPUTimes, _ = Times(false)
  55. lastCPUPercent.lastPerCPUTimes, _ = Times(true)
  56. lastCPUPercent.Unlock()
  57. }
  58. // Counts returns the number of physical or logical cores in the system
  59. func Counts(logical bool) (int, error) {
  60. return CountsWithContext(context.Background(), logical)
  61. }
  62. func (c TimesStat) String() string {
  63. v := []string{
  64. `"cpu":"` + c.CPU + `"`,
  65. `"user":` + strconv.FormatFloat(c.User, 'f', 1, 64),
  66. `"system":` + strconv.FormatFloat(c.System, 'f', 1, 64),
  67. `"idle":` + strconv.FormatFloat(c.Idle, 'f', 1, 64),
  68. `"nice":` + strconv.FormatFloat(c.Nice, 'f', 1, 64),
  69. `"iowait":` + strconv.FormatFloat(c.Iowait, 'f', 1, 64),
  70. `"irq":` + strconv.FormatFloat(c.Irq, 'f', 1, 64),
  71. `"softirq":` + strconv.FormatFloat(c.Softirq, 'f', 1, 64),
  72. `"steal":` + strconv.FormatFloat(c.Steal, 'f', 1, 64),
  73. `"guest":` + strconv.FormatFloat(c.Guest, 'f', 1, 64),
  74. `"guestNice":` + strconv.FormatFloat(c.GuestNice, 'f', 1, 64),
  75. }
  76. return `{` + strings.Join(v, ",") + `}`
  77. }
  78. // Total returns the total number of seconds in a CPUTimesStat
  79. func (c TimesStat) Total() float64 {
  80. total := c.User + c.System + c.Nice + c.Iowait + c.Irq + c.Softirq +
  81. c.Steal + c.Idle
  82. return total
  83. }
  84. func (c InfoStat) String() string {
  85. s, _ := json.Marshal(c)
  86. return string(s)
  87. }
  88. func getAllBusy(t TimesStat) (float64, float64) {
  89. busy := t.User + t.System + t.Nice + t.Iowait + t.Irq +
  90. t.Softirq + t.Steal
  91. return busy + t.Idle, busy
  92. }
  93. func calculateBusy(t1, t2 TimesStat) float64 {
  94. t1All, t1Busy := getAllBusy(t1)
  95. t2All, t2Busy := getAllBusy(t2)
  96. if t2Busy <= t1Busy {
  97. return 0
  98. }
  99. if t2All <= t1All {
  100. return 100
  101. }
  102. return math.Min(100, math.Max(0, (t2Busy-t1Busy)/(t2All-t1All)*100))
  103. }
  104. func calculateAllBusy(t1, t2 []TimesStat) ([]float64, error) {
  105. // Make sure the CPU measurements have the same length.
  106. if len(t1) != len(t2) {
  107. return nil, fmt.Errorf(
  108. "received two CPU counts: %d != %d",
  109. len(t1), len(t2),
  110. )
  111. }
  112. ret := make([]float64, len(t1))
  113. for i, t := range t2 {
  114. ret[i] = calculateBusy(t1[i], t)
  115. }
  116. return ret, nil
  117. }
  118. // Percent calculates the percentage of cpu used either per CPU or combined.
  119. // If an interval of 0 is given it will compare the current cpu times against the last call.
  120. // Returns one value per cpu, or a single value if percpu is set to false.
  121. func Percent(interval time.Duration, percpu bool) ([]float64, error) {
  122. return PercentWithContext(context.Background(), interval, percpu)
  123. }
  124. func PercentWithContext(ctx context.Context, interval time.Duration, percpu bool) ([]float64, error) {
  125. if interval <= 0 {
  126. return percentUsedFromLastCall(percpu)
  127. }
  128. // Get CPU usage at the start of the interval.
  129. cpuTimes1, err := Times(percpu)
  130. if err != nil {
  131. return nil, err
  132. }
  133. if err := common.Sleep(ctx, interval); err != nil {
  134. return nil, err
  135. }
  136. // And at the end of the interval.
  137. cpuTimes2, err := Times(percpu)
  138. if err != nil {
  139. return nil, err
  140. }
  141. return calculateAllBusy(cpuTimes1, cpuTimes2)
  142. }
  143. func percentUsedFromLastCall(percpu bool) ([]float64, error) {
  144. cpuTimes, err := Times(percpu)
  145. if err != nil {
  146. return nil, err
  147. }
  148. lastCPUPercent.Lock()
  149. defer lastCPUPercent.Unlock()
  150. var lastTimes []TimesStat
  151. if percpu {
  152. lastTimes = lastCPUPercent.lastPerCPUTimes
  153. lastCPUPercent.lastPerCPUTimes = cpuTimes
  154. } else {
  155. lastTimes = lastCPUPercent.lastCPUTimes
  156. lastCPUPercent.lastCPUTimes = cpuTimes
  157. }
  158. if lastTimes == nil {
  159. return nil, fmt.Errorf("error getting times for cpu percent. lastTimes was nil")
  160. }
  161. return calculateAllBusy(lastTimes, cpuTimes)
  162. }