Click here to Skip to main content
15,848,349 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
I've been searching a long time for this one until 2017, but i think No one and Nothing sources give a Hint about a "Real" value of Total CPU Usages just like Task Manager in VB.NET



What I have tried:

Here's some method i have tried with several suggestions on internet
- performance counter
- WMI

eg Case:
In task manager it's shown : CPU is 25%
then when using both Performance counter and WMI method with interval 1000, both of them just shown lower value than in Task Manager (WHY ???)

I think there's someway to get the same result like Task Manager value has, maybe just get all list of all usage of each thread and combine them into one value for one Label eg :
LblCpuUsage.text = CombinedAllCpuUsageOfEachThread.NextValue() , but i dont know how to do it, So does anyone know how to do it ???

Note: Any method should be fine as long it's works and same like Task Manager value (%) has, and VB.NET Code should be Perfect!

Many Thanks,
Joe
Posted
Updated 12-Dec-17 10:44am
v15

There is a helper library to get that information: The Performance Data Helper (see Using the PDH Functions to Consume Counter Data (Windows)[^]).

Microsoft examples are in C but there are also corresponding VB (not .Net) functions:
Performance Counters Functions for Visual Basic (Windows)[^]

The English counter name for the total CPU usage is "\Processor(_Total)\% Processor Time" which can be passed to PdhAddEnglishCounter. When using Pdh[Vb]AddCounter you have to pass a localised string.

Call PdhOpenQuery and PdhAdd[English]Counter once for setup. Then call PdhCollectQueryData periodically to get the actual data. Call PdhCloseQuery upon exit.
 
Share this answer
 
Comments
InfinityJoe 12-Dec-17 10:05am    
Hello mate, thanks for your valuable answer, just reviewed your suggestions, and that's a Great startup point!, btw can you give some Hint about the real Code Usages of this Performance Data Helper method ?

Btw i'm pretty sure if this method can resolve this problem (get Real CPU Usages like in Task Manager), we will help a lot of folks who looking for this one now, and someday! especially who's working on project with CPU Usage reated (only on codeProject) :)

looking forward for more info

Cheers,
Joe

Fyi: I'm looking in VB.NET Code than C ( as long the C code can be easily converted i think that's should be fine, as we know some C code can't be converted easily to VB - vice versa)
Jochen Arndt 12-Dec-17 10:24am    
I'm not a VB programmer and can't therefore help much. But because there are VB methods, it should be no problem for you to use those.

I have tested it with an MFC C++ application and it shows the same value as the task manager.

The example at https://msdn.microsoft.com/en-us/library/windows/desktop/aa371886(v=vs.85).aspx shows how to open a build-in dialog to select a counter. That can be used to get the possible strings.

The PDH library is just an interface to get the data from the OS. There is not much documentation but the C examples can be used to know how it works. Doing similar in VB should be then no problem.
InfinityJoe 12-Dec-17 12:57pm    
Thanks for prompt response mate and thanks for re-check it on the MFC , that's definitely an further progress when this method really shown same value in task manager!, btw i tried to convert it on vb, but seems i needs something info from C++ Programmer below :)

Cheers,
Joe
So here's my rough attempt to Convert the C++ code to VB, but it's seems it's had something that missing listed below (Marked in Bold) :

1. I thought this is an importing a lib/dll statement in C++, so how to get the pdh.lib/dll or Referencing it on VB ?
#pragma comment(lib, "pdh.lib")


2. This one "sizeof" always known of not has an equivalent in VB, so any hint for this one ?
ZeroMemory(&BrowseDlgData, sizeof(PDH_BROWSE_DLG_CONFIG));


3. what is wprintf in C++ ? it's a same like "Console.writeline(...), or debug.writeline(...) ?
wprintf(...)


Any help would be appreciated! :)

The Full Code:
Converted from https://msdn.microsoft.com/en-us/library/windows/desktop/aa371886(v=vs.85).aspx[^]

Imports System
Imports Microsoft.VisualBasic

Public Class PDHMonitor
    
