Re: Get gpu temperature - Updated July 2011

Share your advanced PureBasic knowledge/code with the community.
User avatar
doctorized
Addict
Addict
Posts: 882
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: Get gpu temperature - Updated July 2011

Post by doctorized »

[Edit] I give you the two nvapi files (x86 and x64 version, June 2011). For more details download it from here.
The code is tested with a GTX 295 for NVIDIA.
Download the latest code from here.

Here is a code to take gpu temperature for all the gpus installed.
NVidia GPU support has been added but not fully tested. In order
to run fine, you need NVAPI lib (blame NVidia for this). Take it from:
http://developer.download.nvidia.com/NV ... ay2010.zip
and put the two libs (nvapi64.lib and nvapi.lib) into C:\ or change the path
in the code.
Tested under Windows XP and 7 x64 with PB 4.41/4.5x x86 and x64.

Code: Select all

;for ATI
Structure AdapterInfo
    iSize.l
    iAdapterIndex.l
    strUDID.c[256];	
    iBusNumber.l
    iDeviceNumber.l
    iFunctionNumber.l
    iVendorID.l
    strAdapterName.c[256];
    strDisplayName.c[256];
    iPresent.l			
    iExist.l
    strDriverPath.c[256];
	 strDriverPathExt.c[256];
    strPNPString.c[256];
    iOSDisplayIndex.l
EndStructure

Structure ADLTemperature
	iSize.l
	iTemperature.l
EndStructure

;for NVidia
Structure sensor
	controller.l
	defaultMinTemp.l
	defaultMaxTemp.l
	currentTemp.l
	target.l
EndStructure

Structure NV_GPU_THERMAL_SETTINGS
	version.l
	count.l
	sensors.sensor[3]
EndStructure 

Import ""
  GetNativeSystemInfo(*info)
EndImport

Procedure IsWin64(); is the OS x64? Needed to import the right nvapi.lib.
  Protected Info.SYSTEM_INFO
  GetNativeSystemInfo(Info)
  If info\wProcessorArchitecture
    ProcedureReturn #True
  EndIf
EndProcedure 

If IsWin64()
	ImportC "c:\nvapi64.lib"
Else
	ImportC "c:\nvapi.lib"
EndIf
NvAPI_Initialize()
NvAPI_EnumPhysicalGPUs(*GpuHandles, *gpus)
NvAPI_GPU_GetFullName(Handle.l, *name.s)
NvAPI_GPU_GetThermalSettings(Handle.l, i.l, *point.NV_GPU_THERMAL_SETTINGS)
EndImport

;some global stuff
Global gpus.l, realgpus.l, Dim GpuHandles.i(64), Dim NVGPUNames.s(64)
Global Dim adapters.AdapterInfo(1), FoundATI.l = #False, FoundNVidia.l = #False

Procedure ATIGPUClockUpdater(Value.i)	; "Value" not used, but necessary
	adlt.ADLTemperature
	ii.l=-1
	Repeat
		ii = -1
		For i=0 To gpus-1
			If PeekS(@adapters(i)\strUDID) <> Space(10)
				ii+1
				If CallCFunction(0,"ADL_Overdrive5_Temperature_Get", adapters(i)\iAdapterIndex,0, @adlt) = 0
					SetGadgetText(ii, Str(adlt\iTemperature /1000) + Chr(176)+"C")
				EndIf
			EndIf
		Next
		Delay(1000)
	ForEver
EndProcedure

Procedure NVidiaGPUClockUpdater(Value.i)	; "Value" not used, but necessary
settings.NV_GPU_THERMAL_SETTINGS
Repeat	
	For i=0 To gpus-1
		settings\version = SizeOf(NV_GPU_THERMAL_SETTINGS) | (1<<16)
		settings\count = 0
		settings\sensors[0]\controller = -1
		settings\sensors[0]\target = 1
		If NvAPI_GPU_GetThermalSettings(GpuHandles(i), 0, @settings) <> 0
			MessageRequester("error","Unable to get thermal settings")
			ProcedureReturn
		EndIf
    far.l = settings\sensors[0]\currentTemp * 1.8 + 32
		SetGadgetText(i, Str(settings\sensors[0]\currentTemp) + Chr(176) + "C  (" + Str(far) + " " + Chr(176) + "F)")
	Next
	Delay(1000)
