diff --git a/README.rst b/README.rst index 94006773..311d8569 100644 --- a/README.rst +++ b/README.rst @@ -86,9 +86,11 @@ Current Status - terminal (linux) - nice (linux) - num_fds (linux) + - num_threads (linux) - cpu_times (linux) - memory_info (linux) - memory_info_ex (linux) + - Memory_maps() (linux) <- this is a function - not yet @@ -109,7 +111,6 @@ Current Status - cpu_percent - cpu_affinity - memory_percent - - memory_maps - children - open_files - connections diff --git a/process.go b/process.go index fd703b03..534fc395 100644 --- a/process.go +++ b/process.go @@ -46,13 +46,6 @@ type Memory_infoStat struct { VMS uint64 `json:"vms"` // bytes } -type Memory_mapsStat struct { - Path string `json:"path"` - RSS int32 `json:"rss"` - Anonymous int32 `json:"anonymous"` - Swap int32 `json:"swap"` -} - type RlimitStat struct { Resource int32 `json:"resource"` Soft int32 `json:"soft"` diff --git a/process_freebsd.go b/process_freebsd.go index ae05af64..4a21716c 100644 --- a/process_freebsd.go +++ b/process_freebsd.go @@ -9,6 +9,13 @@ import ( "unsafe" ) +// Memory_info_ex is different between OSes +type Memory_info_exStat struct { +} + +type Memory_mapsStat struct { +} + func Pids() ([]int32, error) { ret := make([]int32, 0) procs, err := processes() @@ -23,6 +30,11 @@ func Pids() ([]int32, error) { return ret, nil } +func (p *Process) Memory_Maps() (*[]Memory_mapsStat, error) { + ret := make([]Memory_mapsStat, 0) + return ret, nil +} + func copy_params(k *Kinfo_proc, p *Process) error { p.Exe = byteToString(k.Ki_comm[:]) p.Ppid = k.Ki_ppid diff --git a/process_linux.go b/process_linux.go index 70c08633..74fb7664 100644 --- a/process_linux.go +++ b/process_linux.go @@ -27,6 +27,20 @@ type Memory_info_exStat struct { Dirty uint64 `json:"dirty"` // bytes } +type Memory_mapsStat struct { + Path string `json:"path"` + Rss uint64 `json:"rss"` + Size uint64 `json:"size"` + Pss uint64 `json:"pss"` + Shared_clean uint64 `json:"shared_clean"` + Shared_dirty uint64 `json:"shared_dirty"` + Private_clean uint64 `json:"private_clean"` + Private_dirty uint64 `json:"private_dirty"` + Referenced uint64 `json:"referenced"` + Anonymous uint64 `json:"anonymous"` + Swap uint64 `json:"swap"` +} + type fillFunc func(pid int32, p *Process) error func NewProcess(pid int32) (*Process, error) { @@ -51,6 +65,73 @@ func NewProcess(pid int32) (*Process, error) { return p, nil } +// Get memory maps from /proc/(pid)/smaps +// This is a function. Because Memory map information is very big. +func (p *Process) Memory_Maps() (*[]Memory_mapsStat, error) { + pid := p.Pid + ret := make([]Memory_mapsStat, 0) + smapsPath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "smaps") + contents, err := ioutil.ReadFile(smapsPath) + if err != nil { + return nil, err + } + lines := strings.Split(string(contents), "\n") + + // function of parsing a block + get_block := func(first_line []string, block []string) Memory_mapsStat { + m := Memory_mapsStat{} + m.Path = first_line[len(first_line)-1] + + for _, line := range block { + field := strings.Split(line, ":") + if len(field) < 2 { + continue + } + v := strings.Trim(field[1], " kB") // remove last "kB" + switch field[0] { + case "Size": + m.Size = parseUint64(v) + case "Rss": + m.Rss = parseUint64(v) + case "Pss": + m.Pss = parseUint64(v) + case "Shared_Clean": + m.Shared_clean = parseUint64(v) + case "Shared_Dirty": + m.Shared_dirty = parseUint64(v) + case "Private_Clean": + m.Private_clean = parseUint64(v) + case "Private_Dirty": + m.Private_dirty = parseUint64(v) + case "Referenced": + m.Referenced = parseUint64(v) + case "Anonymous": + m.Anonymous = parseUint64(v) + case "Swap": + m.Swap = parseUint64(v) + } + } + return m + } + + blocks := make([]string, 16) + for _, line := range lines { + field := strings.Split(line, " ") + if strings.HasSuffix(field[0], ":") == false { + // new block section + if len(blocks) > 0 { + ret = append(ret, get_block(field, blocks)) + } + // starts new block + blocks = make([]string, 16) + } else { + blocks = append(blocks, line) + } + } + + return &ret, nil +} + // Parse to int32 without error func parseInt32(val string) int32 { vv, _ := strconv.ParseInt(val, 10, 32) @@ -146,7 +227,7 @@ func fillFromStatm(pid int32, p *Process) error { return nil } -// get various status from /proc/(pid)/status +// Get various status from /proc/(pid)/status func fillFromStatus(pid int32, p *Process) error { statPath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "status") contents, err := ioutil.ReadFile(statPath) diff --git a/process_test.go b/process_test.go index 4589fadd..302cc490 100644 --- a/process_test.go +++ b/process_test.go @@ -34,7 +34,7 @@ func Test_Pid_exists(t *testing.T) { } func Test_NewProcess(t *testing.T) { - check_pid := 1 + check_pid := 19472 if runtime.GOOS == "windows" { check_pid = 0 } @@ -47,3 +47,20 @@ func Test_NewProcess(t *testing.T) { d, _ := json.Marshal(ret) fmt.Println(string(d)) } + +func Test_Process_memory_maps(t *testing.T) { + check_pid := 19472 + if runtime.GOOS == "windows" { + check_pid = 0 + } + ret, err := NewProcess(int32(check_pid)) + + mmaps, err := ret.Memory_Maps() + if err != nil { + t.Errorf("memory map get error %v", err) + } + for _, m := range *mmaps { + fmt.Println(m) + } + +} diff --git a/process_windows.go b/process_windows.go index a69d1a07..7c4754e0 100644 --- a/process_windows.go +++ b/process_windows.go @@ -50,6 +50,13 @@ type SYSTEM_PROCESS_INFORMATION struct { } */ +// Memory_info_ex is different between OSes +type Memory_info_exStat struct { +} + +type Memory_mapsStat struct { +} + func Pids() ([]int32, error) { ret := make([]int32, 0) @@ -64,6 +71,11 @@ func Pids() ([]int32, error) { return ret, nil } +func (p *Process) Memory_Maps() (*[]Memory_mapsStat, error) { + ret := make([]Memory_mapsStat, 0) + return ret, nil +} + func NewProcess(pid int32) (*Process, error) { p := &Process{Pid: pid}