123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 |
- // Copyright (c) 2012 VMware, Inc.
- package sigar
- import (
- "bufio"
- "bytes"
- "io"
- "io/ioutil"
- "os"
- "strconv"
- "strings"
- "syscall"
- )
- var system struct {
- ticks uint64
- btime uint64
- }
- var Procd string
- func init() {
- system.ticks = 100 // C.sysconf(C._SC_CLK_TCK)
- Procd = "/proc"
- // grab system boot time
- readFile(Procd+"/stat", func(line string) bool {
- if strings.HasPrefix(line, "btime") {
- system.btime, _ = strtoull(line[6:])
- return false // stop reading
- }
- return true
- })
- }
- func (self *LoadAverage) Get() error {
- line, err := ioutil.ReadFile(Procd + "/loadavg")
- if err != nil {
- return nil
- }
- fields := strings.Fields(string(line))
- self.One, _ = strconv.ParseFloat(fields[0], 64)
- self.Five, _ = strconv.ParseFloat(fields[1], 64)
- self.Fifteen, _ = strconv.ParseFloat(fields[2], 64)
- return nil
- }
- func (self *Uptime) Get() error {
- sysinfo := syscall.Sysinfo_t{}
- if err := syscall.Sysinfo(&sysinfo); err != nil {
- return err
- }
- self.Length = float64(sysinfo.Uptime)
- return nil
- }
- func (self *Mem) Get() error {
- var buffers, cached uint64
- table := map[string]*uint64{
- "MemTotal": &self.Total,
- "MemFree": &self.Free,
- "Buffers": &buffers,
- "Cached": &cached,
- }
- if err := parseMeminfo(table); err != nil {
- return err
- }
- self.Used = self.Total - self.Free
- kern := buffers + cached
- self.ActualFree = self.Free + kern
- self.ActualUsed = self.Used - kern
- return nil
- }
- func (self *Swap) Get() error {
- table := map[string]*uint64{
- "SwapTotal": &self.Total,
- "SwapFree": &self.Free,
- }
- if err := parseMeminfo(table); err != nil {
- return err
- }
- self.Used = self.Total - self.Free
- return nil
- }
- func (self *Cpu) Get() error {
- return readFile(Procd+"/stat", func(line string) bool {
- if len(line) > 4 && line[0:4] == "cpu " {
- parseCpuStat(self, line)
- return false
- }
- return true
- })
- }
- func (self *CpuList) Get() error {
- capacity := len(self.List)
- if capacity == 0 {
- capacity = 4
- }
- list := make([]Cpu, 0, capacity)
- err := readFile(Procd+"/stat", func(line string) bool {
- if len(line) > 3 && line[0:3] == "cpu" && line[3] != ' ' {
- cpu := Cpu{}
- parseCpuStat(&cpu, line)
- list = append(list, cpu)
- }
- return true
- })
- self.List = list
- return err
- }
- func (self *FileSystemList) Get() error {
- capacity := len(self.List)
- if capacity == 0 {
- capacity = 10
- }
- fslist := make([]FileSystem, 0, capacity)
- err := readFile("/etc/mtab", func(line string) bool {
- fields := strings.Fields(line)
- fs := FileSystem{}
- fs.DevName = fields[0]
- fs.DirName = fields[1]
- fs.SysTypeName = fields[2]
- fs.Options = fields[3]
- fslist = append(fslist, fs)
- return true
- })
- self.List = fslist
- return err
- }
- func (self *ProcList) Get() error {
- dir, err := os.Open(Procd)
- if err != nil {
- return err
- }
- defer dir.Close()
- const readAllDirnames = -1 // see os.File.Readdirnames doc
- names, err := dir.Readdirnames(readAllDirnames)
- if err != nil {
- return err
- }
- capacity := len(names)
- list := make([]int, 0, capacity)
- for _, name := range names {
- if name[0] < '0' || name[0] > '9' {
- continue
- }
- pid, err := strconv.Atoi(name)
- if err == nil {
- list = append(list, pid)
- }
- }
- self.List = list
- return nil
- }
- func (self *ProcState) Get(pid int) error {
- contents, err := readProcFile(pid, "stat")
- if err != nil {
- return err
- }
- fields := strings.Fields(string(contents))
- self.Name = fields[1][1 : len(fields[1])-1] // strip ()'s
- self.State = RunState(fields[2][0])
- self.Ppid, _ = strconv.Atoi(fields[3])
- self.Tty, _ = strconv.Atoi(fields[6])
- self.Priority, _ = strconv.Atoi(fields[17])
- self.Nice, _ = strconv.Atoi(fields[18])
- self.Processor, _ = strconv.Atoi(fields[38])
- return nil
- }
- func (self *ProcMem) Get(pid int) error {
- contents, err := readProcFile(pid, "statm")
- if err != nil {
- return err
- }
- fields := strings.Fields(string(contents))
- size, _ := strtoull(fields[0])
- self.Size = size << 12
- rss, _ := strtoull(fields[1])
- self.Resident = rss << 12
- share, _ := strtoull(fields[2])
- self.Share = share << 12
- contents, err = readProcFile(pid, "stat")
- if err != nil {
- return err
- }
- fields = strings.Fields(string(contents))
- self.MinorFaults, _ = strtoull(fields[10])
- self.MajorFaults, _ = strtoull(fields[12])
- self.PageFaults = self.MinorFaults + self.MajorFaults
- return nil
- }
- func (self *ProcTime) Get(pid int) error {
- contents, err := readProcFile(pid, "stat")
- if err != nil {
- return err
- }
- fields := strings.Fields(string(contents))
- user, _ := strtoull(fields[13])
- sys, _ := strtoull(fields[14])
- // convert to millis
- self.User = user * (1000 / system.ticks)
- self.Sys = sys * (1000 / system.ticks)
- self.Total = self.User + self.Sys
- // convert to millis
- self.StartTime, _ = strtoull(fields[21])
- self.StartTime /= system.ticks
- self.StartTime += system.btime
- self.StartTime *= 1000
- return nil
- }
- func (self *ProcArgs) Get(pid int) error {
- contents, err := readProcFile(pid, "cmdline")
- if err != nil {
- return err
- }
- bbuf := bytes.NewBuffer(contents)
- var args []string
- for {
- arg, err := bbuf.ReadBytes(0)
- if err == io.EOF {
- break
- }
- args = append(args, string(chop(arg)))
- }
- self.List = args
- return nil
- }
- func (self *ProcExe) Get(pid int) error {
- fields := map[string]*string{
- "exe": &self.Name,
- "cwd": &self.Cwd,
- "root": &self.Root,
- }
- for name, field := range fields {
- val, err := os.Readlink(procFileName(pid, name))
- if err != nil {
- return err
- }
- *field = val
- }
- return nil
- }
- func parseMeminfo(table map[string]*uint64) error {
- return readFile(Procd+"/meminfo", func(line string) bool {
- fields := strings.Split(line, ":")
- if ptr := table[fields[0]]; ptr != nil {
- num := strings.TrimLeft(fields[1], " ")
- val, err := strtoull(strings.Fields(num)[0])
- if err == nil {
- *ptr = val * 1024
- }
- }
- return true
- })
- }
- func parseCpuStat(self *Cpu, line string) error {
- fields := strings.Fields(line)
- self.User, _ = strtoull(fields[1])
- self.Nice, _ = strtoull(fields[2])
- self.Sys, _ = strtoull(fields[3])
- self.Idle, _ = strtoull(fields[4])
- self.Wait, _ = strtoull(fields[5])
- self.Irq, _ = strtoull(fields[6])
- self.SoftIrq, _ = strtoull(fields[7])
- self.Stolen, _ = strtoull(fields[8])
- return nil
- }
- func readFile(file string, handler func(string) bool) error {
- contents, err := ioutil.ReadFile(file)
- if err != nil {
- return err
- }
- reader := bufio.NewReader(bytes.NewBuffer(contents))
- for {
- line, _, err := reader.ReadLine()
- if err == io.EOF {
- break
- }
- if !handler(string(line)) {
- break
- }
- }
- return nil
- }
- func strtoull(val string) (uint64, error) {
- return strconv.ParseUint(val, 10, 64)
- }
- func procFileName(pid int, name string) string {
- return Procd + "/" + strconv.Itoa(pid) + "/" + name
- }
- func readProcFile(pid int, name string) ([]byte, error) {
- path := procFileName(pid, name)
- contents, err := ioutil.ReadFile(path)
- if err != nil {
- if perr, ok := err.(*os.PathError); ok {
- if perr.Err == syscall.ENOENT {
- return nil, syscall.ESRCH
- }
- }
- }
- return contents, err
- }
|