143 lines
3.2 KiB
Go
143 lines
3.2 KiB
Go
// +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
|
|
}
|