You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

167 line
3.9 KiB

  1. // Copyright 2020 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. //go:build !windows
  14. // +build !windows
  15. package procfs
  16. import (
  17. "bufio"
  18. "errors"
  19. "fmt"
  20. "os"
  21. "regexp"
  22. "strconv"
  23. "strings"
  24. "github.com/prometheus/procfs/internal/util"
  25. )
  26. var (
  27. // match the header line before each mapped zone in `/proc/pid/smaps`.
  28. procSMapsHeaderLine = regexp.MustCompile(`^[a-f0-9].*$`)
  29. )
  30. type ProcSMapsRollup struct {
  31. // Amount of the mapping that is currently resident in RAM.
  32. Rss uint64
  33. // Process's proportional share of this mapping.
  34. Pss uint64
  35. // Size in bytes of clean shared pages.
  36. SharedClean uint64
  37. // Size in bytes of dirty shared pages.
  38. SharedDirty uint64
  39. // Size in bytes of clean private pages.
  40. PrivateClean uint64
  41. // Size in bytes of dirty private pages.
  42. PrivateDirty uint64
  43. // Amount of memory currently marked as referenced or accessed.
  44. Referenced uint64
  45. // Amount of memory that does not belong to any file.
  46. Anonymous uint64
  47. // Amount would-be-anonymous memory currently on swap.
  48. Swap uint64
  49. // Process's proportional memory on swap.
  50. SwapPss uint64
  51. }
  52. // ProcSMapsRollup reads from /proc/[pid]/smaps_rollup to get summed memory information of the
  53. // process.
  54. //
  55. // If smaps_rollup does not exists (require kernel >= 4.15), the content of /proc/pid/smaps will
  56. // we read and summed.
  57. func (p Proc) ProcSMapsRollup() (ProcSMapsRollup, error) {
  58. data, err := util.ReadFileNoStat(p.path("smaps_rollup"))
  59. if err != nil && os.IsNotExist(err) {
  60. return p.procSMapsRollupManual()
  61. }
  62. if err != nil {
  63. return ProcSMapsRollup{}, err
  64. }
  65. lines := strings.Split(string(data), "\n")
  66. smaps := ProcSMapsRollup{}
  67. // skip first line which don't contains information we need
  68. lines = lines[1:]
  69. for _, line := range lines {
  70. if line == "" {
  71. continue
  72. }
  73. if err := smaps.parseLine(line); err != nil {
  74. return ProcSMapsRollup{}, err
  75. }
  76. }
  77. return smaps, nil
  78. }
  79. // Read /proc/pid/smaps and do the roll-up in Go code.
  80. func (p Proc) procSMapsRollupManual() (ProcSMapsRollup, error) {
  81. file, err := os.Open(p.path("smaps"))
  82. if err != nil {
  83. return ProcSMapsRollup{}, err
  84. }
  85. defer file.Close()
  86. smaps := ProcSMapsRollup{}
  87. scan := bufio.NewScanner(file)
  88. for scan.Scan() {
  89. line := scan.Text()
  90. if procSMapsHeaderLine.MatchString(line) {
  91. continue
  92. }
  93. if err := smaps.parseLine(line); err != nil {
  94. return ProcSMapsRollup{}, err
  95. }
  96. }
  97. return smaps, nil
  98. }
  99. func (s *ProcSMapsRollup) parseLine(line string) error {
  100. kv := strings.SplitN(line, ":", 2)
  101. if len(kv) != 2 {
  102. fmt.Println(line)
  103. return errors.New("invalid net/dev line, missing colon")
  104. }
  105. k := kv[0]
  106. if k == "VmFlags" {
  107. return nil
  108. }
  109. v := strings.TrimSpace(kv[1])
  110. v = strings.TrimRight(v, " kB")
  111. vKBytes, err := strconv.ParseUint(v, 10, 64)
  112. if err != nil {
  113. return err
  114. }
  115. vBytes := vKBytes * 1024
  116. s.addValue(k, v, vKBytes, vBytes)
  117. return nil
  118. }
  119. func (s *ProcSMapsRollup) addValue(k string, vString string, vUint uint64, vUintBytes uint64) {
  120. switch k {
  121. case "Rss":
  122. s.Rss += vUintBytes
  123. case "Pss":
  124. s.Pss += vUintBytes
  125. case "Shared_Clean":
  126. s.SharedClean += vUintBytes
  127. case "Shared_Dirty":
  128. s.SharedDirty += vUintBytes
  129. case "Private_Clean":
  130. s.PrivateClean += vUintBytes
  131. case "Private_Dirty":
  132. s.PrivateDirty += vUintBytes
  133. case "Referenced":
  134. s.Referenced += vUintBytes
  135. case "Anonymous":
  136. s.Anonymous += vUintBytes
  137. case "Swap":
  138. s.Swap += vUintBytes
  139. case "SwapPss":
  140. s.SwapPss += vUintBytes
  141. }
  142. }