mem_freebsd.go 3.9 KB

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