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

Merge pull request #160 from walles/walles/vmtest

Document + add tests for for mem.VirtualMemory()
......@@ -4,18 +4,44 @@ import (
"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 {
Total uint64 `json:"total"`
Available uint64 `json:"available"`
Used uint64 `json:"used"`
// Total amount of RAM on this system
Total uint64 `json:"total"`
// 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"`
Free uint64 `json:"free"`
Active uint64 `json:"active"`
Inactive uint64 `json:"inactive"`
Buffers uint64 `json:"buffers"`
Cached uint64 `json:"cached"`
Wired uint64 `json:"wired"`
Shared uint64 `json:"shared"`
// This is the kernel's notion of free memory; RAM chips whose bits nobody
// cares about the value of right now. For a human consumable number,
// Available is what you really want.
Free uint64 `json:"free"`
// 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 {
......
......@@ -3,12 +3,29 @@
package mem
import (
"encoding/binary"
"strconv"
"strings"
"syscall"
"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.
func SwapMemory() (*SwapMemoryStat, error) {
var ret *SwapMemoryStat
......
......@@ -28,19 +28,20 @@ func VirtualMemory() (*VirtualMemoryStat, error) {
return nil, fmt.Errorf("host_statistics error=%d", status)
}
totalCount := vmstat.wire_count +
vmstat.active_count +
vmstat.inactive_count +
vmstat.free_count
pageSize := uint64(syscall.Getpagesize())
total, err := getHwMemsize()
if err != nil {
return nil, err
}
totalCount := C.natural_t(total / pageSize)
availableCount := vmstat.inactive_count + vmstat.free_count
usedPercent := 100 * float64(totalCount-availableCount) / float64(totalCount)
usedCount := totalCount - vmstat.free_count
usedCount := totalCount - availableCount
pageSize := uint64(syscall.Getpagesize())
return &VirtualMemoryStat{
Total: pageSize * uint64(totalCount),
Total: total,
Available: pageSize * uint64(availableCount),
Used: pageSize * uint64(usedCount),
UsedPercent: usedPercent,
......
......@@ -8,8 +8,6 @@ import (
"strconv"
"strings"
"syscall"
"github.com/shirou/gopsutil/internal/common"
)
// Runs vm_stat and returns Free and inactive pages
......@@ -67,11 +65,7 @@ func parseVMStat(out string, vms *VirtualMemoryStat) error {
func VirtualMemory() (*VirtualMemoryStat, error) {
ret := &VirtualMemoryStat{}
t, err := common.DoSysctrl("hw.memsize")
if err != nil {
return nil, err
}
total, err := strconv.ParseUint(t[0], 10, 64)
total, err := getHwMemsize()
if err != nil {
return nil, err
}
......@@ -83,8 +77,8 @@ func VirtualMemory() (*VirtualMemoryStat, error) {
ret.Available = ret.Free + ret.Inactive
ret.Total = total
ret.Used = ret.Total - ret.Free
ret.UsedPercent = float64(ret.Total-ret.Available) / float64(ret.Total) * 100.0
ret.Used = ret.Total - ret.Available
ret.UsedPercent = 100 * float64(ret.Used) / float64(ret.Total)
return ret, nil
}
......@@ -3,6 +3,9 @@
package mem
import (
"os/exec"
"strconv"
"strings"
"testing"
"github.com/stretchr/testify/assert"
......@@ -12,13 +15,16 @@ func TestVirtualMemoryDarwin(t *testing.T) {
v, err := VirtualMemory()
assert.Nil(t, err)
assert.True(t, v.Total > 0)
assert.Equal(t, v.Total, v.Active+v.Inactive+v.Free+v.Wired)
outBytes, err := exec.Command("/usr/sbin/sysctl", "hw.memsize").Output()
assert.Nil(t, err)
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 < 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.True(t, v.Used > 0)
......
......@@ -79,8 +79,8 @@ func VirtualMemory() (*VirtualMemoryStat, error) {
}
ret.Available = ret.Inactive + ret.Cached + ret.Free
ret.Used = ret.Active + ret.Wired + ret.Cached
ret.UsedPercent = float64(ret.Total-ret.Available) / float64(ret.Total) * 100.0
ret.Used = ret.Total - ret.Available
ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0
return ret, nil
}
......
......@@ -51,7 +51,7 @@ func VirtualMemory() (*VirtualMemoryStat, error) {
if !memavail {
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
return ret, nil
......
......@@ -3,6 +3,8 @@ package mem
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
func TestVirtual_memory(t *testing.T) {
......@@ -14,6 +16,21 @@ func TestVirtual_memory(t *testing.T) {
if v == empty {
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) {
......@@ -35,7 +52,7 @@ func TestVirtualMemoryStat_String(t *testing.T) {
UsedPercent: 30.1,
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) {
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.
先完成此消息的编辑!
想要评论请 注册