169 lines
3.9 KiB
Go
169 lines
3.9 KiB
Go
//go:build freebsd
|
|
// +build freebsd
|
|
|
|
package mem
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"unsafe"
|
|
|
|
"golang.org/x/sys/unix"
|
|
|
|
"github.com/shirou/gopsutil/v3/internal/common"
|
|
)
|
|
|
|
func VirtualMemory() (*VirtualMemoryStat, error) {
|
|
return VirtualMemoryWithContext(context.Background())
|
|
}
|
|
|
|
func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
|
|
pageSize, err := common.SysctlUint("vm.stats.vm.v_page_size")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
physmem, err := common.SysctlUint("hw.physmem")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
free, err := common.SysctlUint("vm.stats.vm.v_free_count")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
active, err := common.SysctlUint("vm.stats.vm.v_active_count")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
inactive, err := common.SysctlUint("vm.stats.vm.v_inactive_count")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
buffers, err := common.SysctlUint("vfs.bufspace")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
wired, err := common.SysctlUint("vm.stats.vm.v_wire_count")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var cached, laundry uint64
|
|
osreldate, _ := common.SysctlUint("kern.osreldate")
|
|
if osreldate < 1102000 {
|
|
cached, err = common.SysctlUint("vm.stats.vm.v_cache_count")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
laundry, err = common.SysctlUint("vm.stats.vm.v_laundry_count")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
p := pageSize
|
|
ret := &VirtualMemoryStat{
|
|
Total: physmem,
|
|
Free: free * p,
|
|
Active: active * p,
|
|
Inactive: inactive * p,
|
|
Cached: cached * p,
|
|
Buffers: buffers,
|
|
Wired: wired * p,
|
|
Laundry: 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_VERSION11 = 1
|
|
XSWDEV_VERSION = 2
|
|
)
|
|
|
|
// Types from vm/vm_param.h
|
|
type xswdev struct {
|
|
Version uint32 // Version is the version
|
|
Dev uint64 // 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
|
|
}
|
|
|
|
// xswdev11 is a compatibility for under FreeBSD 11
|
|
// sys/vm/swap_pager.c
|
|
type xswdev11 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 := common.SysctlUint("vm.nswapdev")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if i == 0 {
|
|
return nil, errors.New("no swap devices found")
|
|
}
|
|
|
|
c := int(i)
|
|
|
|
i, err = common.SysctlUint("vm.stats.vm.v_page_size")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
pageSize := 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
|
|
}
|
|
|
|
// first, try to parse with version 2
|
|
xsw := (*xswdev)(unsafe.Pointer(&buf[0]))
|
|
if xsw.Version == XSWDEV_VERSION11 {
|
|
// this is version 1, so try to parse again
|
|
xsw := (*xswdev11)(unsafe.Pointer(&buf[0]))
|
|
if xsw.Version != XSWDEV_VERSION11 {
|
|
return nil, errors.New("xswdev version mismatch(11)")
|
|
}
|
|
s.Total += uint64(xsw.NBlks)
|
|
s.Used += uint64(xsw.Used)
|
|
} else if xsw.Version != XSWDEV_VERSION {
|
|
return nil, errors.New("xswdev version mismatch")
|
|
} else {
|
|
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
|
|
}
|