sigar_linux.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. // Copyright (c) 2012 VMware, Inc.
  2. package sigar
  3. import (
  4. "bufio"
  5. "bytes"
  6. "io"
  7. "io/ioutil"
  8. "os"
  9. "strconv"
  10. "strings"
  11. "syscall"
  12. )
  13. var system struct {
  14. ticks uint64
  15. btime uint64
  16. }
  17. var Procd string
  18. func init() {
  19. system.ticks = 100 // C.sysconf(C._SC_CLK_TCK)
  20. Procd = "/proc"
  21. // grab system boot time
  22. readFile(Procd+"/stat", func(line string) bool {
  23. if strings.HasPrefix(line, "btime") {
  24. system.btime, _ = strtoull(line[6:])
  25. return false // stop reading
  26. }
  27. return true
  28. })
  29. }
  30. func (self *LoadAverage) Get() error {
  31. line, err := ioutil.ReadFile(Procd + "/loadavg")
  32. if err != nil {
  33. return nil
  34. }
  35. fields := strings.Fields(string(line))
  36. self.One, _ = strconv.ParseFloat(fields[0], 64)
  37. self.Five, _ = strconv.ParseFloat(fields[1], 64)
  38. self.Fifteen, _ = strconv.ParseFloat(fields[2], 64)
  39. return nil
  40. }
  41. func (self *Uptime) Get() error {
  42. sysinfo := syscall.Sysinfo_t{}
  43. if err := syscall.Sysinfo(&sysinfo); err != nil {
  44. return err
  45. }
  46. self.Length = float64(sysinfo.Uptime)
  47. return nil
  48. }
  49. func (self *Mem) Get() error {
  50. var buffers, cached uint64
  51. table := map[string]*uint64{
  52. "MemTotal": &self.Total,
  53. "MemFree": &self.Free,
  54. "Buffers": &buffers,
  55. "Cached": &cached,
  56. }
  57. if err := parseMeminfo(table); err != nil {
  58. return err
  59. }
  60. self.Used = self.Total - self.Free
  61. kern := buffers + cached
  62. self.ActualFree = self.Free + kern
  63. self.ActualUsed = self.Used - kern
  64. return nil
  65. }
  66. func (self *Swap) Get() error {
  67. table := map[string]*uint64{
  68. "SwapTotal": &self.Total,
  69. "SwapFree": &self.Free,
  70. }
  71. if err := parseMeminfo(table); err != nil {
  72. return err
  73. }
  74. self.Used = self.Total - self.Free
  75. return nil
  76. }
  77. func (self *Cpu) Get() error {
  78. return readFile(Procd+"/stat", func(line string) bool {
  79. if len(line) > 4 && line[0:4] == "cpu " {
  80. parseCpuStat(self, line)
  81. return false
  82. }
  83. return true
  84. })
  85. }
  86. func (self *CpuList) Get() error {
  87. capacity := len(self.List)
  88. if capacity == 0 {
  89. capacity = 4
  90. }
  91. list := make([]Cpu, 0, capacity)
  92. err := readFile(Procd+"/stat", func(line string) bool {
  93. if len(line) > 3 && line[0:3] == "cpu" && line[3] != ' ' {
  94. cpu := Cpu{}
  95. parseCpuStat(&cpu, line)
  96. list = append(list, cpu)
  97. }
  98. return true
  99. })
  100. self.List = list
  101. return err
  102. }
  103. func (self *FileSystemList) Get() error {
  104. capacity := len(self.List)
  105. if capacity == 0 {
  106. capacity = 10
  107. }
  108. fslist := make([]FileSystem, 0, capacity)
  109. err := readFile("/etc/mtab", func(line string) bool {
  110. fields := strings.Fields(line)
  111. fs := FileSystem{}
  112. fs.DevName = fields[0]
  113. fs.DirName = fields[1]
  114. fs.SysTypeName = fields[2]
  115. fs.Options = fields[3]
  116. fslist = append(fslist, fs)
  117. return true
  118. })
  119. self.List = fslist
  120. return err
  121. }
  122. func (self *ProcList) Get() error {
  123. dir, err := os.Open(Procd)
  124. if err != nil {
  125. return err
  126. }
  127. defer dir.Close()
  128. const readAllDirnames = -1 // see os.File.Readdirnames doc
  129. names, err := dir.Readdirnames(readAllDirnames)
  130. if err != nil {
  131. return err
  132. }
  133. capacity := len(names)
  134. list := make([]int, 0, capacity)
  135. for _, name := range names {
  136. if name[0] < '0' || name[0] > '9' {
  137. continue
  138. }
  139. pid, err := strconv.Atoi(name)
  140. if err == nil {
  141. list = append(list, pid)
  142. }
  143. }
  144. self.List = list
  145. return nil
  146. }
  147. func (self *ProcState) Get(pid int) error {
  148. contents, err := readProcFile(pid, "stat")
  149. if err != nil {
  150. return err
  151. }
  152. fields := strings.Fields(string(contents))
  153. self.Name = fields[1][1 : len(fields[1])-1] // strip ()'s
  154. self.State = RunState(fields[2][0])
  155. self.Ppid, _ = strconv.Atoi(fields[3])
  156. self.Tty, _ = strconv.Atoi(fields[6])
  157. self.Priority, _ = strconv.Atoi(fields[17])
  158. self.Nice, _ = strconv.Atoi(fields[18])
  159. self.Processor, _ = strconv.Atoi(fields[38])
  160. return nil
  161. }
  162. func (self *ProcMem) Get(pid int) error {
  163. contents, err := readProcFile(pid, "statm")
  164. if err != nil {
  165. return err
  166. }
  167. fields := strings.Fields(string(contents))
  168. size, _ := strtoull(fields[0])
  169. self.Size = size << 12
  170. rss, _ := strtoull(fields[1])
  171. self.Resident = rss << 12
  172. share, _ := strtoull(fields[2])
  173. self.Share = share << 12
  174. contents, err = readProcFile(pid, "stat")
  175. if err != nil {
  176. return err
  177. }
  178. fields = strings.Fields(string(contents))
  179. self.MinorFaults, _ = strtoull(fields[10])
  180. self.MajorFaults, _ = strtoull(fields[12])
  181. self.PageFaults = self.MinorFaults + self.MajorFaults
  182. return nil
  183. }
  184. func (self *ProcTime) Get(pid int) error {
  185. contents, err := readProcFile(pid, "stat")
  186. if err != nil {
  187. return err
  188. }
  189. fields := strings.Fields(string(contents))
  190. user, _ := strtoull(fields[13])
  191. sys, _ := strtoull(fields[14])
  192. // convert to millis
  193. self.User = user * (1000 / system.ticks)
  194. self.Sys = sys * (1000 / system.ticks)
  195. self.Total = self.User + self.Sys
  196. // convert to millis
  197. self.StartTime, _ = strtoull(fields[21])
  198. self.StartTime /= system.ticks
  199. self.StartTime += system.btime
  200. self.StartTime *= 1000
  201. return nil
  202. }
  203. func (self *ProcArgs) Get(pid int) error {
  204. contents, err := readProcFile(pid, "cmdline")
  205. if err != nil {
  206. return err
  207. }
  208. bbuf := bytes.NewBuffer(contents)
  209. var args []string
  210. for {
  211. arg, err := bbuf.ReadBytes(0)
  212. if err == io.EOF {
  213. break
  214. }
  215. args = append(args, string(chop(arg)))
  216. }
  217. self.List = args
  218. return nil
  219. }
  220. func (self *ProcExe) Get(pid int) error {
  221. fields := map[string]*string{
  222. "exe": &self.Name,
  223. "cwd": &self.Cwd,
  224. "root": &self.Root,
  225. }
  226. for name, field := range fields {
  227. val, err := os.Readlink(procFileName(pid, name))
  228. if err != nil {
  229. return err
  230. }
  231. *field = val
  232. }
  233. return nil
  234. }
  235. func parseMeminfo(table map[string]*uint64) error {
  236. return readFile(Procd+"/meminfo", func(line string) bool {
  237. fields := strings.Split(line, ":")
  238. if ptr := table[fields[0]]; ptr != nil {
  239. num := strings.TrimLeft(fields[1], " ")
  240. val, err := strtoull(strings.Fields(num)[0])
  241. if err == nil {
  242. *ptr = val * 1024
  243. }
  244. }
  245. return true
  246. })
  247. }
  248. func parseCpuStat(self *Cpu, line string) error {
  249. fields := strings.Fields(line)
  250. self.User, _ = strtoull(fields[1])
  251. self.Nice, _ = strtoull(fields[2])
  252. self.Sys, _ = strtoull(fields[3])
  253. self.Idle, _ = strtoull(fields[4])
  254. self.Wait, _ = strtoull(fields[5])
  255. self.Irq, _ = strtoull(fields[6])
  256. self.SoftIrq, _ = strtoull(fields[7])
  257. self.Stolen, _ = strtoull(fields[8])
  258. return nil
  259. }
  260. func readFile(file string, handler func(string) bool) error {
  261. contents, err := ioutil.ReadFile(file)
  262. if err != nil {
  263. return err
  264. }
  265. reader := bufio.NewReader(bytes.NewBuffer(contents))
  266. for {
  267. line, _, err := reader.ReadLine()
  268. if err == io.EOF {
  269. break
  270. }
  271. if !handler(string(line)) {
  272. break
  273. }
  274. }
  275. return nil
  276. }
  277. func strtoull(val string) (uint64, error) {
  278. return strconv.ParseUint(val, 10, 64)
  279. }
  280. func procFileName(pid int, name string) string {
  281. return Procd + "/" + strconv.Itoa(pid) + "/" + name
  282. }
  283. func readProcFile(pid int, name string) ([]byte, error) {
  284. path := procFileName(pid, name)
  285. contents, err := ioutil.ReadFile(path)
  286. if err != nil {
  287. if perr, ok := err.(*os.PathError); ok {
  288. if perr.Err == syscall.ENOENT {
  289. return nil, syscall.ESRCH
  290. }
  291. }
  292. }
  293. return contents, err
  294. }