'Declare
    Private Const SAMPLE_INTERVAL_MS As ULong = 1000
    Private Const BROWSE_DIALOG_CAPTION As String = "Select a counter to monitor."

    'C++ TO VB ? 
    #pragma comment(lib, "pdh.lib")

    Private Sub wmain()
        Dim Status As New PDH_STATUS()
        Dim Query As HQUERY = Nothing
        Dim Counter As New HCOUNTER()
        Dim DisplayValue As New PDH_FMT_COUNTERVALUE()
        Dim CounterType As UInteger
        Dim SampleTime As New SYSTEMTIME()
        Dim BrowseDlgData As New PDH_BROWSE_DLG_CONFIG()
        Dim CounterPathBuffer As New String(New Char(PDH_MAX_COUNTER_PATH - 1) {})

        'Create a query.
        Status = PdhOpenQuery(Nothing, Nothing, Query)

        If Status IsNot ERROR_SUCCESS Then
            wprintf(LvbLf & "PdhOpenQuery failed with status 0x%x.", Status)
            GoTo Cleanup
        End If

        'Initialize the browser dialog window settings.
        ZeroMemory(CounterPathBuffer, Len(CounterPathBuffer))

        'C++ TO VB equivalent of 'sizeof' ?
        ZeroMemory(BrowseDlgData, sizeof(PDH_BROWSE_DLG_CONFIG))

         With BrowseDlgData
            .bIncludeInstanceIndex = 0
            .bSingleCounterPerAdd = 1
            .bSingleCounterPerDialog = 1
            .bLocalCountersOnly = 0
            .bWildCardInstances = 1
            .bHideDetailBox = 1
            .bInitializePath = 0
            .bDisableMachineSelection = 0
            .bIncludeCostlyObjects = 0
            .bShowObjectBrowser = 0
            .hWndOwner = Nothing
            .szReturnPathBuffer = CounterPathBuffer
            .cchReturnPathLength = PDH_MAX_COUNTER_PATH
            .pCallBack = Nothing
            .dwCallBackArg = 0
            .CallBackStatus = ERROR_SUCCESS
            .dwDefaultDetailLevel = PERF_DETAIL_WIZARD
            .szDialogBoxCaption = BROWSE_DIALOG_CAPTION
        End With

        ' Display the counter browser window. The dialog is configured
        ' to return a single selection from the counter list.
        Status = PdhBrowseCounters(BrowseDlgData)

        If Status IsNot ERROR_SUCCESS Then
            If Status Is PDH_DIALOG_CANCELLED Then
                Console.Write(LvbLf & "Dialog canceled by user.")
            Else
                wprintf(LvbLf & "PdhBrowseCounters failed with status 0x%x.", Status)
            End If
            GoTo Cleanup
        ElseIf CounterPathBuffer.Length = 0 Then
            Console.Write(LvbLf & "User did not select any counter.")
            GoTo Cleanup
        Else
            wprintf(LvbLf & "Counter selected: %s" & vbLf, CounterPathBuffer)
        End If

        'Add the selected counter to the query.
        Status = PdhAddCounter(Query, CounterPathBuffer, 0, Counter)
        If Status IsNot ERROR_SUCCESS Then
            wprintf(LvbLf & "PdhAddCounter failed with status 0x%x.", Status)
            GoTo Cleanup
        End If

        ' Most counters require two sample values to display a formatted value.
        ' PDH stores the current sample value and the previously collected
        ' sample value. This call retrieves the first value that will be used
        ' by PdhGetFormattedCounterValue in the first iteration of the loop
        ' Note that this value is lost if the counter does not require two
        ' values to compute a displayable value.
        Status = PdhCollectQueryData(Query)
        If Status IsNot ERROR_SUCCESS Then
            wprintf(LvbLf & "PdhCollectQueryData failed with 0x%x." & vbLf, Status)
            GoTo Cleanup
        End If

        'Print counter values until a key is pressed.
        Do While Not _kbhit()

            Sleep(SAMPLE_INTERVAL_MS)
            GetLocalTime(SampleTime)
            Status = PdhCollectQueryData(Query)

            If Status IsNot ERROR_SUCCESS Then
                wprintf(LvbLf & "PdhCollectQueryData failed with status 0x%x.", Status)
            End If

            wprintf(LvbLf & """%2.2d/%2.2d/%4.4d %2.2d:%2.2d:%2.2d.%3.3d""", SampleTime.wMonth, SampleTime.wDay, SampleTime.wYear, SampleTime.wHour, SampleTime.wMinute, SampleTime.wSecond, SampleTime.wMilliseconds)

            'Compute a displayable value for the counter.
            Status = PdhGetFormattedCounterValue(Counter, PDH_FMT_DOUBLE, CounterType, DisplayValue)
            If Status IsNot ERROR_SUCCESS Then
                wprintf(LvbLf & "PdhGetFormattedCounterValue failed with status 0x%x.", Status)
                GoTo Cleanup
            End If

            Console.Write(",""{0:g20}""", DisplayValue.doubleValue)
        Loop

