-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Processes() is extremely CPU intensive #842
Comments
@xxxserxxx could you also try go-sysinfo? I've been wondering but not much time to try it atm. |
Yeah! Thanks; this gives me some impetus to build out proper benchmarks for devices. |
Np, please feel free to share the results, it would be very helpful to me -and anyone needing a process data library in Go- as well. |
I may guess that In fact, we already have the following issues that aim to optimize this: #286, #413. |
I wrote a benchmark, and am attaching it here; again, github has a restricted set of suffixes, so resuffix the file to The attached file is a proper benchmark containing all three implementations: forking,
Of note is that the forking version is the only one that doesn't generate errors when processing data. What I saw of the errors, they appear to be related to processes disappearing while the libraries are gathering information about the process. I'm see vaguely conflicting results. According to the benchmark, EditHow about I go ahead and attach that benchmark, huh? |
I meant to @AtakanColak. Also, @Lomanic -- what did you mean, "benchmark before this change?" Do you want me to fix the version at the commit prior to #821 and benchmark that? The commit immediately prior to the merge was v2.20.1, which made things easy. I pinned the version in ##### v2.20.1
➜ ps go test -benchtime=20s -bench .
go: downloading github.com/shirou/gopsutil v2.20.1+incompatible
goos: linux
goarch: amd64
pkg: ser1.net/perf
BenchmarkForking-8 2430 9777497 ns/op
--- BENCH: BenchmarkForking-8
perf_test.go:25: forking errors: 0
perf_test.go:25: forking errors: 0
perf_test.go:25: forking errors: 0
BenchmarkGoPSUtil-8 1186 21953451 ns/op
--- BENCH: BenchmarkGoPSUtil-8
perf_test.go:32: GoPsUtil errors: 0
perf_test.go:32: GoPsUtil errors: 1
perf_test.go:32: GoPsUtil errors: 16
BenchmarkGoSysInfo-8 2703 8751875 ns/op
--- BENCH: BenchmarkGoSysInfo-8
perf_test.go:39: GoSysInfo errors: 0
perf_test.go:39: GoSysInfo errors: 0
perf_test.go:39: GoSysInfo errors: 28
PASS
ok ser1.net/perf 77.424s The difference is within an easy margin of error, so I ran it again with just the ##### v2.20.1
➜ ps go test -benchtime=20s -bench=BenchmarkGoPSUtil .
goos: linux
goarch: amd64
pkg: ser1.net/perf
BenchmarkGoPSUtil-8 1164 20295012 ns/op
--- BENCH: BenchmarkGoPSUtil-8
perf_test.go:32: GoPsUtil errors: 0
perf_test.go:32: GoPsUtil errors: 0
perf_test.go:32: GoPsUtil errors: 7
PASS
ok ser1.net/perf 25.732s
##### v2.20.2
➜ ps go test -benchtime=20s -bench=BenchmarkGoPSUtil .
goos: linux
goarch: amd64
pkg: ser1.net/perf
BenchmarkGoPSUtil-8 1131 21108605 ns/op
--- BENCH: BenchmarkGoPSUtil-8
perf_test.go:32: GoPsUtil errors: 0
perf_test.go:32: GoPsUtil errors: 0
perf_test.go:32: GoPsUtil errors: 13
PASS
ok ser1.net/perf 26.044s |
Another hiccup with Now I'm wondering how |
@xxxserxxx First of all thank you for your beautiful work. It has also given me few ideas. However, do let me know if I'm wrong, when you execute a To my understanding EDIT: I have taken some look into how |
You're right: I'm not tracking the Yeah, I don't know about I do know that some errors are because processes are disappearing between the time the library is pulling a list of procs and reading data on the procs. So the handles are literally disappearing, like if you read a directory glob and something deleted files before you processed each file. Again, I haven't dug into internals, but this could be mitigated by recognizing that the handle has disappeared and just swallowing it rather than returning errors on it. I believe That said, I'm less worried about the disappearing handles. That can be easily recognized and handled in client code. I'm more concerned about the permission errors I see. Also, I only know the permission issue is happening with |
Exactly, just out of curiosity, I was not expecting a spectacular difference. Sorry for this noise.
That's also the case for gopsutil, see my previous comment. ps, go-sysinfo and gopsutil all get their data about processes from procfs on Linux. There is no special syscalls involved. Hence they should report the same errors. Maybe gopsutil and go-sysinfo don't use the exact same files to get the same data, files with different permissions then. About the core issue reported (comparatively high CPU usage compared to ps), see my previous message. Determining how go-sysinfo is able to get this data more efficiently than gopsutil would need some profiling to check what both libraries do differently, this benchmark provides an interesting data point, thanks for this. |
I've been reading back through the thread, and I just realized that it doesn't matter whether we're counting the I don't think we can explain away the performance because of the off-load onto a separate child process which (a) isn't persistent, and (b) is irrelevant for the benchmark. |
We are seeing a major performance regression on linux between 2.20.4 and 2.20.5. With CPU jumping in a test case from 14% with about 280 processes in 2.20.4, to 195% in 2.20.5. Looks like there was some cache code removed which may be suspect. |
We don't cache BootTime anymore to fix #837. We retrieve this value for each new process instantiation as a consequence to this call to CreateTime() (call to BootTime()), so we can later compare this value in a future call to IsRunning(). #945 may bring some improvements by getting uptime through the sysinfo syscall. |
Here's an update from nearly a year later: I updated to 10642» go test -benchtime=20s -bench .
goos: linux
goarch: amd64
pkg: ser1.net/perf
cpu: Intel(R) Core(TM) i5-8265U CPU @ 1.60GHz
BenchmarkForking-8 1028 23357252 ns/op
--- BENCH: BenchmarkForking-8
perf_test.go:25: forking errors: 0
perf_test.go:25: forking errors: 0
perf_test.go:25: forking errors: 0
BenchmarkGoPSUtil-8 40 556564316 ns/op
--- BENCH: BenchmarkGoPSUtil-8
perf_test.go:32: GoPsUtil errors: 0
perf_test.go:32: GoPsUtil errors: 0
BenchmarkGoSysInfo-8 964 25360231 ns/op
--- BENCH: BenchmarkGoSysInfo-8
perf_test.go:39: GoSysInfo errors: 0
perf_test.go:39: GoSysInfo errors: 0
perf_test.go:39: GoSysInfo errors: 7
PASS
ok ser1.net/perf 76.207s
10643» grep shirou go.mod
github.com/shirou/gopsutil/v3 v3.21.8 |
A significant performance issue has been observed in the 'gopsutil' library on Linux when comparing versions 2.20.4 and 2.20.5. In version 2.20.4, a particular test case with approximately 280 processes exhibited a CPU usage of 14%. However, in version 2.20.5, the CPU usage skyrocketed to 195%. This performance degradation can be attributed to the removal of BootTime caching in order to address a specific scenario where a device initially reports an incorrect date (e.g., epoch or a more recent date set by a tool like 'fake_hwclock') and later corrects it using NTP. This results in 'gopsutil' reporting incorrect system uptime. You can find further details and discussions regarding this issue in the following link: #1283 (comment) |
@cforce And #1579 introduces the |
Describe the bug
Processes()
is significantly more resource intensive than even forkingps
withexec.Command
and parsing the results.To Reproduce
Download the attached go source code (and rename to
perf.go
it because github is dumb) and run it on the command line with:The argument is the number of iterations; you may need to start with fewer if it runs too long.
Expected behavior
I'd expect the native code to be more resource efficient than spawning a child
ps
process. On my machine, I consistently see CPU use of between 2x and 4x CPU use, and much slower results:Environment (please complete the following information):
/etc/os-release
and the result ofuname -a
](trimmed some attributes out)
Edit
I noticed this while doing some development work on gotop; running both branches, for about an hour, it didn't stray off this:
The text was updated successfully, but these errors were encountered: