mem_freebsd.go 3.9 KB

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