-
-
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
when I List process info on win10, it running a long time(30s), cpu usage 30~40% #250
Comments
To get processes on Windows, gopsutil WMI. and WMI is slow. |
When you fix this? |
Sorry, I haven't have a time for a while. But, PR is always welcome! |
is there any progress about it ? WMI is really slow.. |
Implementation becomes slightly better from this issue first opened. Actually, which API is slow and/or could you give us a sample code and benchmark? |
Sure : This is the method that burst cpu usage from %2-5 to %60-80. package main
import (
"github.com/gin-gonic/gin"
"github.com/bamzi/jobrunner"
"github.com/matishsiao/goInfo"
"github.com/shirou/gopsutil/process"
...
)
func FindProcessByCommandLineInfo(processInfo string) bool {
if processInfo == "" {
log.Fatalf("processInfo not specified!")
}
v, _ := process.Processes()
for _, value := range v {
cmdLine, _ := value.Cmdline()
if strings.Contains(cmdLine, processInfo) {
return true
}
}
return false
} |
Then get this result
This means So, we should eliminate WMI especially |
@shirou yes it seems true. Dou you need something to expand border of your investigation? |
Actually Windows functions are spreads widely to get various process information. So we should implement functions one by one. To implement those, some kind of Ki or fired up is required, so please just wait or I will appreciate if you send a PR! |
@shirou porting WMI calls to Go syscalls is on my TODO list since a very long time, I did not have enough time lately to tackle this big problem, but I will probably be less busy in the next following weeks. As far as I remember, retrieving command-line of a process is done in python's psutil by using the (quite undocumented and maybe subject to future breaking changes) PEB structure (psutil_get_cmdline() calls psutil_get_process_data() which retrieves and uses the PEB structure of the given process), which is not straightforward at all to use… Everything I read elsewhere relies on the PEB structure too. |
@shirou Thank you. btw , Unfortunately screenshot -> Screenshot#1
|
The only remaining functions still using WMI are now IOCounters would probably rely on GetProcessIoCounters. Cmdline is the most difficult one to port to win32 API as there is no other way to get this information but by calling NtQuerySystemInformation (which for the moment I'm not even able to do by reusing existing code in common_windows.go), with some wow64 subtleties according to psutil (from my previous comment in this issue) for parsing the PEB structure of the process. Since win8.1 there is a new parameter |
I am really amazed about your great work @Lomanic ! |
Thanks @shirou. Yes, that was the idea, in a first step before implementing properly NtQuerySystemInformation with PEB parsing. |
NtQueryProcessBasicInformation in |
I pushed a commit in https://github.com/Lomanic/gopsutil/tree/issue250, but as said in the commit message this is functional albeit very hacky and will need some help regarding how to properly parse the result returned by NtQueryInformationProcess to a string (using an array of uint16 and converting it to string with Speed improvement is by approx. of a factor of 10 as I remember (down to a few ms for each process on my win10 VM). |
Current progress: after implementing the UNICODE_STRING type, working properly when running as Administrator on Win10 but failing hard with a panic as a non-elevated user with this stacktrace (different when compiling with GOARCH=386 for even more fun)
With package main
import (
"fmt"
"os"
"time"
"github.com/shirou/gopsutil/process"
)
func main() {
start := time.Now()
procs, err := process.Processes()
if err != nil {
fmt.Println("A", err)
os.Exit(1)
}
for _, proc := range procs {
fmt.Println("PID", proc.Pid)
// proc.Cmdline()
fmt.Println(proc.Cmdline())
}
elapsed := time.Now().Sub(start)
fmt.Println("Elapsed time", elapsed, "(", elapsed/(time.Duration(len(procs))), "per process).", len(procs), "processes")
} |
[process][windows] Use win32 API in process.IOCounters() instead of slow WMI call #250
The only remaining call to WMI is now @AtakanColak it has to be the library StackExchange/wmi not freeing memory after use, or something on gopsutil part of course. I won't have time to debug this, I prefer to get rid off WMI instead in my limited free time. Maybe we could try the fix for StackExchange/wmi#27 (StackExchange/wmi#27 (comment)), as far as I see we don't have this in gopsutil. Would you try adding this in |
@Lomanic I added the comment you mentioned to the init() function;
This is how I tested it;
Unfortunately the memory leak persists. I have to leave it here. |
Thanks for testing, that could have been an easy fix. |
I just found this issue and it was a little late. |
Thanks @Lomanic, you are welcome. |
when I List processes info on win10, it running a long time(30s), cpu usage 30~40%
but on linux , it just need 100ms
The text was updated successfully, but these errors were encountered: