proc_status.go 5.9 KB

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