proc_status.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. // Copyright 2018 The Prometheus Authors
  2. // Licensed under the Apache License, Version 2.0 (the "License");
  3. // you may not use this file except in compliance with the License.
  4. // You may obtain a copy of the License at
  5. //
  6. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. package procfs
  14. import (
  15. "bytes"
  16. "sort"
  17. "strconv"
  18. "strings"
  19. "github.com/prometheus/procfs/internal/util"
  20. )
  21. // ProcStatus provides status information about the process,
  22. // read from /proc/[pid]/status.
  23. type ProcStatus struct {
  24. // The process ID.
  25. PID int
  26. // The process name.
  27. Name string
  28. // Thread group ID.
  29. TGID int
  30. // List of Pid namespace.
  31. NSpids []uint64
  32. // Peak virtual memory size.
  33. VmPeak uint64 // nolint:revive
  34. // Virtual memory size.
  35. VmSize uint64 // nolint:revive
  36. // Locked memory size.
  37. VmLck uint64 // nolint:revive
  38. // Pinned memory size.
  39. VmPin uint64 // nolint:revive
  40. // Peak resident set size.
  41. VmHWM uint64 // nolint:revive
  42. // Resident set size (sum of RssAnnon RssFile and RssShmem).
  43. VmRSS uint64 // nolint:revive
  44. // Size of resident anonymous memory.
  45. RssAnon uint64 // nolint:revive
  46. // Size of resident file mappings.
  47. RssFile uint64 // nolint:revive
  48. // Size of resident shared memory.
  49. RssShmem uint64 // nolint:revive
  50. // Size of data segments.
  51. VmData uint64 // nolint:revive
  52. // Size of stack segments.
  53. VmStk uint64 // nolint:revive
  54. // Size of text segments.
  55. VmExe uint64 // nolint:revive
  56. // Shared library code size.
  57. VmLib uint64 // nolint:revive
  58. // Page table entries size.
  59. VmPTE uint64 // nolint:revive
  60. // Size of second-level page tables.
  61. VmPMD uint64 // nolint:revive
  62. // Swapped-out virtual memory size by anonymous private.
  63. VmSwap uint64 // nolint:revive
  64. // Size of hugetlb memory portions
  65. HugetlbPages uint64
  66. // Number of voluntary context switches.
  67. VoluntaryCtxtSwitches uint64
  68. // Number of involuntary context switches.
  69. NonVoluntaryCtxtSwitches uint64
  70. // UIDs of the process (Real, effective, saved set, and filesystem UIDs)
  71. UIDs [4]string
  72. // GIDs of the process (Real, effective, saved set, and filesystem GIDs)
  73. GIDs [4]string
  74. // CpusAllowedList: List of cpu cores processes are allowed to run on.
  75. CpusAllowedList []uint64
  76. }
  77. // NewStatus returns the current status information of the process.
  78. func (p Proc) NewStatus() (ProcStatus, error) {
  79. data, err := util.ReadFileNoStat(p.path("status"))
  80. if err != nil {
  81. return ProcStatus{}, err
  82. }
  83. s := ProcStatus{PID: p.PID}
  84. lines := strings.Split(string(data), "\n")
  85. for _, line := range lines {
  86. if !bytes.Contains([]byte(line), []byte(":")) {
  87. continue
  88. }
  89. kv := strings.SplitN(line, ":", 2)
  90. // removes spaces
  91. k := strings.TrimSpace(kv[0])
  92. v := strings.TrimSpace(kv[1])
  93. // removes "kB"
  94. v = strings.TrimSuffix(v, " kB")
  95. // value to int when possible
  96. // we can skip error check here, 'cause vKBytes is not used when value is a string
  97. vKBytes, _ := strconv.ParseUint(v, 10, 64)
  98. // convert kB to B
  99. vBytes := vKBytes * 1024
  100. s.fillStatus(k, v, vKBytes, vBytes)
  101. }
  102. return s, nil
  103. }
  104. func (s *ProcStatus) fillStatus(k string, vString string, vUint uint64, vUintBytes uint64) {
  105. switch k {
  106. case "Tgid":
  107. s.TGID = int(vUint)
  108. case "Name":
  109. s.Name = vString
  110. case "Uid":
  111. copy(s.UIDs[:], strings.Split(vString, "\t"))
  112. case "Gid":
  113. copy(s.GIDs[:], strings.Split(vString, "\t"))
  114. case "NSpid":
  115. s.NSpids = calcNSPidsList(vString)
  116. case "VmPeak":
  117. s.VmPeak = vUintBytes
  118. case "VmSize":
  119. s.VmSize = vUintBytes
  120. case "VmLck":
  121. s.VmLck = vUintBytes
  122. case "VmPin":
  123. s.VmPin = vUintBytes
  124. case "VmHWM":
  125. s.VmHWM = vUintBytes
  126. case "VmRSS":
  127. s.VmRSS = vUintBytes
  128. case "RssAnon":
  129. s.RssAnon = vUintBytes
  130. case "RssFile":
  131. s.RssFile = vUintBytes
  132. case "RssShmem":
  133. s.RssShmem = vUintBytes
  134. case "VmData":
  135. s.VmData = vUintBytes
  136. case "VmStk":
  137. s.VmStk = vUintBytes
  138. case "VmExe":
  139. s.VmExe = vUintBytes
  140. case "VmLib":
  141. s.VmLib = vUintBytes
  142. case "VmPTE":
  143. s.VmPTE = vUintBytes
  144. case "VmPMD":
  145. s.VmPMD = vUintBytes
  146. case "VmSwap":
  147. s.VmSwap = vUintBytes
  148. case "HugetlbPages":
  149. s.HugetlbPages = vUintBytes
  150. case "voluntary_ctxt_switches":
  151. s.VoluntaryCtxtSwitches = vUint
  152. case "nonvoluntary_ctxt_switches":
  153. s.NonVoluntaryCtxtSwitches = vUint
  154. case "Cpus_allowed_list":
  155. s.CpusAllowedList = calcCpusAllowedList(vString)
  156. }
  157. }
  158. // TotalCtxtSwitches returns the total context switch.
  159. func (s ProcStatus) TotalCtxtSwitches() uint64 {
  160. return s.VoluntaryCtxtSwitches + s.NonVoluntaryCtxtSwitches
  161. }
  162. func calcCpusAllowedList(cpuString string) []uint64 {
  163. s := strings.Split(cpuString, ",")
  164. var g []uint64
  165. for _, cpu := range s {
  166. // parse cpu ranges, example: 1-3=[1,2,3]
  167. if l := strings.Split(strings.TrimSpace(cpu), "-"); len(l) > 1 {
  168. startCPU, _ := strconv.ParseUint(l[0], 10, 64)
  169. endCPU, _ := strconv.ParseUint(l[1], 10, 64)
  170. for i := startCPU; i <= endCPU; i++ {
  171. g = append(g, i)
  172. }
  173. } else if len(l) == 1 {
  174. cpu, _ := strconv.ParseUint(l[0], 10, 64)
  175. g = append(g, cpu)
  176. }
  177. }
  178. sort.Slice(g, func(i, j int) bool { return g[i] < g[j] })
  179. return g
  180. }
  181. func calcNSPidsList(nspidsString string) []uint64 {
  182. s := strings.Split(nspidsString, " ")
  183. var nspids []uint64
  184. for _, nspid := range s {
  185. nspid, _ := strconv.ParseUint(nspid, 10, 64)
  186. if nspid == 0 {
  187. continue
  188. }
  189. nspids = append(nspids, nspid)
  190. }
  191. return nspids
  192. }