in patches/gopsutil/v3/process/process_linux.go [380:481]
func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) {
pid := p.Pid
var ret []MemoryMapsStat
smapsPath := common.HostProc(strconv.Itoa(int(pid)), "smaps")
if grouped {
ret = make([]MemoryMapsStat, 1)
// If smaps_rollup exists (require kernel >= 4.15), then we will use it
// for pre-summed memory information for a process.
smapsRollupPath := common.HostProc(strconv.Itoa(int(pid)), "smaps_rollup")
if _, err := os.Stat(smapsRollupPath); !os.IsNotExist(err) {
smapsPath = smapsRollupPath
}
}
contents, err := ioutil.ReadFile(smapsPath)
if err != nil {
return nil, err
}
lines := strings.Split(string(contents), "\n")
// function of parsing a block
getBlock := func(firstLine []string, block []string) (MemoryMapsStat, error) {
m := MemoryMapsStat{}
m.Path = firstLine[len(firstLine)-1]
for _, line := range block {
if strings.Contains(line, "VmFlags") {
continue
}
field := strings.Split(line, ":")
if len(field) < 2 {
continue
}
v := strings.Trim(field[1], "kB") // remove last "kB"
v = strings.TrimSpace(v)
t, err := strconv.ParseUint(v, 10, 64)
if err != nil {
return m, err
}
switch field[0] {
case "Size":
m.Size = t
case "Rss":
m.Rss = t
case "Pss":
m.Pss = t
case "Shared_Clean":
m.SharedClean = t
case "Shared_Dirty":
m.SharedDirty = t
case "Private_Clean":
m.PrivateClean = t
case "Private_Dirty":
m.PrivateDirty = t
case "Referenced":
m.Referenced = t
case "Anonymous":
m.Anonymous = t
case "Swap":
m.Swap = t
}
}
return m, nil
}
var firstLine []string
blocks := make([]string, 0, 16)
for i, line := range lines {
fields := strings.Fields(line)
if (len(fields) > 0 && !strings.HasSuffix(fields[0], ":")) || i == len(lines)-1 {
// new block section
if len(firstLine) > 0 && len(blocks) > 0 {
g, err := getBlock(firstLine, blocks)
if err != nil {
return &ret, err
}
if grouped {
ret[0].Size += g.Size
ret[0].Rss += g.Rss
ret[0].Pss += g.Pss
ret[0].SharedClean += g.SharedClean
ret[0].SharedDirty += g.SharedDirty
ret[0].PrivateClean += g.PrivateClean
ret[0].PrivateDirty += g.PrivateDirty
ret[0].Referenced += g.Referenced
ret[0].Anonymous += g.Anonymous
ret[0].Swap += g.Swap
} else {
ret = append(ret, g)
}
}
// starts new block
blocks = make([]string, 0, 16)
firstLine = fields
} else {
blocks = append(blocks, line)
}
}
return &ret, nil
}