1
2
3
4
5
6
7
8
9
10
11
12
13
14 package procfs
15
16 import (
17 "bytes"
18 "sort"
19 "strconv"
20 "strings"
21
22 "github.com/prometheus/procfs/internal/util"
23 )
24
25
26
27 type ProcStatus struct {
28
29 PID int
30
31 Name string
32
33
34 TGID int
35
36 NSpids []uint64
37
38
39 VmPeak uint64
40
41 VmSize uint64
42
43 VmLck uint64
44
45 VmPin uint64
46
47 VmHWM uint64
48
49 VmRSS uint64
50
51 RssAnon uint64
52
53 RssFile uint64
54
55 RssShmem uint64
56
57 VmData uint64
58
59 VmStk uint64
60
61 VmExe uint64
62
63 VmLib uint64
64
65 VmPTE uint64
66
67 VmPMD uint64
68
69 VmSwap uint64
70
71 HugetlbPages uint64
72
73
74 VoluntaryCtxtSwitches uint64
75
76 NonVoluntaryCtxtSwitches uint64
77
78
79 UIDs [4]string
80
81 GIDs [4]string
82
83
84 CpusAllowedList []uint64
85 }
86
87
88 func (p Proc) NewStatus() (ProcStatus, error) {
89 data, err := util.ReadFileNoStat(p.path("status"))
90 if err != nil {
91 return ProcStatus{}, err
92 }
93
94 s := ProcStatus{PID: p.PID}
95
96 lines := strings.Split(string(data), "\n")
97 for _, line := range lines {
98 if !bytes.Contains([]byte(line), []byte(":")) {
99 continue
100 }
101
102 kv := strings.SplitN(line, ":", 2)
103
104
105 k := strings.TrimSpace(kv[0])
106 v := strings.TrimSpace(kv[1])
107
108 v = strings.TrimSuffix(v, " kB")
109
110
111
112 vKBytes, _ := strconv.ParseUint(v, 10, 64)
113
114 vBytes := vKBytes * 1024
115
116 s.fillStatus(k, v, vKBytes, vBytes)
117 }
118
119 return s, nil
120 }
121
122 func (s *ProcStatus) fillStatus(k string, vString string, vUint uint64, vUintBytes uint64) {
123 switch k {
124 case "Tgid":
125 s.TGID = int(vUint)
126 case "Name":
127 s.Name = vString
128 case "Uid":
129 copy(s.UIDs[:], strings.Split(vString, "\t"))
130 case "Gid":
131 copy(s.GIDs[:], strings.Split(vString, "\t"))
132 case "NSpid":
133 s.NSpids = calcNSPidsList(vString)
134 case "VmPeak":
135 s.VmPeak = vUintBytes
136 case "VmSize":
137 s.VmSize = vUintBytes
138 case "VmLck":
139 s.VmLck = vUintBytes
140 case "VmPin":
141 s.VmPin = vUintBytes
142 case "VmHWM":
143 s.VmHWM = vUintBytes
144 case "VmRSS":
145 s.VmRSS = vUintBytes
146 case "RssAnon":
147 s.RssAnon = vUintBytes
148 case "RssFile":
149 s.RssFile = vUintBytes
150 case "RssShmem":
151 s.RssShmem = vUintBytes
152 case "VmData":
153 s.VmData = vUintBytes
154 case "VmStk":
155 s.VmStk = vUintBytes
156 case "VmExe":
157 s.VmExe = vUintBytes
158 case "VmLib":
159 s.VmLib = vUintBytes
160 case "VmPTE":
161 s.VmPTE = vUintBytes
162 case "VmPMD":
163 s.VmPMD = vUintBytes
164 case "VmSwap":
165 s.VmSwap = vUintBytes
166 case "HugetlbPages":
167 s.HugetlbPages = vUintBytes
168 case "voluntary_ctxt_switches":
169 s.VoluntaryCtxtSwitches = vUint
170 case "nonvoluntary_ctxt_switches":
171 s.NonVoluntaryCtxtSwitches = vUint
172 case "Cpus_allowed_list":
173 s.CpusAllowedList = calcCpusAllowedList(vString)
174 }
175
176 }
177
178
179 func (s ProcStatus) TotalCtxtSwitches() uint64 {
180 return s.VoluntaryCtxtSwitches + s.NonVoluntaryCtxtSwitches
181 }
182
183 func calcCpusAllowedList(cpuString string) []uint64 {
184 s := strings.Split(cpuString, ",")
185
186 var g []uint64
187
188 for _, cpu := range s {
189
190 if l := strings.Split(strings.TrimSpace(cpu), "-"); len(l) > 1 {
191 startCPU, _ := strconv.ParseUint(l[0], 10, 64)
192 endCPU, _ := strconv.ParseUint(l[1], 10, 64)
193
194 for i := startCPU; i <= endCPU; i++ {
195 g = append(g, i)
196 }
197 } else if len(l) == 1 {
198 cpu, _ := strconv.ParseUint(l[0], 10, 64)
199 g = append(g, cpu)
200 }
201
202 }
203
204 sort.Slice(g, func(i, j int) bool { return g[i] < g[j] })
205 return g
206 }
207
208 func calcNSPidsList(nspidsString string) []uint64 {
209 s := strings.Split(nspidsString, " ")
210 var nspids []uint64
211
212 for _, nspid := range s {
213 nspid, _ := strconv.ParseUint(nspid, 10, 64)
214 if nspid == 0 {
215 continue
216 }
217 nspids = append(nspids, nspid)
218 }
219
220 return nspids
221 }
222
View as plain text