github.com/gofiber/fiber/v2@v2.47.0/internal/gopsutil/mem/mem_freebsd.go (about)

     1  //go:build freebsd
     2  // +build freebsd
     3  
     4  package mem
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"unsafe"
    10  
    11  	"golang.org/x/sys/unix"
    12  
    13  	"github.com/gofiber/fiber/v2/internal/gopsutil/common"
    14  )
    15  
    16  func VirtualMemory() (*VirtualMemoryStat, error) {
    17  	return VirtualMemoryWithContext(context.Background())
    18  }
    19  
    20  func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
    21  	pageSize, err := common.SysctlUint("vm.stats.vm.v_page_size")
    22  	if err != nil {
    23  		return nil, err
    24  	}
    25  	physmem, err := common.SysctlUint("hw.physmem")
    26  	if err != nil {
    27  		return nil, err
    28  	}
    29  
    30  	free, err := common.SysctlUint("vm.stats.vm.v_free_count")
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  	active, err := common.SysctlUint("vm.stats.vm.v_active_count")
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  	inactive, err := common.SysctlUint("vm.stats.vm.v_inactive_count")
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  	buffers, err := common.SysctlUint("vfs.bufspace")
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  	wired, err := common.SysctlUint("vm.stats.vm.v_wire_count")
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  	var cached, laundry uint64
    51  	osreldate, _ := common.SysctlUint("kern.osreldate")
    52  	if osreldate < 1102000 {
    53  		cached, err = common.SysctlUint("vm.stats.vm.v_cache_count")
    54  		if err != nil {
    55  			return nil, err
    56  		}
    57  	} else {
    58  		laundry, err = common.SysctlUint("vm.stats.vm.v_laundry_count")
    59  		if err != nil {
    60  			return nil, err
    61  		}
    62  	}
    63  
    64  	p := pageSize
    65  	ret := &VirtualMemoryStat{
    66  		Total:    physmem,
    67  		Free:     free * p,
    68  		Active:   active * p,
    69  		Inactive: inactive * p,
    70  		Cached:   cached * p,
    71  		Buffers:  buffers,
    72  		Wired:    wired * p,
    73  		Laundry:  laundry * p,
    74  	}
    75  
    76  	ret.Available = ret.Inactive + ret.Cached + ret.Free + ret.Laundry
    77  	ret.Used = ret.Total - ret.Available
    78  	ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0
    79  
    80  	return ret, nil
    81  }
    82  
    83  // Return swapinfo
    84  func SwapMemory() (*SwapMemoryStat, error) {
    85  	return SwapMemoryWithContext(context.Background())
    86  }
    87  
    88  // Constants from vm/vm_param.h
    89  // nolint: golint
    90  const (
    91  	XSWDEV_VERSION11 = 1
    92  	XSWDEV_VERSION   = 2
    93  )
    94  
    95  // Types from vm/vm_param.h
    96  type xswdev struct {
    97  	Version uint32 // Version is the version
    98  	Dev     uint64 // Dev is the device identifier
    99  	Flags   int32  // Flags is the swap flags applied to the device
   100  	NBlks   int32  // NBlks is the total number of blocks
   101  	Used    int32  // Used is the number of blocks used
   102  }
   103  
   104  // xswdev11 is a compatibility for under FreeBSD 11
   105  // sys/vm/swap_pager.c
   106  type xswdev11 struct {
   107  	Version uint32 // Version is the version
   108  	Dev     uint32 // Dev is the device identifier
   109  	Flags   int32  // Flags is the swap flags applied to the device
   110  	NBlks   int32  // NBlks is the total number of blocks
   111  	Used    int32  // Used is the number of blocks used
   112  }
   113  
   114  func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
   115  	// FreeBSD can have multiple swap devices so we total them up
   116  	i, err := common.SysctlUint("vm.nswapdev")
   117  	if err != nil {
   118  		return nil, err
   119  	}
   120  
   121  	if i == 0 {
   122  		return nil, errors.New("no swap devices found")
   123  	}
   124  
   125  	c := int(i)
   126  
   127  	i, err = common.SysctlUint("vm.stats.vm.v_page_size")
   128  	if err != nil {
   129  		return nil, err
   130  	}
   131  	pageSize := i
   132  
   133  	var buf []byte
   134  	s := &SwapMemoryStat{}
   135  	for n := 0; n < c; n++ {
   136  		buf, err = unix.SysctlRaw("vm.swap_info", n)
   137  		if err != nil {
   138  			return nil, err
   139  		}
   140  
   141  		// first, try to parse with version 2
   142  		xsw := (*xswdev)(unsafe.Pointer(&buf[0]))
   143  		if xsw.Version == XSWDEV_VERSION11 {
   144  			// this is version 1, so try to parse again
   145  			xsw := (*xswdev11)(unsafe.Pointer(&buf[0]))
   146  			if xsw.Version != XSWDEV_VERSION11 {
   147  				return nil, errors.New("xswdev version mismatch(11)")
   148  			}
   149  			s.Total += uint64(xsw.NBlks)
   150  			s.Used += uint64(xsw.Used)
   151  		} else if xsw.Version != XSWDEV_VERSION {
   152  			return nil, errors.New("xswdev version mismatch")
   153  		} else {
   154  			s.Total += uint64(xsw.NBlks)
   155  			s.Used += uint64(xsw.Used)
   156  		}
   157  
   158  	}
   159  
   160  	if s.Total != 0 {
   161  		s.UsedPercent = float64(s.Used) / float64(s.Total) * 100
   162  	}
   163  	s.Total *= pageSize
   164  	s.Used *= pageSize
   165  	s.Free = s.Total - s.Used
   166  
   167  	return s, nil
   168  }