ForEver
EndProcedure

Procedure ATIGPU()
If CallCFunction(0,"ADL_Main_Control_Create", 1) <> 0 
	MessageRequester("error","Unable to Create Main Control")
	;ProcedureReturn
EndIf
i= CallCFunction(0,"ADL_Adapter_NumberOfAdapters_Get", @gpus) 
If gpus = 0
	MessageRequester("error","Unable to get the number of adapters")
	;ProcedureReturn
EndIf
ReDim adapters.AdapterInfo(gpus)
If CallCFunction(0,"ADL_Adapter_AdapterInfo_Get", @adapters(), SizeOf(AdapterInfo) *gpus) <> 0
	MessageRequester("error","Unable to get adapter's info")
	;ProcedureReturn
Else
;first, check for duplicate entries
	realgpus = gpus
	For i=0 To gpus-1
		For ii=0 To gpus-1
			If i <> ii; we do not need to check every gpu with itself.
				If adapters(i)\iBusNumber = adapters(ii)\iBusNumber And adapters(i)\iDeviceNumber = adapters(ii)\iDeviceNumber And adapters(i)\iFunctionNumber = adapters(ii)\iFunctionNumber And PeekS(@adapters(ii)\strUDID) <> Space(10)
					realgpus -1
					PokeS(@adapters(i)\strUDID,Space(10));we erase the content of strUDID because we need something to stand on to see later which gpus to monitor, and it is something not really usefull to us.
				EndIf
			EndIf
		Next
	Next
	For i=0 To gpus-1
		CallCFunction(0,"ADL_Adapter_Active_Get",adapters(i)\iAdapterIndex,@IsActive.l)
		CallCFunction(0,"ADL_Adapter_ID_Get",adapters(i)\iAdapterIndex,@AdapterID.l)
	Next
EndIf
EndProcedure

Procedure NVidiaGPU()
If NvAPI_Initialize() <>0
	MessageRequester("error","Unable to Initialize NVAPI.")
	ProcedureReturn
EndIf
If NvAPI_EnumPhysicalGPUs(@GpuHandles(0), @gpus) <> 0
	MessageRequester("error","Unable to take number of physical gpus.")
	ProcedureReturn
EndIf
For i=0 To gpus-1
	name.s = Space(64)
	NvAPI_GPU_GetFullName(GpuHandles(i), @name)
	NVGPUNames(i) = name
	NvAPI_EnumPhysicalGPUs(@GpuHandles(0), @dummy.l); this function needs to run again because if not, the program may crash in some cases.
Next
realgpus = gpus
EndProcedure

If OpenLibrary(0,"atiadlxx.dll") = 0
	CloseLibrary(0)
	If OpenLibrary(0,"atiadlxy.dll") = 0
		;no ATI? check NVidia
		If OpenLibrary(0,"nvapi64.dll") = 0; x64 library
			If OpenLibrary(0,"nvapi.dll") = 0; x86 library
				MessageRequester("error","Unable to load API library")
				End
			Else
				FoundNVidia = #True
				NVidiaGPU()
			EndIf
		Else
			FoundNVidia = #True
			NVidiaGPU()
		EndIf
	Else
		FoundATI = #True
		ATIGPU()
	EndIf
Else
	FoundATI = #True
	ATIGPU()
EndIf

