Getting CPU & core temperatures on Mac

Mac OSX specific forum
User avatar
robertfern
User
User
Posts: 38
Joined: Fri Feb 02, 2018 10:33 pm
Location: New Jersey

Getting CPU & core temperatures on Mac

Post by robertfern »

Here is a console app that will return the CPU & individual core temperatures.
I was able to convert a C program "osx-cpu-temp" from Sébastien Lavoie on GitHub.
https://github.com/lavoiesl/osx-cpu-temp

Code: Select all

; Converted from C source code on
; https://github.com/lavoiesl/osx-cpu-temp/blob/master/smc.c
; https://github.com/acidanthera/VirtualSMC/blob/master/Docs/SMCKeys.txt - list of SMC Keys
; https://alwinesch.github.io/test-xbmc/Leia/kodi-base/d6/d33/struct_s_m_c_key_data__t.html - struct definitions
; Copyright (C) 2006 devnull 
; Portions © RMF Solutions - Robert Fernandez, 2023. also under the GPL
EnableExplicit

#KERNEL_INDEX_SMC = 2
#SMC_KEY_CPU_TEMP = "TC0P" ;"TC4C"
#SMC_CMD_READ_BYTES = 5
#SMC_CMD_READ_KEYINFO = 9
#kIOReturnSuccess = 0

Structure SMCVal_t Align #PB_Structure_AlignC
  key.l
  dataSize.l
  dataType.l
  bytes.b[32]
EndStructure

Structure SMCKeyData_vers_t Align #PB_Structure_AlignC
  major.b
  minor.b
  build.b
  reserved.b[1]  
  release.w
EndStructure

Structure SMCKeyData_pLimitData_t Align #PB_Structure_AlignC
  version.w
  length.w
  cpuPLimit.l
  gpuPLimit.l
  memPLimit.l
EndStructure

Structure SMCKeyData_keyInfo_t Align #PB_Structure_AlignC
  dataSize.l
  dataType.l
  dataAttributes.b
EndStructure

Structure SMCKeyData_t Align #PB_Structure_AlignC
  key.l
  vers.SMCKeyData_vers_t
  pLimitData.SMCKeyData_pLimitData_t
  keyInfo.SMCKeyData_keyInfo_t
  result.b
  status.b
  data8.b
  data32.l
  bytes.b[32]
EndStructure

ImportC "-framework IOKit"
  IOServiceGetMatchingServices(mainPort.i, MatchingDictionary.i, *iterator)
  IOServiceMatching(*name)
  IOIteratorNext(iterator)
  IOObjectRelease(object)
  IOServiceOpen(service, owningTask, type, *connect)
  IOServiceClose(connect)
  IOConnectCallStructMethod(connection, selector, *inputStruct, inputStructCnt, *outputStruct, *outputStructCnt)
EndImport

ImportC ""
  mach_task_self()
EndImport

Define matchingDictionary.i
Define iterator.i, k.l, device.i, connection.i, temperature.f, kern_return_t.i
;Define inputStructure.SMCKeyData_t, outputStructure.SMCKeyData_t ;, val.SMCVal_t
Define structureInputSize.i, structureOutputSize.i

Procedure.l _strtoul(str.s)
  Protected total.l = 0, i.l, size.l
  size = Len(str)
  For i = 0 To size - 1
    total = (total << 8)  + PeekB(@str +  (i * 2))
  Next i
  ProcedureReturn total
EndProcedure

Procedure.s _ultostr(smcval.l)
  Protected strng.s = "????"
  PokeB(@strng, PeekB(@smcval))
  PokeB(@strng +  2,PeekB(@smcval + 1))
  PokeB(@strng +  4,PeekB(@smcval + 2))
  PokeB(@strng +  6,PeekB(@smcval + 3))
  Debug "_ultostr string = " + strng
  ProcedureReturn strng
EndProcedure

