sigar_darwin.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. // Copyright (c) 2012 VMware, Inc.
  2. package sigar
  3. /*
  4. #include <stdlib.h>
  5. #include <sys/sysctl.h>
  6. #include <sys/mount.h>
  7. #include <mach/mach_init.h>
  8. #include <mach/mach_host.h>
  9. #include <mach/host_info.h>
  10. #include <libproc.h>
  11. #include <mach/processor_info.h>
  12. #include <mach/vm_map.h>
  13. */
  14. import "C"
  15. import (
  16. "bytes"
  17. "encoding/binary"
  18. "fmt"
  19. "io"
  20. "syscall"
  21. "time"
  22. "unsafe"
  23. )
  24. func (self *LoadAverage) Get() error {
  25. avg := []C.double{0, 0, 0}
  26. C.getloadavg(&avg[0], C.int(len(avg)))
  27. self.One = float64(avg[0])
  28. self.Five = float64(avg[1])
  29. self.Fifteen = float64(avg[2])
  30. return nil
  31. }
  32. func (self *Uptime) Get() error {
  33. tv := syscall.Timeval32{}
  34. if err := sysctlbyname("kern.boottime", &tv); err != nil {
  35. return err
  36. }
  37. self.Length = time.Since(time.Unix(int64(tv.Sec), int64(tv.Usec)*1000)).Seconds()
  38. return nil
  39. }
  40. func (self *Mem) Get() error {
  41. var vmstat C.vm_statistics_data_t
  42. if err := sysctlbyname("hw.memsize", &self.Total); err != nil {
  43. return err
  44. }
  45. if err := vm_info(&vmstat); err != nil {
  46. return err
  47. }
  48. kern := uint64(vmstat.inactive_count) << 12
  49. self.Free = uint64(vmstat.free_count) << 12
  50. self.Used = self.Total - self.Free
  51. self.ActualFree = self.Free + kern
  52. self.ActualUsed = self.Used - kern
  53. return nil
  54. }
  55. type xsw_usage struct {
  56. Total, Avail, Used uint64
  57. }
  58. func (self *Swap) Get() error {
  59. sw_usage := xsw_usage{}
  60. if err := sysctlbyname("vm.swapusage", &sw_usage); err != nil {
  61. return err
  62. }
  63. self.Total = sw_usage.Total
  64. self.Used = sw_usage.Used
  65. self.Free = sw_usage.Avail
  66. return nil
  67. }
  68. func (self *Cpu) Get() error {
  69. var count C.mach_msg_type_number_t = C.HOST_CPU_LOAD_INFO_COUNT
  70. var cpuload C.host_cpu_load_info_data_t
  71. status := C.host_statistics(C.host_t(C.mach_host_self()),
  72. C.HOST_CPU_LOAD_INFO,
  73. C.host_info_t(unsafe.Pointer(&cpuload)),
  74. &count)
  75. if status != C.KERN_SUCCESS {
  76. return fmt.Errorf("host_statistics error=%d", status)
  77. }
  78. self.User = uint64(cpuload.cpu_ticks[C.CPU_STATE_USER])
  79. self.Sys = uint64(cpuload.cpu_ticks[C.CPU_STATE_SYSTEM])
  80. self.Idle = uint64(cpuload.cpu_ticks[C.CPU_STATE_IDLE])
  81. self.Nice = uint64(cpuload.cpu_ticks[C.CPU_STATE_NICE])
  82. return nil
  83. }
  84. func (self *CpuList) Get() error {
  85. var count C.mach_msg_type_number_t
  86. var cpuload *C.processor_cpu_load_info_data_t
  87. var ncpu C.natural_t
  88. status := C.host_processor_info(C.host_t(C.mach_host_self()),
  89. C.PROCESSOR_CPU_LOAD_INFO,
  90. &ncpu,
  91. (*C.processor_info_array_t)(unsafe.Pointer(&cpuload)),
  92. &count)
  93. if status != C.KERN_SUCCESS {
  94. return fmt.Errorf("host_processor_info error=%d", status)
  95. }
  96. // jump through some cgo casting hoops and ensure we properly free
  97. // the memory that cpuload points to
  98. target := C.vm_map_t(C.mach_task_self_)
  99. address := C.vm_address_t(uintptr(unsafe.Pointer(cpuload)))
  100. defer C.vm_deallocate(target, address, C.vm_size_t(ncpu))
  101. // the body of struct processor_cpu_load_info
  102. // aka processor_cpu_load_info_data_t
  103. var cpu_ticks [C.CPU_STATE_MAX]uint32
  104. // copy the cpuload array to a []byte buffer
  105. // where we can binary.Read the data
  106. size := int(ncpu) * binary.Size(cpu_ticks)
  107. buf := C.GoBytes(unsafe.Pointer(cpuload), C.int(size))
  108. bbuf := bytes.NewBuffer(buf)
  109. self.List = make([]Cpu, 0, ncpu)
  110. for i := 0; i < int(ncpu); i++ {
  111. cpu := Cpu{}
  112. err := binary.Read(bbuf, binary.LittleEndian, &cpu_ticks)
  113. if err != nil {
  114. return err
  115. }
  116. cpu.User = uint64(cpu_ticks[C.CPU_STATE_USER])
  117. cpu.Sys = uint64(cpu_ticks[C.CPU_STATE_SYSTEM])
  118. cpu.Idle = uint64(cpu_ticks[C.CPU_STATE_IDLE])
  119. cpu.Nice = uint64(cpu_ticks[C.CPU_STATE_NICE])
  120. self.List = append(self.List, cpu)
  121. }
  122. return nil
  123. }
  124. func (self *FileSystemList) Get() error {
  125. num, err := getfsstat(nil, C.MNT_NOWAIT)
  126. if num < 0 {
  127. return err
  128. }
  129. buf := make([]syscall.Statfs_t, num)
  130. num, err = getfsstat(buf, C.MNT_NOWAIT)
  131. if err != nil {
  132. return err
  133. }
  134. fslist := make([]FileSystem, 0, num)
  135. for i := 0; i < num; i++ {
  136. fs := FileSystem{}
  137. fs.DirName = bytePtrToString(&buf[i].Mntonname[0])
  138. fs.DevName = bytePtrToString(&buf[i].Mntfromname[0])
  139. fs.SysTypeName = bytePtrToString(&buf[i].Fstypename[0])
  140. fslist = append(fslist, fs)
  141. }
  142. self.List = fslist
  143. return err
  144. }
  145. func (self *ProcList) Get() error {
  146. n := C.proc_listpids(C.PROC_ALL_PIDS, 0, nil, 0)
  147. if n <= 0 {
  148. return syscall.EINVAL
  149. }
  150. buf := make([]byte, n)
  151. n = C.proc_listpids(C.PROC_ALL_PIDS, 0, unsafe.Pointer(&buf[0]), n)
  152. if n <= 0 {
  153. return syscall.ENOMEM
  154. }
  155. var pid int32
  156. num := int(n) / binary.Size(pid)
  157. list := make([]int, 0, num)
  158. bbuf := bytes.NewBuffer(buf)
  159. for i := 0; i < num; i++ {
  160. if err := binary.Read(bbuf, binary.LittleEndian, &pid); err != nil {
  161. return err
  162. }
  163. if pid == 0 {
  164. continue
  165. }
  166. list = append(list, int(pid))
  167. }
  168. self.List = list
  169. return nil
  170. }
  171. func (self *ProcState) Get(pid int) error {
  172. info := C.struct_proc_taskallinfo{}
  173. if err := task_info(pid, &info); err != nil {
  174. return err
  175. }
  176. self.Name = C.GoString(&info.pbsd.pbi_comm[0])
  177. switch info.pbsd.pbi_status {
  178. case C.SIDL:
  179. self.State = RunStateIdle
  180. case C.SRUN:
  181. self.State = RunStateRun
  182. case C.SSLEEP:
  183. self.State = RunStateSleep
  184. case C.SSTOP:
  185. self.State = RunStateStop
  186. case C.SZOMB:
  187. self.State = RunStateZombie
  188. default:
  189. self.State = RunStateUnknown
  190. }
  191. self.Ppid = int(info.pbsd.pbi_ppid)
  192. self.Tty = int(info.pbsd.e_tdev)
  193. self.Priority = int(info.ptinfo.pti_priority)
  194. self.Nice = int(info.pbsd.pbi_nice)
  195. return nil
  196. }
  197. func (self *ProcMem) Get(pid int) error {
  198. info := C.struct_proc_taskallinfo{}
  199. if err := task_info(pid, &info); err != nil {
  200. return err
  201. }
  202. self.Size = uint64(info.ptinfo.pti_virtual_size)
  203. self.Resident = uint64(info.ptinfo.pti_resident_size)
  204. self.PageFaults = uint64(info.ptinfo.pti_faults)
  205. return nil
  206. }
  207. func (self *ProcTime) Get(pid int) error {
  208. info := C.struct_proc_taskallinfo{}
  209. if err := task_info(pid, &info); err != nil {
  210. return err
  211. }
  212. self.User =
  213. uint64(info.ptinfo.pti_total_user) / uint64(time.Millisecond)
  214. self.Sys =
  215. uint64(info.ptinfo.pti_total_system) / uint64(time.Millisecond)
  216. self.Total = self.User + self.Sys
  217. self.StartTime = (uint64(info.pbsd.pbi_start_tvsec) * 1000) +
  218. (uint64(info.pbsd.pbi_start_tvusec) / 1000)
  219. return nil
  220. }
  221. func (self *ProcArgs) Get(pid int) error {
  222. var args []string
  223. argv := func(arg string) {
  224. args = append(args, arg)
  225. }
  226. err := kern_procargs(pid, nil, argv, nil)
  227. self.List = args
  228. return err
  229. }
  230. func (self *ProcExe) Get(pid int) error {
  231. exe := func(arg string) {
  232. self.Name = arg
  233. }
  234. return kern_procargs(pid, exe, nil, nil)
  235. }
  236. // wrapper around sysctl KERN_PROCARGS2
  237. // callbacks params are optional,
  238. // up to the caller as to which pieces of data they want
  239. func kern_procargs(pid int,
  240. exe func(string),
  241. argv func(string),
  242. env func(string, string)) error {
  243. mib := []C.int{C.CTL_KERN, C.KERN_PROCARGS2, C.int(pid)}
  244. argmax := uintptr(C.ARG_MAX)
  245. buf := make([]byte, argmax)
  246. err := sysctl(mib, &buf[0], &argmax, nil, 0)
  247. if err != nil {
  248. return nil
  249. }
  250. bbuf := bytes.NewBuffer(buf)
  251. bbuf.Truncate(int(argmax))
  252. var argc int32
  253. binary.Read(bbuf, binary.LittleEndian, &argc)
  254. path, err := bbuf.ReadBytes(0)
  255. if exe != nil {
  256. exe(string(chop(path)))
  257. }
  258. // skip trailing \0's
  259. for {
  260. c, _ := bbuf.ReadByte()
  261. if c != 0 {
  262. bbuf.UnreadByte()
  263. break // start of argv[0]
  264. }
  265. }
  266. for i := 0; i < int(argc); i++ {
  267. arg, err := bbuf.ReadBytes(0)
  268. if err == io.EOF {
  269. break
  270. }
  271. if argv != nil {
  272. argv(string(chop(arg)))
  273. }
  274. }
  275. if env == nil {
  276. return nil
  277. }
  278. delim := []byte{61} // "="
  279. for {
  280. line, err := bbuf.ReadBytes(0)
  281. if err == io.EOF || line[0] == 0 {
  282. break
  283. }
  284. pair := bytes.SplitN(chop(line), delim, 2)
  285. env(string(pair[0]), string(pair[1]))
  286. }
  287. return nil
  288. }
  289. // XXX copied from zsyscall_darwin_amd64.go
  290. func sysctl(mib []C.int, old *byte, oldlen *uintptr,
  291. new *byte, newlen uintptr) (err error) {
  292. var p0 unsafe.Pointer
  293. p0 = unsafe.Pointer(&mib[0])
  294. _, _, e1 := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(p0),
  295. uintptr(len(mib)),
  296. uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)),
  297. uintptr(unsafe.Pointer(new)), uintptr(newlen))
  298. if e1 != 0 {
  299. err = e1
  300. }
  301. return
  302. }
  303. func vm_info(vmstat *C.vm_statistics_data_t) error {
  304. var count C.mach_msg_type_number_t = C.HOST_VM_INFO_COUNT
  305. status := C.host_statistics(
  306. C.host_t(C.mach_host_self()),
  307. C.HOST_VM_INFO,
  308. C.host_info_t(unsafe.Pointer(vmstat)),
  309. &count)
  310. if status != C.KERN_SUCCESS {
  311. return fmt.Errorf("host_statistics=%d", status)
  312. }
  313. return nil
  314. }
  315. // generic Sysctl buffer unmarshalling
  316. func sysctlbyname(name string, data interface{}) (err error) {
  317. val, err := syscall.Sysctl(name)
  318. if err != nil {
  319. return err
  320. }
  321. buf := []byte(val)
  322. switch v := data.(type) {
  323. case *uint64:
  324. *v = *(*uint64)(unsafe.Pointer(&buf[0]))
  325. return
  326. }
  327. bbuf := bytes.NewBuffer([]byte(val))
  328. return binary.Read(bbuf, binary.LittleEndian, data)
  329. }
  330. // syscall.Getfsstat() wrapper is broken, roll our own to workaround.
  331. func getfsstat(buf []syscall.Statfs_t, flags int) (n int, err error) {
  332. var ptr uintptr
  333. var size uintptr
  334. if len(buf) > 0 {
  335. ptr = uintptr(unsafe.Pointer(&buf[0]))
  336. size = unsafe.Sizeof(buf[0]) * uintptr(len(buf))
  337. } else {
  338. ptr = uintptr(0)
  339. size = uintptr(0)
  340. }
  341. trap := uintptr(syscall.SYS_GETFSSTAT64)
  342. ret, _, errno := syscall.Syscall(trap, ptr, size, uintptr(flags))
  343. n = int(ret)
  344. if errno != 0 {
  345. err = errno
  346. }
  347. return
  348. }
  349. func task_info(pid int, info *C.struct_proc_taskallinfo) error {
  350. size := C.int(unsafe.Sizeof(*info))
  351. ptr := unsafe.Pointer(info)
  352. n := C.proc_pidinfo(C.int(pid), C.PROC_PIDTASKALLINFO, 0, ptr, size)
  353. if n != size {
  354. return syscall.ENOMEM
  355. }
  356. return nil
  357. }