Link to home
Start Free TrialLog in
Avatar of cnxmax
cnxmax

asked on

How to use GetThreadTimes in vb.net 4.0 visualstudio2010

I have a VB.net 4.0 cloud project in VS2010.  In Worker1.Role I create a thread whose execute function is called ProcessWork found in Class Worker.  The cloud project is all working fine.

Now I want to know how much CPU my thread consumes (kernel/user).  My plan was to call GetThreadTimes at the start and finish of ProcessWork and use the values to calculate overall usage.  Problem is GetThreadTimes requires the thread's handle.  How do I get a VB.net's thread handle when using Threading.Thread?  How do I get oThisWorkThread's handle in the code attached?

I have tried using OpenThread to return the handle but it requires the ThreadID.  I tried using oThisWorkThread.ManagedThreadID (=17) as the threadID but I get a handle back of -2...which does not look like a good handle and when the handle (-2) is used in GetThreadTimes I get a memory violation error.

I am not firm to use GetThreadTimes so if anyone has another VB.net way of getting a thread's CPU time please let me know.

I also tried using a function called CreateThread instead of "New Threading.Thread" but that seems to be a C++C# function.  I tried CreateThread because it returns the created thread's handle.
Dim oNewWorker As New Worker(sManagerID, oWorkItem)
Dim oThisWorkThread As Thread
Dim oThreadStart As New ThreadStart(AddressOf oNewWorker.ProcessWork)
oThisWorkThread = New Thread(oThreadStart)
oThisWorkThread.Start()

Open in new window

Avatar of graye
graye
Flag of United States of America image

There is a good description the following article (about half way down) that explains that you use a low-level API call to get the "real" thread ID.  The 2nd link has the P/Invoke "signature"

http://stackoverflow.com/questions/1279950/relationship-between-managedthreadid-and-operating-system-threadid
http://www.pinvoke.net/default.aspx/kernel32.getcurrentthreadid

It would look like this:

        Thread.BeginThreadAffinity()
        Dim RealThreadID as Inptr
        RealThreadID = GetCurrentThreadId()
        Thread.EndThreadAffinity()
oops, I see that should have been an Integer (and not an IntPtr) in my example.
Avatar of cnxmax
cnxmax

ASKER

qraye, thanks for responding.  The caravan seems to have moved forward somewhat.

I now appear to get a reasonable ThreadID (like 2392) from GetCurrentThreadID which I feed to OpenThread.  OpenThread appears to be giving me a reasonable ThreadHandle (like 23435).  I feed the ThreadHandle to GetThreadTimes (see code snipet).  Problem is I always get the same result from GetThreadTimes...i get 156001 or 0 even though the "do some work" various greatly in wall time to accomplish (not much else is going on in my development maching).  Can you see a problem with my code?

As a side note i did a little experimenting with OpenThread.  I called OpenThread multiple times (one code line after another) using the same arguments (same access, same boolean, same iThreadID). Each time it returns a different ThreadHandle...very strange.  Not sure to what to make of that.

Still searching for the amount of processor time a thread consumes...if anyone has a different approach please let me know.  Thanks.
Public Sub ProcessWork(ByRef iProcessorTime as integer)
Thread.BeginThreadAffinity()

Dim iThreadHandle As IntPtr
Dim iCreationTime,  ExitTime, KernelTime, UserTime As Long
Dim iThreadID As Integer = GetCurrentThreadId()
iThreadHandle = OpenThread(ThreadAccess.SET_INFORMATION Or ThreadAccess.QUERY_INFORMATION, False, iThreadID)

GetThreadTimes(iThreadHandle, iCreationTime, ExitTime, KernelTime, UserTime)
Dim iStartTime = KernelTime + UserTime
'
' do some work
'
GetThreadTimes(iThreadHandle, iFinishCreationTime, ExitTime, KernelTime, UserTime)
Dim iFinishTime As Integer = KernelTime + UserTime
Dim iProcessorTime = iFinishTime - iStartTime

Thread.EndThreadAffinity()
End Sub

Open in new window

Have a look at the ProcessThread Class

