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 14 package procfs 15 16 import ( 17 "bytes" 18 "fmt" 19 "os" 20 21 "github.com/prometheus/procfs/internal/util" 22 ) 23 24 // Originally, this USER_HZ value was dynamically retrieved via a sysconf call 25 // which required cgo. However, that caused a lot of problems regarding 26 // cross-compilation. Alternatives such as running a binary to determine the 27 // value, or trying to derive it in some other way were all problematic. After 28 // much research it was determined that USER_HZ is actually hardcoded to 100 on 29 // all Go-supported platforms as of the time of this writing. This is why we 30 // decided to hardcode it here as well. It is not impossible that there could 31 // be systems with exceptions, but they should be very exotic edge cases, and 32 // in that case, the worst outcome will be two misreported metrics. 33 // 34 // See also the following discussions: 35 // 36 // - https://github.com/prometheus/node_exporter/issues/52 37 // - https://github.com/prometheus/procfs/pull/2 38 // - http://stackoverflow.com/questions/17410841/how-does-user-hz-solve-the-jiffy-scaling-issue 39 const userHZ = 100 40 41 // ProcStat provides status information about the process, 42 // read from /proc/[pid]/stat. 43 type ProcStat struct { 44 // The process ID. 45 PID int 46 // The filename of the executable. 47 Comm string 48 // The process state. 49 State string 50 // The PID of the parent of this process. 51 PPID int 52 // The process group ID of the process. 53 PGRP int 54 // The session ID of the process. 55 Session int 56 // The controlling terminal of the process. 57 TTY int 58 // The ID of the foreground process group of the controlling terminal of 59 // the process. 60 TPGID int 61 // The kernel flags word of the process. 62 Flags uint 63 // The number of minor faults the process has made which have not required 64 // loading a memory page from disk. 65 MinFlt uint 66 // The number of minor faults that the process's waited-for children have 67 // made. 68 CMinFlt uint 69 // The number of major faults the process has made which have required 70 // loading a memory page from disk. 71 MajFlt uint 72 // The number of major faults that the process's waited-for children have 73 // made. 74 CMajFlt uint 75 // Amount of time that this process has been scheduled in user mode, 76 // measured in clock ticks. 77 UTime uint 78 // Amount of time that this process has been scheduled in kernel mode, 79 // measured in clock ticks. 80 STime uint 81 // Amount of time that this process's waited-for children have been 82 // scheduled in user mode, measured in clock ticks. 83 CUTime int 84 // Amount of time that this process's waited-for children have been 85 // scheduled in kernel mode, measured in clock ticks. 86 CSTime int 87 // For processes running a real-time scheduling policy, this is the negated 88 // scheduling priority, minus one. 89 Priority int 90 // The nice value, a value in the range 19 (low priority) to -20 (high 91 // priority). 92 Nice int 93 // Number of threads in this process. 94 NumThreads int 95 // The time the process started after system boot, the value is expressed 96 // in clock ticks. 97 Starttime uint64 98 // Virtual memory size in bytes. 99 VSize uint 100 // Resident set size in pages. 101 RSS int 102 // Soft limit in bytes on the rss of the process. 103 RSSLimit uint64 104 // CPU number last executed on. 105 Processor uint 106 // Real-time scheduling priority, a number in the range 1 to 99 for processes 107 // scheduled under a real-time policy, or 0, for non-real-time processes. 108 RTPriority uint 109 // Scheduling policy. 110 Policy uint 111 // Aggregated block I/O delays, measured in clock ticks (centiseconds). 112 DelayAcctBlkIOTicks uint64 113 // Guest time of the process (time spent running a virtual CPU for a guest 114 // operating system), measured in clock ticks. 115 GuestTime int 116 // Guest time of the process's children, measured in clock ticks. 117 CGuestTime int 118 119 proc FS 120 } 121 122 // NewStat returns the current status information of the process. 123 // 124 // Deprecated: Use p.Stat() instead. 125 func (p Proc) NewStat() (ProcStat, error) { 126 return p.Stat() 127 } 128 129 // Stat returns the current status information of the process. 130 func (p Proc) Stat() (ProcStat, error) { 131 data, err := util.ReadFileNoStat(p.path("stat")) 132 if err != nil { 133 return ProcStat{}, err 134 } 135 136 var ( 137 ignoreInt64 int64 138 ignoreUint64 uint64 139 140 s = ProcStat{PID: p.PID, proc: p.fs} 141 l = bytes.Index(data, []byte("(")) 142 r = bytes.LastIndex(data, []byte(")")) 143 ) 144 145 if l < 0 || r < 0 { 146 return ProcStat{}, fmt.Errorf("%w: unexpected format, couldn't extract comm %q", ErrFileParse, data) 147 } 148 149 s.Comm = string(data[l+1 : r]) 150 151 // Check the following resources for the details about the particular stat 152 // fields and their data types: 153 // * https://man7.org/linux/man-pages/man5/proc.5.html 154 // * https://man7.org/linux/man-pages/man3/scanf.3.html 155 _, err = fmt.Fscan( 156 bytes.NewBuffer(data[r+2:]), 157 &s.State, 158 &s.PPID, 159 &s.PGRP, 160 &s.Session, 161 &s.TTY, 162 &s.TPGID, 163 &s.Flags, 164 &s.MinFlt, 165 &s.CMinFlt, 166 &s.MajFlt, 167 &s.CMajFlt, 168 &s.UTime, 169 &s.STime, 170 &s.CUTime, 171 &s.CSTime, 172 &s.Priority, 173 &s.Nice, 174 &s.NumThreads, 175 &ignoreInt64, 176 &s.Starttime, 177 &s.VSize, 178 &s.RSS, 179 &s.RSSLimit, 180 &ignoreUint64, 181 &ignoreUint64, 182 &ignoreUint64, 183 &ignoreUint64, 184 &ignoreUint64, 185 &ignoreUint64, 186 &ignoreUint64, 187 &ignoreUint64, 188 &ignoreUint64, 189 &ignoreUint64, 190 &ignoreUint64, 191 &ignoreUint64, 192 &ignoreInt64, 193 &s.Processor, 194 &s.RTPriority, 195 &s.Policy, 196 &s.DelayAcctBlkIOTicks, 197 &s.GuestTime, 198 &s.CGuestTime, 199 ) 200 if err != nil { 201 return ProcStat{}, err 202 } 203 204 return s, nil 205 } 206 207 // VirtualMemory returns the virtual memory size in bytes. 208 func (s ProcStat) VirtualMemory() uint { 209 return s.VSize 210 } 211 212 // ResidentMemory returns the resident memory size in bytes. 213 func (s ProcStat) ResidentMemory() int { 214 return s.RSS * os.Getpagesize() 215 } 216 217 // StartTime returns the unix timestamp of the process in seconds. 218 func (s ProcStat) StartTime() (float64, error) { 219 stat, err := s.proc.Stat() 220 if err != nil { 221 return 0, err 222 } 223 return float64(stat.BootTime) + (float64(s.Starttime) / userHZ), nil 224 } 225 226 // CPUTime returns the total CPU user and system time in seconds. 227 func (s ProcStat) CPUTime() float64 { 228 return float64(s.UTime+s.STime) / userHZ 229 } 230