Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Processes() calls with many cores #1514

Merged
merged 8 commits into from Aug 29, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 24 additions & 0 deletions internal/common/common.go
Expand Up @@ -114,6 +114,30 @@ func ReadLines(filename string) ([]string, error) {
return ReadLinesOffsetN(filename, 0, -1)
}

// ReadLine reads a file and returns the first occurrence of a line that is prefixed with prefix.
func ReadLine(filename string, prefix string) (string, error) {
f, err := os.Open(filename)
if err != nil {
return "", err
}
defer f.Close()
r := bufio.NewReader(f)
for {
line, err := r.ReadString('\n')
if err != nil {
if err == io.EOF {
break
}
return "", err
}
if strings.HasPrefix(line, prefix) {
return line, nil
}
}

return "", nil
}

// ReadLinesOffsetN reads contents from file and splits them by new line.
// The offset tells at which line number to start.
// The count determines the number of lines to read (starting from offset):
Expand Down
69 changes: 39 additions & 30 deletions internal/common/common_linux.go
Expand Up @@ -62,17 +62,38 @@ func BootTimeWithContext(ctx context.Context) (uint64, error) {
return 0, err
}

statFile := "stat"
useStatFile := true
if system == "lxc" && role == "guest" {
// if lxc, /proc/uptime is used.
statFile = "uptime"
useStatFile = false
} else if system == "docker" && role == "guest" {
// also docker, guest
statFile = "uptime"
useStatFile = false
}

filename := HostProcWithContext(ctx, statFile)
if useStatFile {
return readBootTimeStat(ctx)
}

filename := HostProcWithContext(ctx, "uptime")
lines, err := ReadLines(filename)
if err != nil {
return handleBootTimeFileReadErr(err)
}
if len(lines) != 1 {
return 0, fmt.Errorf("wrong uptime format")
}
f := strings.Fields(lines[0])
b, err := strconv.ParseFloat(f[0], 64)
if err != nil {
return 0, err
}
currentTime := float64(time.Now().UnixNano()) / float64(time.Second)
t := currentTime - b
return uint64(t), nil
}

func handleBootTimeFileReadErr(err error) (uint64, error) {
if os.IsPermission(err) {
var info syscall.Sysinfo_t
err := syscall.Sysinfo(&info)
Expand All @@ -84,39 +105,27 @@ func BootTimeWithContext(ctx context.Context) (uint64, error) {
t := currentTime - int64(info.Uptime)
return uint64(t), nil
}
return 0, err
}

func readBootTimeStat(ctx context.Context) (uint64, error) {
filename := HostProcWithContext(ctx, "stat")
line, err := ReadLine(filename, "btime")
if err != nil {
return 0, err
return handleBootTimeFileReadErr(err)
}

if statFile == "stat" {
for _, line := range lines {
if strings.HasPrefix(line, "btime") {
f := strings.Fields(line)
if len(f) != 2 {
return 0, fmt.Errorf("wrong btime format")
}
b, err := strconv.ParseInt(f[1], 10, 64)
if err != nil {
return 0, err
}
t := uint64(b)
return t, nil
}
}
} else if statFile == "uptime" {
if len(lines) != 1 {
return 0, fmt.Errorf("wrong uptime format")
if strings.HasPrefix(line, "btime") {
f := strings.Fields(line)
if len(f) != 2 {
return 0, fmt.Errorf("wrong btime format")
}
f := strings.Fields(lines[0])
b, err := strconv.ParseFloat(f[0], 64)
b, err := strconv.ParseInt(f[1], 10, 64)
if err != nil {
return 0, err
}
currentTime := float64(time.Now().UnixNano()) / float64(time.Second)
t := currentTime - b
return uint64(t), nil
t := uint64(b)
return t, nil
}

return 0, fmt.Errorf("could not find btime")
}

Expand Down
7 changes: 7 additions & 0 deletions process/process_test.go
Expand Up @@ -19,6 +19,7 @@ import (
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/shirou/gopsutil/v3/internal/common"
)
Expand Down Expand Up @@ -862,3 +863,9 @@ func BenchmarkProcessPpid(b *testing.B) {
p.Ppid()
}
}

func BenchmarkProcesses(b *testing.B) {
ps, err := Processes()
require.NoError(b, err)
require.Greater(b, len(ps), 0)
}
atoulme marked this conversation as resolved.
Show resolved Hide resolved