ProcessThread Class
http://msdn.microsoft.com/en-us/library/system.diagnostics.processthread.aspx
Private Sub GetThreadTime()
        Dim ptc As ProcessThreadCollection = Process.GetCurrentProcess.Threads
        For Each pt As ProcessThread In ptc
            Debug.Print("id={0}     UserProcessorTime={1}   TotalProcessorTime={2}", pt.Id, pt.UserProcessorTime.TotalMilliseconds, pt.TotalProcessorTime.TotalMilliseconds)
        Next
    End Sub

Open in new window

Avatar of cnxmax

ASKER

eql1044 thanks for responding.  I am still investigating ProcessThreadCollection but this is what i found so far.

As I interate through my ptc i check the pt.ID against my iThreadID and I sometimes find my iThreadID and sometime i do not.  I have also read several articles about ProcessThreadCollection and am forming a conclusion that the collection of threads found in ProcessThreadCollection is of the type "Process Thread"  which appears to not be the same kind as my "oThisWorkThread = New Thread" thread...which would explain why i do not always find my iThreadID in my ptc.

The search contains.
.NET generates and manages it's own thread ID (ManagedThreadId) it's different than the ID generated by the OS. The Id from the ProcessThread class is the real native thread Id. If your thread isn't running at the time you call the function it won't be located since the thread has already exited. If you use GetCurrentThreadId in your thread function that will be the same Id returned from ProcessThread Id.


Avatar of cnxmax

ASKER

eql1044 thanks for responding.  Please see my revised code.  I might not understand ProcessThreadCollection correctly.  

You said  "If your thread isn't running at the time you call the function it won't be located since the thread has already exited".  

I think my thread is running when I use ProcessThreadCollection because I am calling ProcessThreadCollection  in my thread.  That is my interpertation of the use of ProcessThreadCollection .  I thought if i did some work in a thread I could then ask ProcessThreadCollection how much TotalProcessorTime i used (in milliseconds).  Am i not to use ProcessThreadCollection  IN  my thread but instead should hand my iThreadID to an outside observer thread who monitors the thread represented by iThreadID?
Public Sub ProcessWork(ByRef iProcessorTime as integer)
Thread.BeginThreadAffinity()
Dim iThreadID As Integer = GetCurrentThreadId()
'
' do some work
'
Dim iProcessorTime As Integer = -1
Dim ptc As ProcessThreadCollection = Process.GetCurrentProcess.Threads
For Each pt As ProcessThread In ptc
   If pt.Id = iThreadID Then
      iProcessorTime = pt.TotalProcessorTime.Milliseconds
   End If
Next

Thread.EndThreadAffinity()
End Sub

Open in new window

If you call the function in your thread it will change the results since your thread is going to be executing the code and in turn will be adding more overhead to your thread function giving different time results. That's why when you want to time your thread only use the code that will be executed in realtime scenario. You can call the example from the forms thread or create another thread to time your threads. This class gives the information your looking for and is equivlent to using the P/Invoke but instead it's wrapped up already in managed code.
Avatar of cnxmax

ASKER

eq1044 thanks for responding.  I think i have a bead on it.  Adding a little overhead to each measurement is acceptable since (i'm assuming) the overhead is approximately the same for each thread life.  My customer is going to be charged by the percent of processor time they use so adding the overhead will not be a big deal.

I am curious however... If I try to get the thread's TotalProcessorTime by using ProcessThreadCollection running in some OTHER thread how exactly is that done.   How does the OTHER thread know the iThreadID in question? How does the OTHER thread know when iThreadID is done processing but not yet exited.  Don't I have to use ptc before the iThreadID thread exits?

As a side note:  I did more exacting testing with ptc using a test project.  I created a thread and called ptc at the end to check the TotalProcessorTime (calling ptc at the end of ProcessWork subroutine while still in the thread).  In these experiments I did find my iThreadID in ptc every time.  My other testing was more hurried and possibly flawed.
ASKER CERTIFIED SOLUTION
Avatar of nffvrxqgrcfqvvc
nffvrxqgrcfqvvc

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of cnxmax

ASKER

Good job.  Well done.