Windows - syscall.GetProcessTimes() always shows 0 values.

760 views
Skip to first unread message

kevin.mic...@gmail.com

unread,
May 31, 2017, 7:23:55 PM5/31/17
to golang-nuts
I am trying to query the process statistics against the runtime in Windows so I can monitor it's utilisation.

First, I get the process handle for the runtime:

// GetCurrentProcess will return our process handle with the appropriate information.
func
GetCurrentProcess() (syscall.Handle, error) {
    myProcess
, err := syscall.GetCurrentProcess()
   
if err != nil {
       
return syscall.Handle(0), err
   
}
   
return syscall.Handle(myHandle), err
}



Then, I sleep for one second to make sure the process has been running for at least one second, so no counters will be 0. After that, I call `syscall.GetProcessTimes()`:

func (p *ProcInfo) GetProcessTimes() error {
    lpCreationTime
:= new(syscall.Filetime)
    lpExitTime
:= new(syscall.Filetime)
    lpKernelTime
:= new(syscall.Filetime)
    lpUserTime
:= new(syscall.Filetime)

   
if err := syscall.GetProcessTimes(p.handle, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime); err != nil {
       
return err
   
}

    p
.CreationTime = lpCreationTime
    p
.ExitTime = lpExitTime
    p
.KernelTime = lpKernelTime
    p
.UserTime = lpUserTime

   
return nil
}



Once that is done, I print out the values:

func main() {
    me
, err := GetCurrentProcess()
   
if err != nil {
        fmt
.Println(err)
        os
.Exit(1)
   
}

    proc
:= &ProcInfo{handle: me}

    time
.Sleep(time.Duration(time.Second * 1))

    err
= proc.GetProcessTimes()
   
if err != nil {
        fmt
.Println(err)
        os
.Exit(1)
   
}

    fmt
.Printf("%#v\n", proc)
    fmt
.Printf("kernel low time: %d\n", proc.KernelTime.LowDateTime)
    fmt
.Printf("kernel high time: %d\n", proc.KernelTime.HighDateTime)
    fmt
.Printf("user low time: %d\n", proc.UserTime.LowDateTime)
    fmt
.Printf("user high time: %d\n", proc.UserTime.HighDateTime)
}



I've been reading through the Windows API documentation and it should return the value in 100-nanosecond units the process has spent in user and/or kernel space. However, even thought I'm sleeping my little test program for 1 second, all the counters from `syscall.GetProcessTimes()` are 0. They should at least be in the millions since the program slept for 1 second.

Here is the full code: https://play.golang.org/p/_Z3o4H2WwR

Is this a bug or am I not using it correctly?

Steven Hartland

unread,
May 31, 2017, 9:12:37 PM5/31/17
to kevin.mic...@gmail.com, golang-nuts
Your main problem is the fact that the Windows time interval is 16ms by default. It uses this value for its internal timers and thread time quantum, which effectively means you won't see any changes until they have added up to a min of 16ms.

You can see this by changing the 16ms in the following example to something lower, which will cause 0's are you described:

You'll also see I took a different approach to getting the process handle which will work with most processes instead of just the current process, passing a pid, as well as ensuring the retrieved handle is closed; which is not necessary for the pseudo handle returned by GetCurrentProcess.

If you're looking to accurately measure CPU usage on windows you'll instead want to look at QueryProcessCycleTime.

Hope this helps.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

kevin.mic...@gmail.com

unread,
May 31, 2017, 9:29:53 PM5/31/17
to golang-nuts, kevin.mic...@gmail.com
Steven, your example is really helpful! I didn't know Windows had a lower time interval for internal timers, so that's good to know, thanks for getting me unstuck! Thought I was losing my mind.

Is there a reason to pass the PID around instead of using the pseudo handle? I'm new to the core Windows APIs, so I'm not sure when to use processes or handles yet.

Looking at Linux's /proc/[pid]/stat, it gives clock cycles, so thanks for pointing out QueryProcessCycleTime, I think that's what I want over GetProcessTimes. Is QueryProcessCycleTime also subject to the 16ms thread time quantum, or is that a higher precision timer?
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

Steven Hartland

unread,
Jun 1, 2017, 5:36:57 AM6/1/17
to golan...@googlegroups.com
All depends on what your going to end up doing.

If code will deal with processes other than itself then pid is arguably easier to deal with, however if you only ever deal with your process then I would have the NewProcInfo method just setup the handle as you had it (reducing the number of syscalls).

QueryProcessCycleTime is not subject to thread time quantum.

You may find the following useful reading:
http://computerperformancebydesign.com/Articles/windows-performance/cpu-utilization/

    Regards
    Steve
Reply all
Reply to author
Forward
0 new messages