If OpenWindow (0, 0, 0, 288, 97, "GPU clock", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered) 
LoadFont(4,"MS Sans Serif",24, #PB_Font_Bold)
If realgpus > 1
	ResizeWindow(0, #PB_Ignore, #PB_Ignore, 280, realgpus * 61)
EndIf

thrd.i
If FoundATI = #True
	tmpi.l=-1
	For i=0 To gpus - 1			      
		If PeekS(@adapters(i)\strUDID) <> Space(10)
			tmpi + 1
			Frame3DGadget(tmpi+10,24,8+tmpi*55,233,50,"GPU # " +Str(tmpi) + "   -   " + PeekS(@adapters(i)\strAdapterName))
			TextGadget(tmpi, 25, 20+tmpi*55, 230, 35, "Please wait", #PB_Text_Center)
			SetGadgetFont(tmpi, FontID(4))
		EndIf
	Next
	thrd = CreateThread(@ATIGPUClockUpdater(),189)
ElseIf FoundNVidia = #True
	For i=0 To gpus - 1			      
			Frame3DGadget(i+10,24,8+i*55,233,50,"GPU # " +Str(i) + "   -   " + NVGPUNames(i))
			TextGadget(i, 25, 20+i*55, 230, 35, "Please wait", #PB_Text_Center)
			SetGadgetFont(i, FontID(4))
	Next
	thrd = CreateThread(@NVidiaGPUClockUpdater(),189)
EndIf

Repeat
		Select WaitWindowEvent()
			Case #PB_Event_CloseWindow
			Break
		EndSelect
ForEver
KillThread(thrd)
If FoundATI = #True
	CallCFunction(0,"ADL_Main_Control_Destroy")
EndIf
EndIf
CloseLibrary(0)
Last edited by doctorized on Mon Jul 11, 2011 9:41 pm, edited 8 times in total.
User avatar
chi
Addict
Addict
Posts: 1087
Joined: Sat May 05, 2007 5:31 pm
Location: Austria

Re: Get gpu temperature

Post by chi »

wow, thx for sharing... might come handy!
Et cetera is my worst enemy
User avatar
doctorized
Addict
Addict
Posts: 882
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: Get gpu temperature

Post by doctorized »

I ran my code and fould that the x86 compilation is not working at all and the x64 is working but shows the temp for the first gpu only (NVIDIA GTX 295 with the latest driver). I downloaded the latest NVAPI but the problem still exists. Is anyone else having the same problem?
User avatar
doctorized
Addict
Addict
Posts: 882
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: Get gpu temperature - Updated August 29th.

Post by doctorized »

I edited the code and works fine with PB x64 but with PB x86 returns "Invalid memory access (write error at address 0)" for line 149 ("name.s = space(64)"). Can somebody please tell me why?

Code: Select all

;for ATI
Structure AdapterInfo
    iSize.l
    iAdapterIndex.l
    strUDID.c[256];	
    iBusNumber.l
    iDeviceNumber.l
    iFunctionNumber.l
    iVendorID.l
    strAdapterName.c[256];
    strDisplayName.c[256];
    iPresent.l			
    iExist.l
    strDriverPath.c[256];
	 strDriverPathExt.c[256];
    strPNPString.c[256];
    iOSDisplayIndex.l
EndStructure

Structure ADLTemperature
	iSize.l
	iTemperature.l
EndStructure

;for NVidia
Structure sensor
	controller.l
	defaultMinTemp.l
	defaultMaxTemp.l
	currentTemp.l
	target.l
EndStructure

Structure NV_GPU_THERMAL_SETTINGS
	version.l
	count.l
	sensors.sensor[3]
EndStructure 

CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
	Import "nvapi64.lib"
CompilerElse
	Import "nvapi.lib"
CompilerEndIf
NvAPI_Initialize()
NvAPI_EnumPhysicalGPUs(*GpuHandles, *gpus)
NvAPI_GPU_GetFullName(Handle.l, *name.s)
NvAPI_GPU_GetThermalSettings(Handle.l, i.l, *point.NV_GPU_THERMAL_SETTINGS)
EndImport

;some global stuff
Global gpus.l, realgpus.l, Dim GpuHandles.i(64), Dim NVGPUNames.s(64)
Global Dim adapters.AdapterInfo(1), FoundATI.l = #False, FoundNVidia.l = #False

Procedure ATIGPUClockUpdater(Value.i)	; "Value" not used, but necessary
	adlt.ADLTemperature
	ii.l=-1
	Repeat
		ii = -1
		For i=0 To gpus-1
			If PeekS(@adapters(i)\strUDID) <> Space(10)
				ii+1
				If CallCFunction(0,"ADL_Overdrive5_Temperature_Get", adapters(i)\iAdapterIndex,0, @adlt) = 0
					far.l=(adlt\iTemperature /1000) * 1.8 + 32
					SetGadgetText(ii, Str(adlt\iTemperature /1000) + Chr(176)+"C  (" + Str(far) + " " + Chr(176) + "F)")
				EndIf
			EndIf
		Next
		Delay(1000)
	ForEver
EndProcedure

Procedure NVidiaGPUClockUpdater(Value.i)	; "Value" not used, but necessary
settings.NV_GPU_THERMAL_SETTINGS
Repeat	
	For i=0 To gpus-1
		settings\version = SizeOf(NV_GPU_THERMAL_SETTINGS) | (1<<16)
		settings\count = 0
		settings\sensors[0]\controller = -1
		settings\sensors[0]\target = 1
		If NvAPI_GPU_GetThermalSettings(GpuHandles(i), 0, @settings) <> 0
			MessageRequester("error","Unable to get thermal settings")
			ProcedureReturn
		EndIf
			far.l = settings\sensors[0]\currentTemp * 1.8 + 32
			SetGadgetText(i, Str(settings\sensors[0]\currentTemp) + Chr(176) + "C  (" + Str(far) + " " + Chr(176) + "F)")
	Next
	Delay(1000)
ForEver
EndProcedure

Procedure ATIGPU()
If CallCFunction(0,"ADL_Main_Control_Create", 1) <> 0 
	MessageRequester("error","Unable to Create Main Control")
	;ProcedureReturn
EndIf
i= CallCFunction(0,"ADL_Adapter_NumberOfAdapters_Get", @gpus) 
If gpus = 0
	MessageRequester("error","Unable to get the number of adapters")
	;ProcedureReturn
EndIf
ReDim adapters.AdapterInfo(gpus)
If CallCFunction(0,"ADL_Adapter_AdapterInfo_Get", @adapters(), SizeOf(AdapterInfo) *gpus) <> 0
	MessageRequester("error","Unable to get adapter's info")
	;ProcedureReturn
Else
;first, check for duplicate entries
	realgpus = gpus
	For i=0 To gpus-1
		For ii=1 To gpus-1
			If adapters(i)\iBusNumber = 0 And PeekS(@adapters(i)\strUDID) <> Space(10); gpu cannot be on bus 0.
				realgpus -1
				PokeS(@adapters(i)\strUDID,Space(10))
			ElseIf i <> ii; we do not need to check every gpu with itself.
				If adapters(i)\iBusNumber = adapters(ii)\iBusNumber And adapters(i)\iDeviceNumber = adapters(ii)\iDeviceNumber And adapters(i)\iFunctionNumber = adapters(ii)\iFunctionNumber And PeekS(@adapters(i)\strUDID) <> Space(10)
					realgpus -1
					PokeS(@adapters(ii)\strUDID,Space(10));we erase the content of strUDID because we need something to stand on to see later which gpus to monitor, and it is something not really usefull to us.
				EndIf
			EndIf
		Next
	Next
	For i=0 To gpus-1
		CallCFunction(0,"ADL_Adapter_Active_Get",adapters(i)\iAdapterIndex,@IsActive.l)
		;Debug "AdapterIndex: " + Str(adapters(i)\iAdapterIndex)
		;Debug "IsActive: " + Str(IsActive)
		;Debug "AdapterName: " + PeekS(@adapters(i)\strAdapterName)
		;Debug "UDID: " + PeekS(@adapters(i)\strUDID)
		;Debug "Present: " + Str(adapters(i)\iPresent)
		;Debug "VendorID: " + Hex(adapters(i)\iVendorID)
		;Debug "BusNumber: " + Str(adapters(i)\iBusNumber)
		;Debug "DeviceNumber: " + Str(adapters(i)\iDeviceNumber)
		;Debug "FunctionNumber: " + Str(adapters(i)\iFunctionNumber)		
		CallCFunction(0,"ADL_Adapter_ID_Get",adapters(i)\iAdapterIndex,@AdapterID.l)
	Next
EndIf
;ProcedureReturn
EndProcedure

Procedure NVidiaGPU()
If NvAPI_Initialize() <> 0
	MessageRequester("error","Unable to Initialize NVAPI.")
	ProcedureReturn
EndIf
If NvAPI_EnumPhysicalGPUs(@GpuHandles(0), @gpus) <> 0
	MessageRequester("error","Unable to take number of physical gpus.")
	ProcedureReturn
EndIf
For i=0 To gpus-1
	name.s = Space(64)
	NvAPI_GPU_GetFullName(GpuHandles(i), @name)
	NVGPUNames(i) = name
	NvAPI_EnumPhysicalGPUs(@GpuHandles(0), @dummy.l); this function needs to run again because if not, the program may crash in some cases.
Next
realgpus = gpus
EndProcedure

If OpenLibrary(0,"atiadlxx.dll") = 0
	CloseLibrary(0)
	If OpenLibrary(0,"atiadlxy.dll") = 0
		;no ATI? check NVidia
		If OpenLibrary(0,"nvapi64.dll") = 0; x64 library
			If OpenLibrary(0,"nvapi.dll") = 0; x86 library
				MessageRequester("error","Unable to load API library")
				End
			Else
				FoundNVidia = #True
				NVidiaGPU()
			EndIf
		Else
			FoundNVidia = #True
			NVidiaGPU()
		EndIf
	Else
		FoundATI = #True
		ATIGPU()
	EndIf
Else
	FoundATI = #True
	ATIGPU()
EndIf

If OpenWindow (0, 0, 0, 288, 97, "GPU Temperature", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered) 
LoadFont(4,"MS Sans Serif",24, #PB_Font_Bold)
If realgpus > 1
	ResizeWindow(0, #PB_Ignore, #PB_Ignore, 280, realgpus * 61)
EndIf
thrd.i
If FoundATI = #True
	tmpi.l=-1
	For i=0 To gpus - 1			      
		If PeekS(@adapters(i)\strUDID) <> Space(10)
			tmpi + 1
			Frame3DGadget(tmpi+10,14,8+tmpi*55,253,50,"GPU # " +Str(tmpi) + "   -   " + PeekS(@adapters(i)\strAdapterName))
			TextGadget(tmpi, 15, 20+tmpi*55, 250, 35, "Please wait", #PB_Text_Center)
			SetGadgetFont(tmpi, FontID(4))
		EndIf
	Next
	thrd = CreateThread(@ATIGPUClockUpdater(),189)
ElseIf FoundNVidia = #True
	For i=0 To gpus - 1			      
			Frame3DGadget(i+10,24,8+i*55,233,50,"GPU # " +Str(i) + "   -   " + NVGPUNames(i))
			TextGadget(i, 25, 20+i*55, 230, 35, "Please wait", #PB_Text_Center)
			SetGadgetFont(i, FontID(4))
	Next
	thrd = CreateThread(@NVidiaGPUClockUpdater(),189)
EndIf

Repeat
		Select WaitWindowEvent()
			Case #PB_Event_CloseWindow
			Break
		EndSelect
ForEver
KillThread(thrd)
If FoundATI = #True
	CallCFunction(0,"ADL_Main_Control_Destroy")
EndIf
EndIf
CloseLibrary(0)
eesau
Enthusiast
Enthusiast
Posts: 589
Joined: Fri Apr 27, 2007 12:38 pm
Location: Finland

Re: Get gpu temperature - Updated August 29th.

Post by eesau »

Code: Select all

If IsWin64()
   ImportC "c:\nvapi64.lib"
Else
   ImportC "c:\nvapi.lib"
EndIf
NvAPI_Initialize()
NvAPI_EnumPhysicalGPUs(*GpuHandles, *gpus)
NvAPI_GPU_GetFullName(Handle.l, *name.s)
NvAPI_GPU_GetThermalSettings(Handle.l, i.l, *point.NV_GPU_THERMAL_SETTINGS)
EndImport
Can Import/ImportC really be used dynamically like this? :shock:
DarkDragon
Addict
Addict
Posts: 2344
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Re: Get gpu temperature - Updated August 29th.

Post by DarkDragon »

eesau wrote:

Code: Select all

If IsWin64()
   ImportC "c:\nvapi64.lib"
Else
   ImportC "c:\nvapi.lib"
EndIf
NvAPI_Initialize()
NvAPI_EnumPhysicalGPUs(*GpuHandles, *gpus)
NvAPI_GPU_GetFullName(Handle.l, *name.s)
NvAPI_GPU_GetThermalSettings(Handle.l, i.l, *point.NV_GPU_THERMAL_SETTINGS)
EndImport
Can Import/ImportC really be used dynamically like this? :shock:
No. You'd need a CompilerIf.
bye,
Daniel
eesau
Enthusiast
Enthusiast
Posts: 589
Joined: Fri Apr 27, 2007 12:38 pm
Location: Finland

Re: Get gpu temperature - Updated August 29th.

Post by eesau »

Yeah, thought so.
Polo
Addict
Addict
Posts: 2422
Joined: Tue May 06, 2003 5:07 pm
Location: UK

Re: Get gpu temperature - Updated August 29th.

Post by Polo »

No CompilerIf for what needs to be achieved either (the program needs to detect if it's running on x86 or x64).
User avatar
doctorized
Addict
Addict
Posts: 882
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: Get gpu temperature - Updated August 29th.

Post by doctorized »

eesau wrote:

Code: Select all

If IsWin64()
   ImportC "c:\nvapi64.lib"
Else
   ImportC "c:\nvapi.lib"
EndIf
NvAPI_Initialize()
NvAPI_EnumPhysicalGPUs(*GpuHandles, *gpus)
NvAPI_GPU_GetFullName(Handle.l, *name.s)
NvAPI_GPU_GetThermalSettings(Handle.l, i.l, *point.NV_GPU_THERMAL_SETTINGS)
EndImport
Can Import/ImportC really be used dynamically like this? :shock:
Take a small look above. I changed it with:

Code: Select all

CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
   Import "nvapi64.lib"
CompilerElse
   Import "nvapi.lib"
CompilerEndIf
and the problem still exists for the x86 version.
The solution was the use of ImportC. For a reason, I cannot remember why, I had changed ImportC to Import and that was the cause of my problem. The code works fine with both x86 and x64 version of PB.
User avatar
doctorized
Addict
Addict
Posts: 882
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: Get gpu temperature - Updated July 2011

Post by doctorized »

Download the latest code from here. It contains the latest NVAPI (June 2011).
DarkDragon
Addict
Addict
Posts: 2344
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Re: Get gpu temperature - Updated August 29th.

Post by DarkDragon »

Polo wrote:No CompilerIf for what needs to be achieved either (the program needs to detect if it's running on x86 or x64).
Sure, because Import would link to both if you'd not use CompilerIf ;-) . You are linking statically, not dynamically ;-) . You need to decide it at the compile time when linking statically.
bye,
Daniel
Post Reply