Procedure.f get_SMCKey(key.s)
  Protected inputStructure.SMCKeyData_t, outputStructure.SMCKeyData_t, kern_return_t.i
  Shared connection.i, structureInputSize.i, structureOutputSize.i
  inputStructure\key = _strtoul(key)
  inputStructure\data8 = #SMC_CMD_READ_KEYINFO
  Debug Str(inputStructure\key)
  kern_return_t = IOConnectCallStructMethod(connection, #KERNEL_INDEX_SMC, @inputStructure, structureInputSize, @outputStructure, @structureOutputSize)
  If kern_return_t <> #kIOReturnSuccess
    Debug "Error: IOConnectCallStructMethod() = " + Str(kern_return_t)
    PrintN("Error: IOConnectCallStructMethod() = " + Str(kern_return_t))
    End
  EndIf
  inputStructure\keyInfo\dataSize = outputStructure\keyInfo\dataSize ;val\dataSize
  inputStructure\data8 = #SMC_CMD_READ_BYTES
  kern_return_t = IOConnectCallStructMethod(connection, #KERNEL_INDEX_SMC, @inputStructure, structureInputSize, @outputStructure, @structureOutputSize)
  If kern_return_t <> #kIOReturnSuccess
    Debug "Error: IOConnectCallStructMethod() = " + Str(kern_return_t)
    PrintN("Error: IOConnectCallStructMethod() = " + Str(kern_return_t))
    End
  EndIf
  ProcedureReturn (outputStructure\bytes[0] * 256.0 + outputStructure\bytes[1]) / 256.0
EndProcedure

structureInputSize = SizeOf(SMCKeyData_t)
structureOutputSize = SizeOf(SMCKeyData_t)

If OpenConsole()
  matchingDictionary = IOServiceMatching(UTF8("AppleSMC"))
  Debug "SMC = " + Str(matchingDictionary)
  kern_return_t = IOServiceGetMatchingServices(#Null, matchingDictionary, @iterator)
  If kern_return_t <> #kIOReturnSuccess
    Debug "Error: IOServiceGetMatchingServices() = " + Str(kern_return_t)
    PrintN("Error: IOServiceGetMatchingServices() = " + Str(kern_return_t))
    End
  EndIf
  device = IOIteratorNext(iterator)
  IOObjectRelease(iterator)
  If device = 0
    Debug "Error: no SMC found"
    PrintN("Error: no SMC found")
    End
  EndIf
  
  kern_return_t = IOServiceOpen(device, mach_task_self(), 0, @connection)
  If kern_return_t <> #kIOReturnSuccess
    Debug "Error: IOServiceOpen() = " + Str(kern_return_t)
    PrintN("Error: IOServiceOpen() = " + Str(kern_return_t))
    End
  EndIf
  Debug "variable structureInputSize = " + Str(structureInputSize)
  Debug "variable structureOutputSize = " + Str(structureOutputSize)
  Debug "variable SMCKeyData_vers_t = " + Str(SizeOf(SMCKeyData_vers_t))
  Debug "variable SMCKeyData_pLimitData_t = " + Str(SizeOf(SMCKeyData_pLimitData_t))
  Debug "variable SMCKeyData_keyInfo_t = " + Str(SizeOf(SMCKeyData_keyInfo_t))
  temperature = get_SMCKey(#SMC_KEY_CPU_TEMP)
  Debug "CPU temp = " + StrF(temperature,1) + " ºC"
  PrintN("CPU temp = " + StrF(temperature,1) + " ºC")
  ; some Macs the CPU count starts at 0, some at 1. So we check if result is 0.0
  For k = 0 To CountCPUs(#PB_System_ProcessCPUs)
    temperature = get_SMCKey("TC" + Str(k) + "C")
    If temperature > 0.0
      PrintN("CPU core " + Str(k) + " temp = " + StrF(temperature,1) + " ºC")
    EndIf
  Next
  
  kern_return_t = IOServiceClose(connection)
  If kern_return_t <> #kIOReturnSuccess
    Debug "Error: IOServiceClose() = " + Str(kern_return_t)
    PrintN("Error: IOServiceClose() = " + Str(kern_return_t))
    End
  EndIf
  CloseConsole()
EndIf
End
Mac OSX Ventura & Windows 10, PB 6.12
User avatar
robertfern
User
User
Posts: 38
Joined: Fri Feb 02, 2018 10:33 pm
Location: New Jersey

Re: Getting CPU & core temperatures on Mac

Post by robertfern »

Here is a modified version where I added GPU temperature

Code: Select all

; Converted from C source code on
; https://github.com/lavoiesl/osx-cpu-temp/blob/master/smc.c
; https://github.com/acidanthera/VirtualSMC/blob/master/Docs/SMCKeys.txt - list of SMC Keys
; https://alwinesch.github.io/test-xbmc/Leia/kodi-base/d6/d33/struct_s_m_c_key_data__t.html - struct definitions
; © RMF Solutions - Robert Fernandez, 2023
EnableExplicit

#KERNEL_INDEX_SMC = 2
#SMC_KEY_CPU_TEMP = "TC0P" ;"TC4C"
#SMC_CMD_READ_BYTES = 5
#SMC_CMD_READ_KEYINFO = 9
#kIOReturnSuccess = 0

Structure SMCVal_t Align #PB_Structure_AlignC
  key.l
  dataSize.l
  dataType.l
  bytes.b[32]
EndStructure

Structure SMCKeyData_vers_t Align #PB_Structure_AlignC
  major.b
  minor.b
  build.b
  reserved.b[1]  
  release.w
EndStructure

Structure SMCKeyData_pLimitData_t Align #PB_Structure_AlignC
  version.w
  length.w
  cpuPLimit.l
  gpuPLimit.l
  memPLimit.l
EndStructure

Structure SMCKeyData_keyInfo_t Align #PB_Structure_AlignC
  dataSize.l
  dataType.l
  dataAttributes.b
EndStructure

Structure SMCKeyData_t Align #PB_Structure_AlignC
  key.l
  vers.SMCKeyData_vers_t
  pLimitData.SMCKeyData_pLimitData_t
  keyInfo.SMCKeyData_keyInfo_t
  result.b
  status.b
  data8.b
  data32.l
  bytes.b[32]
EndStructure

ImportC "-framework IOKit"
  IOServiceGetMatchingServices(mainPort.i, MatchingDictionary.i, *iterator)
  IOServiceMatching(*name)
  IOIteratorNext(iterator)
  IOObjectRelease(object)
  IOServiceOpen(service, owningTask, type, *connect)
  IOServiceClose(connect)
  IOConnectCallStructMethod(connection, selector, *inputStruct, inputStructCnt, *outputStruct, *outputStructCnt)
EndImport

ImportC ""
  mach_task_self()
EndImport

Define matchingDictionary.i
Define iterator.i, k.l, device.i, connection.i, temperature.f, kern_return_t.i
;Define inputStructure.SMCKeyData_t, outputStructure.SMCKeyData_t ;, val.SMCVal_t
Define structureInputSize.i, structureOutputSize.i

Procedure.l _strtoul(str.s)
  Protected total.l = 0, i.l, size.l
  size = Len(str)
  For i = 0 To size - 1
    total = (total << 8)  + PeekB(@str +  (i * 2))
  Next i
  ProcedureReturn total
EndProcedure

Procedure.s _ultostr(smcval.l)
  Protected strng.s = "????"
  PokeB(@strng, PeekB(@smcval))
  PokeB(@strng +  2,PeekB(@smcval + 1))
  PokeB(@strng +  4,PeekB(@smcval + 2))
  PokeB(@strng +  6,PeekB(@smcval + 3))
  Debug "_ultostr string = " + strng
  ProcedureReturn strng
EndProcedure

Procedure.f get_SMCKey(key.s)
  Protected inputStructure.SMCKeyData_t, outputStructure.SMCKeyData_t, kern_return_t.i
  Shared connection.i, structureInputSize.i, structureOutputSize.i
  inputStructure\key = _strtoul(key)
  inputStructure\data8 = #SMC_CMD_READ_KEYINFO
  Debug Str(inputStructure\key)
  kern_return_t = IOConnectCallStructMethod(connection, #KERNEL_INDEX_SMC, @inputStructure, structureInputSize, @outputStructure, @structureOutputSize)
  If kern_return_t <> #kIOReturnSuccess
    Debug "Error: IOConnectCallStructMethod() = " + Str(kern_return_t)
    PrintN("Error: IOConnectCallStructMethod() = " + Str(kern_return_t))
    End
  EndIf
  inputStructure\keyInfo\dataSize = outputStructure\keyInfo\dataSize ;val\dataSize
  inputStructure\data8 = #SMC_CMD_READ_BYTES
  kern_return_t = IOConnectCallStructMethod(connection, #KERNEL_INDEX_SMC, @inputStructure, structureInputSize, @outputStructure, @structureOutputSize)
  If kern_return_t <> #kIOReturnSuccess
    Debug "Error: IOConnectCallStructMethod() = " + Str(kern_return_t)
    PrintN("Error: IOConnectCallStructMethod() = " + Str(kern_return_t))
    End
  EndIf
  ProcedureReturn (outputStructure\bytes[0] * 256.0 + outputStructure\bytes[1]) / 256.0
EndProcedure

structureInputSize = SizeOf(SMCKeyData_t)
structureOutputSize = SizeOf(SMCKeyData_t)

If OpenConsole()
  matchingDictionary = IOServiceMatching(UTF8("AppleSMC"))
  Debug "SMC = " + Str(matchingDictionary)
  kern_return_t = IOServiceGetMatchingServices(#Null, matchingDictionary, @iterator)
  If kern_return_t <> #kIOReturnSuccess
    Debug "Error: IOServiceGetMatchingServices() = " + Str(kern_return_t)
    PrintN("Error: IOServiceGetMatchingServices() = " + Str(kern_return_t))
    End
  EndIf
  device = IOIteratorNext(iterator)
  IOObjectRelease(iterator)
  If device = 0
    Debug "Error: no SMC found"
    PrintN("Error: no SMC found")
    End
  EndIf
  PrintN("mach_task_self() = " + Str(mach_task_self()))
  kern_return_t = IOServiceOpen(device, mach_task_self(), 0, @connection)
  If kern_return_t <> #kIOReturnSuccess
    Debug "Error: IOServiceOpen() = " + Str(kern_return_t)
    PrintN("Error: IOServiceOpen() = " + Str(kern_return_t))
    End
  EndIf
  Debug "variable structureInputSize = " + Str(structureInputSize)
  Debug "variable structureOutputSize = " + Str(structureOutputSize)
  Debug "variable SMCKeyData_vers_t = " + Str(SizeOf(SMCKeyData_vers_t))
  Debug "variable SMCKeyData_pLimitData_t = " + Str(SizeOf(SMCKeyData_pLimitData_t))
  Debug "variable SMCKeyData_keyInfo_t = " + Str(SizeOf(SMCKeyData_keyInfo_t))
  temperature = get_SMCKey(#SMC_KEY_CPU_TEMP) ; CPU Temperature
  Debug "CPU die temp = " + StrF(temperature,1) + " ºC"
  PrintN("CPU die temp = " + StrF(temperature,1) + " ºC")
  For k = 0 To CountCPUs(#PB_System_ProcessCPUs) ; individual core temperatures
    temperature = get_SMCKey("TC" + Str(k) + "C")
    If temperature > 0.0
      PrintN("CPU core " + Str(k) + " temp = " + StrF(temperature,1) + " ºC")
    EndIf
  Next
  temperature = get_SMCKey("TCGC") ; GPU Temperature
  PrintN("GPU temp = " + StrF(temperature,1) + " ºC")
  kern_return_t = IOServiceClose(connection)
  If kern_return_t <> #kIOReturnSuccess
    Debug "Error: IOServiceClose() = " + Str(kern_return_t)
    PrintN("Error: IOServiceClose() = " + Str(kern_return_t))
    End
  EndIf
  CloseConsole()
EndIf
End
Mac OSX Ventura & Windows 10, PB 6.12
Post Reply