提交 1d09f7a4 编写于 作者: S shirou

Merge pull request #160 from walles/walles/vmtest

Document + add tests for for mem.VirtualMemory()
...@@ -4,18 +4,44 @@ import ( ...@@ -4,18 +4,44 @@ import (
"encoding/json" "encoding/json"
) )
// Memory usage statistics. Total, Available and Used contain numbers of bytes
// for human consumption.
//
// The other fields in this struct contain kernel specific values.
type VirtualMemoryStat struct { type VirtualMemoryStat struct {
Total uint64 `json:"total"` // Total amount of RAM on this system
Available uint64 `json:"available"` Total uint64 `json:"total"`
Used uint64 `json:"used"`
// RAM available for programs to allocate
//
// This value is computed from the kernel specific values.
Available uint64 `json:"available"`
// RAM used by programs
//
// This value is computed from the kernel specific values.
Used uint64 `json:"used"`
// Percentage of RAM used by programs
//
// This value is computed from the kernel specific values.
UsedPercent float64 `json:"used_percent"` UsedPercent float64 `json:"used_percent"`
Free uint64 `json:"free"`
Active uint64 `json:"active"` // This is the kernel's notion of free memory; RAM chips whose bits nobody
Inactive uint64 `json:"inactive"` // cares about the value of right now. For a human consumable number,
Buffers uint64 `json:"buffers"` // Available is what you really want.
Cached uint64 `json:"cached"` Free uint64 `json:"free"`
Wired uint64 `json:"wired"`
Shared uint64 `json:"shared"` // OS X / BSD specific numbers:
// http://www.macyourself.com/2010/02/17/what-is-free-wired-active-and-inactive-system-memory-ram/
Active uint64 `json:"active"`
Inactive uint64 `json:"inactive"`
Wired uint64 `json:"wired"`
// Linux specific numbers
// https://www.centos.org/docs/5/html/5.1/Deployment_Guide/s2-proc-meminfo.html
Buffers uint64 `json:"buffers"`
Cached uint64 `json:"cached"`
} }
type SwapMemoryStat struct { type SwapMemoryStat struct {
......
...@@ -3,12 +3,29 @@ ...@@ -3,12 +3,29 @@
package mem package mem
import ( import (
"encoding/binary"
"strconv" "strconv"
"strings" "strings"
"syscall"
"github.com/shirou/gopsutil/internal/common" "github.com/shirou/gopsutil/internal/common"
) )
func getHwMemsize() (uint64, error) {
totalString, err := syscall.Sysctl("hw.memsize")
if err != nil {
return 0, err
}
// syscall.sysctl() helpfully assumes the result is a null-terminated string and
// removes the last byte of the result if it's 0 :/
totalString += "\x00"
total := uint64(binary.LittleEndian.Uint64([]byte(totalString)))
return total, nil
}
// SwapMemory returns swapinfo. // SwapMemory returns swapinfo.
func SwapMemory() (*SwapMemoryStat, error) { func SwapMemory() (*SwapMemoryStat, error) {
var ret *SwapMemoryStat var ret *SwapMemoryStat
......
...@@ -28,19 +28,20 @@ func VirtualMemory() (*VirtualMemoryStat, error) { ...@@ -28,19 +28,20 @@ func VirtualMemory() (*VirtualMemoryStat, error) {
return nil, fmt.Errorf("host_statistics error=%d", status) return nil, fmt.Errorf("host_statistics error=%d", status)
} }
totalCount := vmstat.wire_count + pageSize := uint64(syscall.Getpagesize())
vmstat.active_count + total, err := getHwMemsize()
vmstat.inactive_count + if err != nil {
vmstat.free_count return nil, err
}
totalCount := C.natural_t(total / pageSize)
availableCount := vmstat.inactive_count + vmstat.free_count availableCount := vmstat.inactive_count + vmstat.free_count
usedPercent := 100 * float64(totalCount-availableCount) / float64(totalCount) usedPercent := 100 * float64(totalCount-availableCount) / float64(totalCount)
usedCount := totalCount - vmstat.free_count usedCount := totalCount - availableCount
pageSize := uint64(syscall.Getpagesize())
return &VirtualMemoryStat{ return &VirtualMemoryStat{
Total: pageSize * uint64(totalCount), Total: total,
Available: pageSize * uint64(availableCount), Available: pageSize * uint64(availableCount),
Used: pageSize * uint64(usedCount), Used: pageSize * uint64(usedCount),
UsedPercent: usedPercent, UsedPercent: usedPercent,
......
...@@ -8,8 +8,6 @@ import ( ...@@ -8,8 +8,6 @@ import (
"strconv" "strconv"
"strings" "strings"
"syscall" "syscall"
"github.com/shirou/gopsutil/internal/common"
) )
// Runs vm_stat and returns Free and inactive pages // Runs vm_stat and returns Free and inactive pages
...@@ -67,11 +65,7 @@ func parseVMStat(out string, vms *VirtualMemoryStat) error { ...@@ -67,11 +65,7 @@ func parseVMStat(out string, vms *VirtualMemoryStat) error {
func VirtualMemory() (*VirtualMemoryStat, error) { func VirtualMemory() (*VirtualMemoryStat, error) {
ret := &VirtualMemoryStat{} ret := &VirtualMemoryStat{}
t, err := common.DoSysctrl("hw.memsize") total, err := getHwMemsize()
if err != nil {
return nil, err
}
total, err := strconv.ParseUint(t[0], 10, 64)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -83,8 +77,8 @@ func VirtualMemory() (*VirtualMemoryStat, error) { ...@@ -83,8 +77,8 @@ func VirtualMemory() (*VirtualMemoryStat, error) {
ret.Available = ret.Free + ret.Inactive ret.Available = ret.Free + ret.Inactive
ret.Total = total ret.Total = total
ret.Used = ret.Total - ret.Free ret.Used = ret.Total - ret.Available
ret.UsedPercent = float64(ret.Total-ret.Available) / float64(ret.Total) * 100.0 ret.UsedPercent = 100 * float64(ret.Used) / float64(ret.Total)
return ret, nil return ret, nil
} }
...@@ -3,6 +3,9 @@ ...@@ -3,6 +3,9 @@
package mem package mem
import ( import (
"os/exec"
"strconv"
"strings"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
...@@ -12,13 +15,16 @@ func TestVirtualMemoryDarwin(t *testing.T) { ...@@ -12,13 +15,16 @@ func TestVirtualMemoryDarwin(t *testing.T) {
v, err := VirtualMemory() v, err := VirtualMemory()
assert.Nil(t, err) assert.Nil(t, err)
assert.True(t, v.Total > 0) outBytes, err := exec.Command("/usr/sbin/sysctl", "hw.memsize").Output()
assert.Nil(t, err)
assert.Equal(t, v.Total, v.Active+v.Inactive+v.Free+v.Wired) outString := string(outBytes)
outString = strings.TrimSpace(outString)
outParts := strings.Split(outString, " ")
actualTotal, err := strconv.ParseInt(outParts[1], 10, 64)
assert.Nil(t, err)
assert.Equal(t, uint64(actualTotal), v.Total)
assert.True(t, v.Available > 0) assert.True(t, v.Available > 0)
assert.True(t, v.Available < v.Total)
assert.Equal(t, v.Available, v.Total-v.Wired-v.Active, "%v", v)
assert.Equal(t, v.Available, v.Free+v.Inactive, "%v", v) assert.Equal(t, v.Available, v.Free+v.Inactive, "%v", v)
assert.True(t, v.Used > 0) assert.True(t, v.Used > 0)
......
...@@ -79,8 +79,8 @@ func VirtualMemory() (*VirtualMemoryStat, error) { ...@@ -79,8 +79,8 @@ func VirtualMemory() (*VirtualMemoryStat, error) {
} }
ret.Available = ret.Inactive + ret.Cached + ret.Free ret.Available = ret.Inactive + ret.Cached + ret.Free
ret.Used = ret.Active + ret.Wired + ret.Cached ret.Used = ret.Total - ret.Available
ret.UsedPercent = float64(ret.Total-ret.Available) / float64(ret.Total) * 100.0 ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0
return ret, nil return ret, nil
} }
......
...@@ -51,7 +51,7 @@ func VirtualMemory() (*VirtualMemoryStat, error) { ...@@ -51,7 +51,7 @@ func VirtualMemory() (*VirtualMemoryStat, error) {
if !memavail { if !memavail {
ret.Available = ret.Free + ret.Buffers + ret.Cached ret.Available = ret.Free + ret.Buffers + ret.Cached
} }
ret.Used = ret.Total - ret.Free ret.Used = ret.Total - ret.Available
ret.UsedPercent = float64(ret.Total-ret.Available) / float64(ret.Total) * 100.0 ret.UsedPercent = float64(ret.Total-ret.Available) / float64(ret.Total) * 100.0
return ret, nil return ret, nil
......
...@@ -3,6 +3,8 @@ package mem ...@@ -3,6 +3,8 @@ package mem
import ( import (
"fmt" "fmt"
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
func TestVirtual_memory(t *testing.T) { func TestVirtual_memory(t *testing.T) {
...@@ -14,6 +16,21 @@ func TestVirtual_memory(t *testing.T) { ...@@ -14,6 +16,21 @@ func TestVirtual_memory(t *testing.T) {
if v == empty { if v == empty {
t.Errorf("error %v", v) t.Errorf("error %v", v)
} }
assert.True(t, v.Total > 0)
assert.True(t, v.Available > 0)
assert.True(t, v.Used > 0)
assert.Equal(t, v.Total, v.Available+v.Used,
"Total should be computable from available + used: %v", v)
assert.True(t, v.Free > 0)
assert.True(t, v.Available > v.Free,
"Free should be a subset of Available: %v", v)
assert.InDelta(t, v.UsedPercent,
100*float64(v.Used)/float64(v.Total), 0.1,
"UsedPercent should be how many percent of Total is Used: %v", v)
} }
func TestSwap_memory(t *testing.T) { func TestSwap_memory(t *testing.T) {
...@@ -35,7 +52,7 @@ func TestVirtualMemoryStat_String(t *testing.T) { ...@@ -35,7 +52,7 @@ func TestVirtualMemoryStat_String(t *testing.T) {
UsedPercent: 30.1, UsedPercent: 30.1,
Free: 40, Free: 40,
} }
e := `{"total":10,"available":20,"used":30,"used_percent":30.1,"free":40,"active":0,"inactive":0,"buffers":0,"cached":0,"wired":0,"shared":0}` e := `{"total":10,"available":20,"used":30,"used_percent":30.1,"free":40,"active":0,"inactive":0,"wired":0,"buffers":0,"cached":0}`
if e != fmt.Sprintf("%v", v) { if e != fmt.Sprintf("%v", v) {
t.Errorf("VirtualMemoryStat string is invalid: %v", v) t.Errorf("VirtualMemoryStat string is invalid: %v", v)
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册