123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468 |
- // Copyright (c) 2012 VMware, Inc.
- package sigar
- /*
- #include <stdlib.h>
- #include <sys/sysctl.h>
- #include <sys/mount.h>
- #include <mach/mach_init.h>
- #include <mach/mach_host.h>
- #include <mach/host_info.h>
- #include <libproc.h>
- #include <mach/processor_info.h>
- #include <mach/vm_map.h>
- */
- import "C"
- import (
- "bytes"
- "encoding/binary"
- "fmt"
- "io"
- "syscall"
- "time"
- "unsafe"
- )
- func (self *LoadAverage) Get() error {
- avg := []C.double{0, 0, 0}
- C.getloadavg(&avg[0], C.int(len(avg)))
- self.One = float64(avg[0])
- self.Five = float64(avg[1])
- self.Fifteen = float64(avg[2])
- return nil
- }
- func (self *Uptime) Get() error {
- tv := syscall.Timeval32{}
- if err := sysctlbyname("kern.boottime", &tv); err != nil {
- return err
- }
- self.Length = time.Since(time.Unix(int64(tv.Sec), int64(tv.Usec)*1000)).Seconds()
- return nil
- }
- func (self *Mem) Get() error {
- var vmstat C.vm_statistics_data_t
- if err := sysctlbyname("hw.memsize", &self.Total); err != nil {
- return err
- }
- if err := vm_info(&vmstat); err != nil {
- return err
- }
- kern := uint64(vmstat.inactive_count) << 12
- self.Free = uint64(vmstat.free_count) << 12
- self.Used = self.Total - self.Free
- self.ActualFree = self.Free + kern
- self.ActualUsed = self.Used - kern
- return nil
- }
- type xsw_usage struct {
- Total, Avail, Used uint64
- }
- func (self *Swap) Get() error {
- sw_usage := xsw_usage{}
- if err := sysctlbyname("vm.swapusage", &sw_usage); err != nil {
- return err
- }
- self.Total = sw_usage.Total
- self.Used = sw_usage.Used
- self.Free = sw_usage.Avail
- return nil
- }
- func (self *Cpu) Get() error {
- var count C.mach_msg_type_number_t = C.HOST_CPU_LOAD_INFO_COUNT
- var cpuload C.host_cpu_load_info_data_t
- status := C.host_statistics(C.host_t(C.mach_host_self()),
- C.HOST_CPU_LOAD_INFO,
- C.host_info_t(unsafe.Pointer(&cpuload)),
- &count)
- if status != C.KERN_SUCCESS {
- return fmt.Errorf("host_statistics error=%d", status)
- }
- self.User = uint64(cpuload.cpu_ticks[C.CPU_STATE_USER])
- self.Sys = uint64(cpuload.cpu_ticks[C.CPU_STATE_SYSTEM])
- self.Idle = uint64(cpuload.cpu_ticks[C.CPU_STATE_IDLE])
- self.Nice = uint64(cpuload.cpu_ticks[C.CPU_STATE_NICE])
- return nil
- }
- func (self *CpuList) Get() error {
- var count C.mach_msg_type_number_t
- var cpuload *C.processor_cpu_load_info_data_t
- var ncpu C.natural_t
- status := C.host_processor_info(C.host_t(C.mach_host_self()),
- C.PROCESSOR_CPU_LOAD_INFO,
- &ncpu,
- (*C.processor_info_array_t)(unsafe.Pointer(&cpuload)),
- &count)
- if status != C.KERN_SUCCESS {
- return fmt.Errorf("host_processor_info error=%d", status)
- }
- // jump through some cgo casting hoops and ensure we properly free
- // the memory that cpuload points to
- target := C.vm_map_t(C.mach_task_self_)
- address := C.vm_address_t(uintptr(unsafe.Pointer(cpuload)))
- defer C.vm_deallocate(target, address, C.vm_size_t(ncpu))
- // the body of struct processor_cpu_load_info
- // aka processor_cpu_load_info_data_t
- var cpu_ticks [C.CPU_STATE_MAX]uint32
- // copy the cpuload array to a []byte buffer
- // where we can binary.Read the data
- size := int(ncpu) * binary.Size(cpu_ticks)
- buf := C.GoBytes(unsafe.Pointer(cpuload), C.int(size))
- bbuf := bytes.NewBuffer(buf)
- self.List = make([]Cpu, 0, ncpu)
- for i := 0; i < int(ncpu); i++ {
- cpu := Cpu{}
- err := binary.Read(bbuf, binary.LittleEndian, &cpu_ticks)
- if err != nil {
- return err
- }
- cpu.User = uint64(cpu_ticks[C.CPU_STATE_USER])
- cpu.Sys = uint64(cpu_ticks[C.CPU_STATE_SYSTEM])
- cpu.Idle = uint64(cpu_ticks[C.CPU_STATE_IDLE])
- cpu.Nice = uint64(cpu_ticks[C.CPU_STATE_NICE])
- self.List = append(self.List, cpu)
- }
- return nil
- }
- func (self *FileSystemList) Get() error {
- num, err := getfsstat(nil, C.MNT_NOWAIT)
- if num < 0 {
- return err
- }
- buf := make([]syscall.Statfs_t, num)
- num, err = getfsstat(buf, C.MNT_NOWAIT)
- if err != nil {
- return err
- }
- fslist := make([]FileSystem, 0, num)
- for i := 0; i < num; i++ {
- fs := FileSystem{}
- fs.DirName = bytePtrToString(&buf[i].Mntonname[0])
- fs.DevName = bytePtrToString(&buf[i].Mntfromname[0])
- fs.SysTypeName = bytePtrToString(&buf[i].Fstypename[0])
- fslist = append(fslist, fs)
- }
- self.List = fslist
- return err
- }
- func (self *ProcList) Get() error {
- n := C.proc_listpids(C.PROC_ALL_PIDS, 0, nil, 0)
- if n <= 0 {
- return syscall.EINVAL
- }
- buf := make([]byte, n)
- n = C.proc_listpids(C.PROC_ALL_PIDS, 0, unsafe.Pointer(&buf[0]), n)
- if n <= 0 {
- return syscall.ENOMEM
- }
- var pid int32
- num := int(n) / binary.Size(pid)
- list := make([]int, 0, num)
- bbuf := bytes.NewBuffer(buf)
- for i := 0; i < num; i++ {
- if err := binary.Read(bbuf, binary.LittleEndian, &pid); err != nil {
- return err
- }
- if pid == 0 {
- continue
- }
- list = append(list, int(pid))
- }
- self.List = list
- return nil
- }
- func (self *ProcState) Get(pid int) error {
- info := C.struct_proc_taskallinfo{}
- if err := task_info(pid, &info); err != nil {
- return err
- }
- self.Name = C.GoString(&info.pbsd.pbi_comm[0])
- switch info.pbsd.pbi_status {
- case C.SIDL:
- self.State = RunStateIdle
- case C.SRUN:
- self.State = RunStateRun
- case C.SSLEEP:
- self.State = RunStateSleep
- case C.SSTOP:
- self.State = RunStateStop
- case C.SZOMB:
- self.State = RunStateZombie
- default:
- self.State = RunStateUnknown
- }
- self.Ppid = int(info.pbsd.pbi_ppid)
- self.Tty = int(info.pbsd.e_tdev)
- self.Priority = int(info.ptinfo.pti_priority)
- self.Nice = int(info.pbsd.pbi_nice)
- return nil
- }
- func (self *ProcMem) Get(pid int) error {
- info := C.struct_proc_taskallinfo{}
- if err := task_info(pid, &info); err != nil {
- return err
- }
- self.Size = uint64(info.ptinfo.pti_virtual_size)
- self.Resident = uint64(info.ptinfo.pti_resident_size)
- self.PageFaults = uint64(info.ptinfo.pti_faults)
- return nil
- }
- func (self *ProcTime) Get(pid int) error {
- info := C.struct_proc_taskallinfo{}
- if err := task_info(pid, &info); err != nil {
- return err
- }
- self.User =
- uint64(info.ptinfo.pti_total_user) / uint64(time.Millisecond)
- self.Sys =
- uint64(info.ptinfo.pti_total_system) / uint64(time.Millisecond)
- self.Total = self.User + self.Sys
- self.StartTime = (uint64(info.pbsd.pbi_start_tvsec) * 1000) +
- (uint64(info.pbsd.pbi_start_tvusec) / 1000)
- return nil
- }
- func (self *ProcArgs) Get(pid int) error {
- var args []string
- argv := func(arg string) {
- args = append(args, arg)
- }
- err := kern_procargs(pid, nil, argv, nil)
- self.List = args
- return err
- }
- func (self *ProcExe) Get(pid int) error {
- exe := func(arg string) {
- self.Name = arg
- }
- return kern_procargs(pid, exe, nil, nil)
- }
- // wrapper around sysctl KERN_PROCARGS2
- // callbacks params are optional,
- // up to the caller as to which pieces of data they want
- func kern_procargs(pid int,
- exe func(string),
- argv func(string),
- env func(string, string)) error {
- mib := []C.int{C.CTL_KERN, C.KERN_PROCARGS2, C.int(pid)}
- argmax := uintptr(C.ARG_MAX)
- buf := make([]byte, argmax)
- err := sysctl(mib, &buf[0], &argmax, nil, 0)
- if err != nil {
- return nil
- }
- bbuf := bytes.NewBuffer(buf)
- bbuf.Truncate(int(argmax))
- var argc int32
- binary.Read(bbuf, binary.LittleEndian, &argc)
- path, err := bbuf.ReadBytes(0)
- if exe != nil {
- exe(string(chop(path)))
- }
- // skip trailing \0's
- for {
- c, _ := bbuf.ReadByte()
- if c != 0 {
- bbuf.UnreadByte()
- break // start of argv[0]
- }
- }
- for i := 0; i < int(argc); i++ {
- arg, err := bbuf.ReadBytes(0)
- if err == io.EOF {
- break
- }
- if argv != nil {
- argv(string(chop(arg)))
- }
- }
- if env == nil {
- return nil
- }
- delim := []byte{61} // "="
- for {
- line, err := bbuf.ReadBytes(0)
- if err == io.EOF || line[0] == 0 {
- break
- }
- pair := bytes.SplitN(chop(line), delim, 2)
- env(string(pair[0]), string(pair[1]))
- }
- return nil
- }
- // XXX copied from zsyscall_darwin_amd64.go
- func sysctl(mib []C.int, old *byte, oldlen *uintptr,
- new *byte, newlen uintptr) (err error) {
- var p0 unsafe.Pointer
- p0 = unsafe.Pointer(&mib[0])
- _, _, e1 := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(p0),
- uintptr(len(mib)),
- uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)),
- uintptr(unsafe.Pointer(new)), uintptr(newlen))
- if e1 != 0 {
- err = e1
- }
- return
- }
- func vm_info(vmstat *C.vm_statistics_data_t) error {
- var count C.mach_msg_type_number_t = C.HOST_VM_INFO_COUNT
- status := C.host_statistics(
- C.host_t(C.mach_host_self()),
- C.HOST_VM_INFO,
- C.host_info_t(unsafe.Pointer(vmstat)),
- &count)
- if status != C.KERN_SUCCESS {
- return fmt.Errorf("host_statistics=%d", status)
- }
- return nil
- }
- // generic Sysctl buffer unmarshalling
- func sysctlbyname(name string, data interface{}) (err error) {
- val, err := syscall.Sysctl(name)
- if err != nil {
- return err
- }
- buf := []byte(val)
- switch v := data.(type) {
- case *uint64:
- *v = *(*uint64)(unsafe.Pointer(&buf[0]))
- return
- }
- bbuf := bytes.NewBuffer([]byte(val))
- return binary.Read(bbuf, binary.LittleEndian, data)
- }
- // syscall.Getfsstat() wrapper is broken, roll our own to workaround.
- func getfsstat(buf []syscall.Statfs_t, flags int) (n int, err error) {
- var ptr uintptr
- var size uintptr
- if len(buf) > 0 {
- ptr = uintptr(unsafe.Pointer(&buf[0]))
- size = unsafe.Sizeof(buf[0]) * uintptr(len(buf))
- } else {
- ptr = uintptr(0)
- size = uintptr(0)
- }
- trap := uintptr(syscall.SYS_GETFSSTAT64)
- ret, _, errno := syscall.Syscall(trap, ptr, size, uintptr(flags))
- n = int(ret)
- if errno != 0 {
- err = errno
- }
- return
- }
- func task_info(pid int, info *C.struct_proc_taskallinfo) error {
- size := C.int(unsafe.Sizeof(*info))
- ptr := unsafe.Pointer(info)
- n := C.proc_pidinfo(C.int(pid), C.PROC_PIDTASKALLINFO, 0, ptr, size)
- if n != size {
- return syscall.ENOMEM
- }
- return nil
- }
|