Skip to content

Commit

Permalink
proc walker: cache limits and cmdline/name after parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
alban committed May 3, 2017
1 parent 1b0e36c commit b4b73df
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 61 deletions.
41 changes: 0 additions & 41 deletions probe/process/cache.go

This file was deleted.

81 changes: 61 additions & 20 deletions probe/process/walker_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ package process

import (
"bytes"
"encoding/binary"
"fmt"
"os"
"path"
"strconv"
"strings"

linuxproc "github.com/c9s/goprocinfo/linux"
"github.com/coocood/freecache"

"github.com/weaveworks/common/fs"
"github.com/weaveworks/scope/probe/host"
Expand All @@ -17,6 +20,23 @@ type walker struct {
procRoot string
}

var (
// limitsCache caches /proc/<pid>/limits
// key: filename in /proc. Example: "42"
// value: max open files (soft limit) stored in a [8]byte (uint64, little endian)
limitsCache = freecache.NewCache(1024 * 16)

// cmdlineCache caches /proc/<pid>/cmdline and /proc/<pid>/name
// key: filename in /proc. Example: "42"
// value: two strings separated by a '\0'
cmdlineCache = freecache.NewCache(1024 * 16)
)

const (
limitsCacheTimeout = 60
cmdlineCacheTimeout = 60
)

// NewWalker creates a new process Walker.
func NewWalker(procRoot string) Walker {
return &walker{procRoot: procRoot}
Expand Down Expand Up @@ -97,7 +117,7 @@ func readStats(path string) (ppid, threads int, jiffies, rss, rssLimit uint64, e
}

func readLimits(path string) (openFilesLimit uint64, err error) {
buf, err := cachedReadFile(path)
buf, err := fs.ReadFile(path)
if err != nil {
return 0, err
}
Expand Down Expand Up @@ -130,6 +150,27 @@ func readLimits(path string) (openFilesLimit uint64, err error) {
return softLimit, nil
}

func (w *walker) readCmdline(filename string) (cmdline, name string) {
if cmdlineBuf, err := fs.ReadFile(path.Join(w.procRoot, filename, "cmdline")); err == nil {
// like proc, treat name as the first element of command line
i := bytes.IndexByte(cmdlineBuf, '\000')
if i == -1 {
i = len(cmdlineBuf)
}
name = string(cmdlineBuf[:i])
cmdlineBuf = bytes.Replace(cmdlineBuf, []byte{'\000'}, []byte{' '}, -1)
cmdline = string(cmdlineBuf)
}
if name == "" {
if commBuf, err := fs.ReadFile(path.Join(w.procRoot, filename, "comm")); err == nil {
name = "[" + strings.TrimSpace(string(commBuf)) + "]"
} else {
name = "(unknown)"
}
}
return
}

// Walk walks the supplied directory (expecting it to look like /proc)
// and marshalls the files into instances of Process, which it then
// passes one-by-one to the supplied function. Walk is only made public
Expand All @@ -156,29 +197,29 @@ func (w *walker) Walk(f func(Process, Process)) error {
continue
}

openFilesLimit, err := readLimits(path.Join(w.procRoot, filename, "limits"))
if err != nil {
continue
var openFilesLimit uint64
if v, err := limitsCache.Get([]byte(filename)); err == nil {
openFilesLimit = binary.LittleEndian.Uint64(v)
} else {
openFilesLimit, err = readLimits(path.Join(w.procRoot, filename, "limits"))
if err != nil {
continue
}
buf := make([]byte, 8)
binary.LittleEndian.PutUint64(buf, openFilesLimit)
limitsCache.Set([]byte(filename), buf, limitsCacheTimeout)
}

cmdline, name := "", ""
if cmdlineBuf, err := cachedReadFile(path.Join(w.procRoot, filename, "cmdline")); err == nil {
// like proc, treat name as the first element of command line
i := bytes.IndexByte(cmdlineBuf, '\000')
if i == -1 {
i = len(cmdlineBuf)
}
name = string(cmdlineBuf[:i])
cmdlineBuf = bytes.Replace(cmdlineBuf, []byte{'\000'}, []byte{' '}, -1)
cmdline = string(cmdlineBuf)
}
if name == "" {
if commBuf, err := cachedReadFile(path.Join(w.procRoot, filename, "comm")); err == nil {
name = "[" + strings.TrimSpace(string(commBuf)) + "]"
} else {
name = "(unknown)"
}
if v, err := cmdlineCache.Get([]byte(filename)); err == nil {
separatorPos := strings.Index(string(v), "\x00")
cmdline = string(v[:separatorPos])
name = string(v[separatorPos+1:])
} else {
cmdline, name = w.readCmdline(filename)
cmdlineCache.Set([]byte(filename), []byte(fmt.Sprintf("%s\x00%s", cmdline, name)), cmdlineCacheTimeout)
}

f(Process{
PID: pid,
PPID: ppid,
Expand Down

0 comments on commit b4b73df

Please sign in to comment.