CPU Usage Multi-core

Just starting out? Need help? Post your questions and find answers here.
User avatar
doctorized
Addict
Addict
Posts: 882
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: CPU Usage Multi-core

Post by doctorized »

This is my code. Test it please and tell me if it works fine.

Code: Select all

#COUNTERPERF_PROCESSOR = 238
#COUNTERPERF_PERCENTPROCESSORTIME = 6

Global NumCores.w
Global hQuery.l
Structure PDH_FMT_COUNTERVALUE
    CStatus.l; As Long
    ;  case Cardinal of
    ;    0: (longValue: Integer);
    ;    1: (doubleValue: Double);
    ;    2: (largeValue: Int64);
    ;    3: (AnsiStringValue: PChar);
    ;    4: (WideStringValue: PWideChar);
    padding.l; As Long
    ulValueLow.l; As Long
    ulValueHigh.l; As Long
EndStructure

Global Dim cpuCounters.l(1)
Global Dim dCPU.d(1)

#PDH_CSTATUS_VALID_DATA = 0
#PDH_CSTATUS_NEW_DATA = 1

Declare.s GetCPUCounter(strInstance.s)

Procedure Close_CPU_Usage()
    PdhCloseQuery_(hQuery) ; close cpu usage
EndProcedure

Procedure.l InitializeCPU()
    pdhStatus.l: SysInfo.SYSTEM_INFO: CPU_Obj.s
    hCounter.l: i.l
    ; get # of cpus
    GetSystemInfo_(@SysInfo)
    NumCores = SysInfo\dwNumberOfProcessors - 1
    ReDim dCPU.d(NumCores)
    ReDim cpuCounters.l(NumCores)
    
    pdhStatus = PdhOpenQuery_(0, 1, @hQuery)
    If pdhStatus = 0
        For i = 0 To NumCores
            CPU_Obj = GetCPUCounter(Trim(Str(i)))
            If PdhValidatePath_(CPU_Obj) <> #ERROR_SUCCESS
            	MessageRequester("Error","Unable To initialize CPU usage.")
            EndIf
            pdhStatus = PdhAddCounter_(hQuery, CPU_Obj, 0, @hCounter)
            If pdhStatus = #PDH_CSTATUS_VALID_DATA: cpuCounters(i) = hCounter: EndIf
        Next i
        
        If hCounter <> 0 
            ProcedureReturn 1
        EndIf
    EndIf

    MessageRequester("Error","Unable To initialize CPU usage.")

EndProcedure

Procedure Update_Cpu_Usage()
    ; get usage per core
    hIcon.l: pdhStatus.l
    i.l
    lpValue.PDH_FMT_COUNTERVALUE
    PdhCollectQueryData_(hQuery)
    For i = 0 To NumCores
        PdhGetFormattedCounterValue_(cpuCounters(i), $200, @dwType.l, @lpValue)
        CopyMemory(@lpValue\ulValueLow, @dCPU(i),8)
    Next

EndProcedure

Procedure.s GetCPUCounter(strInstance.s)
    ; get Object & Counter names for CPU Usage
    ; Different languages of windows use different names so we use a look-up!
	If OpenLibrary(0, "pdh.dll")  
		*F = GetFunction(0, "PdhLookupPerfNameByIndexA")
		If *F
			 NameLen.l: ObjectName.s: CounterName.s
		    
		    NameLen = #MAX_PATH
		    ObjectName = Space(NameLen)
		    i = CallFunctionFast(*F,#Null, #COUNTERPERF_PROCESSOR, @ObjectName, @NameLen)
       
		    NameLen = #MAX_PATH
		    CounterName = Space(NameLen)
		    
		    i = CallFunctionFast(*F,#Null, #COUNTERPERF_PERCENTPROCESSORTIME, @CounterName, @NameLen)
		    Debug "\" + ObjectName + "(" + strInstance + ")\" + CounterName
		    ProcedureReturn "\" + ObjectName + "(" + strInstance + ")\" + CounterName
		EndIf
		CloseLibrary(0)
	EndIf
EndProcedure



initializecpu()
For i=1 To 40
	update_cpu_usage()
	For ii=0 To NumCores
		tmp.s + "Core #" + Str(ii) + " usage = " + Str(dCPU(ii)) + "%     "
	Next
	Debug tmp
	tmp=""
	Delay(1000)
Next
close_cpu_usage()
jack
Addict
Addict
Posts: 1358
Joined: Fri Apr 25, 2003 11:10 pm

Re: CPU Usage Multi-core

Post by jack »

works OK on my vitual machine, windows 7x32
User avatar
GG
Enthusiast
Enthusiast
Posts: 266
Joined: Tue Jul 26, 2005 12:02 pm
Location: Lieusaint (77), France

Re: CPU Usage Multi-core

Post by GG »

Looks perfect for me, 2 cores detected, and CPU % for each one well performed. :)
Purebasic 6.12 64 bits - Windows 11 Pro 64 bits 23H2
User avatar
doctorized
Addict
Addict
Posts: 882
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: CPU Usage Multi-core

Post by doctorized »

Visit the website of my signature to find a graphical way of my code. It looks like the Windows' way in task manager.
The code is writen in PB 4.31 but works fine with 4.61.
User avatar
electrochrisso
Addict
Addict
Posts: 989
Joined: Mon May 14, 2007 2:13 am
Location: Darling River

Re: CPU Usage Multi-core

Post by electrochrisso »

Works fine on my Atom quad core N550, I can use this, thanks Doc. :)
PureBasic! Purely the best 8)
User avatar
Michael Vogel
Addict
Addict
Posts: 2806
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: CPU Usage Multi-core

