process_info.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. package performance
  2. import (
  3. "fmt"
  4. "math"
  5. "runtime"
  6. "strings"
  7. "time"
  8. "github.com/shirou/gopsutil/v4/process"
  9. )
  10. type NginxProcessInfo struct {
  11. Workers int `json:"workers"`
  12. Master int `json:"master"`
  13. Cache int `json:"cache"`
  14. Other int `json:"other"`
  15. CPUUsage float64 `json:"cpu_usage"`
  16. MemoryUsage float64 `json:"memory_usage"`
  17. }
  18. // GetNginxProcessInfo Get Nginx process information
  19. func GetNginxProcessInfo() (*NginxProcessInfo, error) {
  20. result := &NginxProcessInfo{
  21. Workers: 0,
  22. Master: 0,
  23. Cache: 0,
  24. Other: 0,
  25. CPUUsage: 0.0,
  26. MemoryUsage: 0.0,
  27. }
  28. // Find all Nginx processes
  29. processes, err := process.Processes()
  30. if err != nil {
  31. return result, fmt.Errorf("failed to get processes: %v", err)
  32. }
  33. totalMemory := 0.0
  34. workerCount := 0
  35. masterCount := 0
  36. cacheCount := 0
  37. otherCount := 0
  38. nginxProcesses := []*process.Process{}
  39. // Get the number of system CPU cores
  40. numCPU := runtime.NumCPU()
  41. // Get the PID of the Nginx master process
  42. var masterPID int32 = -1
  43. for _, p := range processes {
  44. name, err := p.Name()
  45. if err != nil {
  46. continue
  47. }
  48. cmdline, err := p.Cmdline()
  49. if err != nil {
  50. continue
  51. }
  52. // Check if it is the Nginx master process
  53. if strings.Contains(strings.ToLower(name), "nginx") &&
  54. (strings.Contains(cmdline, "master process") ||
  55. !strings.Contains(cmdline, "worker process")) &&
  56. p.Pid > 0 {
  57. masterPID = p.Pid
  58. masterCount++
  59. nginxProcesses = append(nginxProcesses, p)
  60. // Get the memory usage
  61. mem, err := p.MemoryInfo()
  62. if err == nil && mem != nil {
  63. // Convert to MB
  64. memoryUsage := float64(mem.RSS) / 1024 / 1024
  65. totalMemory += memoryUsage
  66. }
  67. break
  68. }
  69. }
  70. // Iterate through all processes, distinguishing between worker processes and other Nginx processes
  71. for _, p := range processes {
  72. if p.Pid == masterPID {
  73. continue // Already calculated the master process
  74. }
  75. name, err := p.Name()
  76. if err != nil {
  77. continue
  78. }
  79. // Only process Nginx related processes
  80. if !strings.Contains(strings.ToLower(name), "nginx") {
  81. continue
  82. }
  83. // Add to the Nginx process list
  84. nginxProcesses = append(nginxProcesses, p)
  85. // Get the parent process PID
  86. ppid, err := p.Ppid()
  87. if err != nil {
  88. continue
  89. }
  90. cmdline, err := p.Cmdline()
  91. if err != nil {
  92. continue
  93. }
  94. // Get the memory usage
  95. mem, err := p.MemoryInfo()
  96. if err == nil && mem != nil {
  97. // Convert to MB
  98. memoryUsage := float64(mem.RSS) / 1024 / 1024
  99. totalMemory += memoryUsage
  100. }
  101. // Distinguish between worker processes, cache processes, and other processes
  102. if ppid == masterPID && strings.Contains(cmdline, "worker process") {
  103. workerCount++
  104. } else if ppid == masterPID && strings.Contains(cmdline, "cache") {
  105. cacheCount++
  106. } else {
  107. otherCount++
  108. }
  109. }
  110. // Calculate the CPU usage
  111. // First, measure the initial CPU time
  112. times1 := make(map[int32]float64)
  113. for _, p := range nginxProcesses {
  114. times, err := p.Times()
  115. if err == nil {
  116. // CPU time = user time + system time
  117. times1[p.Pid] = times.User + times.System
  118. }
  119. }
  120. // Wait for a short period of time
  121. time.Sleep(100 * time.Millisecond)
  122. // Measure the CPU time again
  123. totalCPUPercent := 0.0
  124. for _, p := range nginxProcesses {
  125. times, err := p.Times()
  126. if err != nil {
  127. continue
  128. }
  129. // Calculate the CPU time difference
  130. currentTotal := times.User + times.System
  131. if previousTotal, ok := times1[p.Pid]; ok {
  132. // Calculate the CPU usage percentage during this period (considering multiple cores)
  133. cpuDelta := currentTotal - previousTotal
  134. // Calculate the CPU usage per second (considering the sampling time)
  135. cpuPercent := (cpuDelta / 0.1) * 100.0 / float64(numCPU)
  136. totalCPUPercent += cpuPercent
  137. }
  138. }
  139. // Round to the nearest integer, which is more consistent with the top display
  140. totalCPUPercent = math.Round(totalCPUPercent)
  141. // Round the memory usage to two decimal places
  142. totalMemory = math.Round(totalMemory*100) / 100
  143. result.Workers = workerCount
  144. result.Master = masterCount
  145. result.Cache = cacheCount
  146. result.Other = otherCount
  147. result.CPUUsage = totalCPUPercent
  148. result.MemoryUsage = totalMemory
  149. return result, nil
  150. }