Cleanup:
        ' Close the query.
        If Query IsNot Nothing Then
            PdhCloseQuery(Query)
        End If
    End Sub
End Class
 
Share this answer
 
v7
Comments
Richard Deeming 13-Dec-17 10:43am    
If you want to update your question, click the green "Improve question" link at the bottom of the question and edit it.

DO NOT post your update as a "solution"!
InfinityJoe 13-Dec-17 11:12am    
Hi Mate, thanks for your advice, i really appreciate it!, i'm quite new on this site, so im sorry if i took a little mistake at some point, and yes will use your advice later on, btw it would be great if you have an solution about my question above, though :)

Cheers
Jaroslav Mitrovic 18-Jan-18 3:24am    
Hi, InfinityJoe.

I have some ideas about it, but I am quiet not sure, never written C++ (admitted only twice).

I found this about the #pragma comment:
"https://books.google.de/books?id=CbwYAAAAQBAJ&pg=PA295&lpg=PA295&dq=pragma+comment+to+vb&source=bl&ots=k3QIlHouHv&sig=USsi9pSYiW_-Ml4piYemv9ETbnQ&hl=de&sa=X&ved=0ahUKEwjVzp_xgOHYAhWKYlAKHfmyCd4Q6AEIMjAB#v=onepage&q=pragma%20comment%20to%20vb&f=false"

So I think you want to use a DLL in your .NET right? In codeproject there are alot of DLL Import Examples.
Not really hard to get it done.
The Problem is the managed vs. unmanaged Dll Imports in VB.NET. There are also Workarounds, but it seems it is not the issue here.

So "#pragma" means shared memory usage is intended...
The "comment" is pointing to the "Sectione/Part" of the DLL which will be used in the Shared memory...

"#pragma" do "THIS" in the Compiler with "comment(lib,"pdh.lib")" so with "THAT PART" 'lib' from 'pdh.lib'

hmmmm... dunno just making a gues.

So I wouldnt think about it because you will use the DLL by setting in the Project in the IDE anyway the Reference? I think that ist only the C++ way to do it.

If you can access the DLL and instatiate something in it or use a Function aof the DLL, you shuld be good to go.

Also these Wprint thingies.

You are right just by examining the code it must be some kind of ".writeline"

wprintf(LvbLf & """%2.2d/%2.2d/%4.4d %2.2d:%2.2d:%2.2d.%3.3d""", SampleTime.wMonth, SampleTime.wDay, SampleTime.wYear, SampleTime.wHour, SampleTime.wMinute, SampleTime.wSecond, SampleTime.wMilliseconds)


Console.Write(",""{0:g20}""", DisplayValue.doubleValue)

You know this right?
Debug.WriteLine("The begin of my line: {0} {1} some filling Text between the Second Value and the Last Value {2}""", WhateverValue0, WhateverValue1, WhateverValue2)

Debug.Write("My Cpu Result: {0:g20}" , MyCpuResult.Value}
Is just the Value in special Formatting, and it seems C++ is doing it in a "I am very special and Unreadable" way. lol

For that it would be the best to use a DateTime.
Use the "SampleTime" and somehow convert it.
If needed make a Converting-Function from "SampleTime" To Sample-DateTime.

From Microsoft:


Dim dateString, format As String
Dim result As Date
Dim provider As CultureInfo = CultureInfo.InvariantCulture

' Parse date-only value with invariant culture.
dateString = "06/15/2008"
format = "d"
Try
result = Date.ParseExact(dateString, format, provider)
Console.WriteLine("{0} converts to {1}.", dateString, result.ToString())
Catch e As FormatException
Console.WriteLine("{0} is not in the correct format.", dateString)
End Try


So just use all the "SampleTime.WhateverValues" and use them to instantiate a DateTime Object.
And if the "SampleTime.wMonth" is of a numeric value you are go to go also. You can pass in Values as Parameters to Instantiate a DateTime.
If the "SampleTime.wMonth" is a String (and the others too) use the ".Parse()" Function of the DateTime Object.

Also consider to use TimeSpans, in the .NET they are really Performate and Optimized to handle TimeRelated Datastructures and do als fast Computation on them.
And the best of it it has the ".ToString()" Method where you can Pass the Output Format in a Short Syntax .("I am very special and less Unreadable then the C++ Stuff over there..."

no real Solution but maybe a hint...

c.u. Zui from Hamburg

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900