diff --git a/mem/mem_darwin.go b/mem/mem_darwin.go index ba4dbd8..df997d7 100644 --- a/mem/mem_darwin.go +++ b/mem/mem_darwin.go @@ -2,10 +2,18 @@ package mem +/* +#include +#include +*/ +import "C" + import ( + "fmt" "os/exec" "strconv" "strings" + "unsafe" "github.com/shirou/gopsutil/internal/common" ) @@ -23,91 +31,41 @@ func getPageSize() (uint64, error) { return p, nil } -// Runs vm_stat and returns Free and inactive pages -func getVmStat(pagesize uint64, vms *VirtualMemoryStat) error { - out, err := exec.Command("vm_stat").Output() - if err != nil { - return err - } - return parseVmStat(string(out), pagesize, vms) -} - -func parseVmStat(out string, pagesize uint64, vms *VirtualMemoryStat) error { - var err error - - lines := strings.Split(out, "\n") - for _, line := range lines { - fields := strings.Split(line, ":") - if len(fields) < 2 { - continue - } - key := strings.TrimSpace(fields[0]) - value := strings.Trim(fields[1], " .") - switch key { - case "Pages free": - free, e := strconv.ParseUint(value, 10, 64) - if e != nil { - err = e - } - vms.Free = free * pagesize - case "Pages inactive": - inactive, e := strconv.ParseUint(value, 10, 64) - if e != nil { - err = e - } - vms.Cached += inactive * pagesize - vms.Inactive = inactive * pagesize - case "Pages active": - active, e := strconv.ParseUint(value, 10, 64) - if e != nil { - err = e - } - vms.Active = active * pagesize - case "Pages wired down": - wired, e := strconv.ParseUint(value, 10, 64) - if e != nil { - err = e - } - vms.Wired = wired * pagesize - case "Pages purgeable": - purgeable, e := strconv.ParseUint(value, 10, 64) - if e != nil { - err = e - } - vms.Cached += purgeable * pagesize - } - } - return err -} - // VirtualMemory returns VirtualmemoryStat. func VirtualMemory() (*VirtualMemoryStat, error) { - ret := &VirtualMemoryStat{} + count := C.mach_msg_type_number_t(C.HOST_VM_INFO_COUNT) + var vmstat C.vm_statistics_data_t - p, err := getPageSize() - if err != nil { - return nil, err - } - t, err := common.DoSysctrl("hw.memsize") - if err != nil { - return nil, err - } - total, err := strconv.ParseUint(t[0], 10, 64) - if err != nil { - return nil, err - } - err = getVmStat(p, ret) - if err != nil { - return nil, err - } - - ret.Available = ret.Free + ret.Cached - ret.Total = total + status := C.host_statistics(C.host_t(C.mach_host_self()), + C.HOST_VM_INFO, + C.host_info_t(unsafe.Pointer(&vmstat)), + &count) - ret.Used = ret.Total - ret.Free - ret.UsedPercent = float64(ret.Total-ret.Available) / float64(ret.Total) * 100.0 + if status != C.KERN_SUCCESS { + return nil, fmt.Errorf("host_statistics error=%d", status) + } - return ret, nil + totalCount := vmstat.wire_count + + vmstat.active_count + + vmstat.inactive_count + + vmstat.free_count + + availableCount := vmstat.inactive_count + vmstat.free_count + usedPercent := 100 * float64(totalCount-availableCount) / float64(totalCount) + + usedCount := totalCount - vmstat.free_count + + pageSize := uint64(C.getpagesize()) + return &VirtualMemoryStat{ + Total: pageSize * uint64(totalCount), + Available: pageSize * uint64(availableCount), + Used: pageSize * uint64(usedCount), + UsedPercent: usedPercent, + Free: pageSize * uint64(vmstat.free_count), + Active: pageSize * uint64(vmstat.active_count), + Inactive: pageSize * uint64(vmstat.inactive_count), + Wired: pageSize * uint64(vmstat.wire_count), + }, nil } // SwapMemory returns swapinfo. diff --git a/mem/mem_darwin_test.go b/mem/mem_darwin_test.go index 8db0e2d..cf10ea8 100644 --- a/mem/mem_darwin_test.go +++ b/mem/mem_darwin_test.go @@ -8,66 +8,6 @@ import ( "github.com/stretchr/testify/assert" ) -var vmStatOut = ` -Mach Virtual Memory Statistics: (page size of 4096 bytes) -Pages free: 105885. -Pages active: 725641. -Pages inactive: 449242. -Pages speculative: 6155. -Pages throttled: 0. -Pages wired down: 560835. -Pages purgeable: 128967. -"Translation faults": 622528839. -Pages copy-on-write: 17697839. -Pages zero filled: 311034413. -Pages reactivated: 4705104. -Pages purged: 5605610. -File-backed pages: 349192. -Anonymous pages: 831846. -Pages stored in compressor: 876507. -Pages occupied by compressor: 249167. -Decompressions: 4555025. -Compressions: 7524729. -Pageins: 40532443. -Pageouts: 126496. -Swapins: 2988073. -Swapouts: 3283599. -` - -func TestParseVmStat(t *testing.T) { - ret := &VirtualMemoryStat{} - err := parseVmStat(vmStatOut, 4096, ret) - - if err != nil { - t.Errorf("Expected no error, got %s\n", err.Error()) - } - - if ret.Free != uint64(105885*4096) { - t.Errorf("Free pages, actual: %d, expected: %d", ret.Free, - 105885*4096) - } - - if ret.Inactive != uint64(449242*4096) { - t.Errorf("Inactive pages, actual: %d, expected: %d", ret.Inactive, - 449242*4096) - } - - if ret.Active != uint64(725641*4096) { - t.Errorf("Active pages, actual: %d, expected: %d", ret.Active, - 725641*4096) - } - - if ret.Wired != uint64(560835*4096) { - t.Errorf("Wired pages, actual: %d, expected: %d", ret.Wired, - 560835*4096) - } - - if ret.Cached != uint64(128967*4096+449242.*4096) { - t.Errorf("Cached pages, actual: %d, expected: %f", ret.Cached, - 128967*4096+449242.*4096) - } -} - func TestVirtualMemoryDarwin(t *testing.T) { v, err := VirtualMemory() assert.Nil(t, err)