// +build freebsd package mem import ( "context" "errors" "unsafe" "golang.org/x/sys/unix" ) func VirtualMemory() (*VirtualMemoryStat, error) { return VirtualMemoryWithContext(context.Background()) } func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) { pageSize, err := unix.SysctlUint32("vm.stats.vm.v_page_size") if err != nil { return nil, err } physmem, err := unix.SysctlUint64("hw.physmem") if err != nil { return nil, err } free, err := unix.SysctlUint32("vm.stats.vm.v_free_count") if err != nil { return nil, err } active, err := unix.SysctlUint32("vm.stats.vm.v_active_count") if err != nil { return nil, err } inactive, err := unix.SysctlUint32("vm.stats.vm.v_inactive_count") if err != nil { return nil, err } buffers, err := unix.SysctlUint64("vfs.bufspace") if err != nil { return nil, err } wired, err := unix.SysctlUint32("vm.stats.vm.v_wire_count") if err != nil { return nil, err } var cached, laundry uint32 osreldate, _ := unix.SysctlUint32("kern.osreldate") if osreldate < 1102000 { cached, err = unix.SysctlUint32("vm.stats.vm.v_cache_count") if err != nil { return nil, err } } else { laundry, err = unix.SysctlUint32("vm.stats.vm.v_laundry_count") if err != nil { return nil, err } } p := uint64(pageSize) ret := &VirtualMemoryStat{ Total: uint64(physmem), Free: uint64(free) * p, Active: uint64(active) * p, Inactive: uint64(inactive) * p, Cached: uint64(cached) * p, Buffers: uint64(buffers), Wired: uint64(wired) * p, Laundry: uint64(laundry) * p, } ret.Available = ret.Inactive + ret.Cached + ret.Free + ret.Laundry ret.Used = ret.Total - ret.Available ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0 return ret, nil } // Return swapinfo func SwapMemory() (*SwapMemoryStat, error) { return SwapMemoryWithContext(context.Background()) } // Constants from vm/vm_param.h // nolint: golint const ( XSWDEV_VERSION = 1 ) // Types from vm/vm_param.h type xswdev struct { Version uint32 // Version is the version Dev uint32 // Dev is the device identifier Flags int32 // Flags is the swap flags applied to the device NBlks int32 // NBlks is the total number of blocks Used int32 // Used is the number of blocks used } func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) { // FreeBSD can have multiple swap devices so we total them up i, err := unix.SysctlUint32("vm.nswapdev") if err != nil { return nil, err } if i == 0 { return nil, errors.New("no swap devices found") } c := int(i) i, err = unix.SysctlUint32("vm.stats.vm.v_page_size") if err != nil { return nil, err } pageSize := uint64(i) var buf []byte s := &SwapMemoryStat{} for n := 0; n < c; n++ { buf, err = unix.SysctlRaw("vm.swap_info", n) if err != nil { return nil, err } xsw := (*xswdev)(unsafe.Pointer(&buf[0])) if xsw.Version != XSWDEV_VERSION { return nil, errors.New("xswdev version mismatch") } s.Total += uint64(xsw.NBlks) s.Used += uint64(xsw.Used) } if s.Total != 0 { s.UsedPercent = float64(s.Used) / float64(s.Total) * 100 } s.Total *= pageSize s.Used *= pageSize s.Free = s.Total - s.Used return s, nil }