Post by Michael Vogel »

Didn't find the correct structure for the return values when using query functions of the PDH library. The following code works fine for 64 bit machines, but it does not work when using the x86 compiler. (It does not show the values for each core but only the total CPU load)

The problem should be somewhere in the structure of PdhCounterType and as a result the line If \Buffer\Error=#Null fails. Does anyone know how to change the structure for working in both modes, 32 and 64 bits?

Changing the structure to something like below does work but I'd be more happy if someone could double check if this is valid.
  • Structure PdhCounterType
    Code.l; +0
    Error.i; +4
    CompilerIf #PB_Compiler_Processor = #PB_Processor_x86 : Dummy.l : CompilerEndIf
    Value.d; +12
    EndStructure

Code: Select all

; Define

	Prototype.l ProtoOpenQuery(Para1.l, Para2.l, Para3.i)
	Prototype.l ProtoCloseQuery(Para1.l)
	Prototype.l ProtoCollectData(Para1.l)
	Prototype.d ProtoPerformance(Para1.l, Para2.l, Para3.l, Para4.i)
	Prototype.l ProtoAddCounter(Para1.l, Para2.l, Para3.l, Para4.i)

	Structure PdhCounterType
		Code.l;			+0
		Error.q;			+4
		Value.d;		+12
	EndStructure

	Structure CpuLoadType
		QueryActive.i
		HandleQuery.l
		Buffer.PdhCounterType
		OpenQuery.ProtoOpenQuery
		AddCounter.ProtoAddCounter
		CollectData.ProtoCollectData
		Performance.ProtoPerformance
		CloseQuery.ProtoCloseQuery
	EndStructure

	Global CpuLoad.CpuLoadType

; EndDefine

Procedure GarbageCollection()

	Protected lib,fnc

	lib=OpenLibrary(#PB_Any,"Psapi.dll")
	If lib
		fnc=GetFunction(lib,"EmptyWorkingSet")
		If fnc
			CallFunctionFast(fnc,GetCurrentProcess_())
		EndIf
		CloseLibrary(lib)
	EndIf

EndProcedure

Procedure InitCpuLoad()

	#PDH_FMT_DOUBLE=512

	Protected CounterDefinition.s

	With CpuLoad

		\QueryActive=#Null

		If OpenLibrary(0,"PDH.DLL")

			\OpenQuery.ProtoOpenQuery=	GetFunction(0, "PdhOpenQuery")
			\CloseQuery.ProtoCloseQuery=	GetFunction(0, "PdhCloseQuery")
			\CollectData.ProtoCollectData=	GetFunction(0, "PdhCollectQueryData")
			\AddCounter.ProtoAddCounter=	GetFunction(0, "PdhAddEnglishCounterW");	
			\Performance.ProtoPerformance=GetFunction(0, "PdhGetFormattedCounterValue")

			If \OpenQuery(0,1,@\HandleQuery)=#Null
				CounterDefinition="\Processor(_Total)\% Processor Time"
				If \AddCounter(\HandleQuery,@CounterDefinition,1,\Buffer)=#Null
					\QueryActive=#True
				EndIf
			EndIf
		EndIf

		ProcedureReturn \QueryActive

	EndWith

EndProcedure
Procedure ShowCpuLoad()

	With CpuLoad

		\CollectData(\HandleQuery)
		\Performance(\Buffer\Code, #PDH_FMT_DOUBLE, 0,@\Buffer\Error)
		If \Buffer\Error=#Null
			Debug StrD(\Buffer\Value,1)+"%"
		EndIf
	EndWith

EndProcedure
Procedure StopCpuLoad()

	With CpuLoad
		If \QueryActive
			\CloseQuery(\HandleQuery)
			CloseLibrary(0)
		EndIf
	EndWith

EndProcedure

If InitCpuLoad()

	GarbageCollection()

	For i=0 To 10
		ShowCpuLoad()

		Delay(1000)
	Next i
	StopCpuLoad()
EndIf
Fred
Administrator
Administrator
Posts: 18199
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: CPU Usage Multi-core

Post by Fred »

What you need is 'Structure PdhCounterType Align #PB_Structure_AlignC' to handle these alignment padding automatically
Post Reply