One way is read-out model specific registers (MSR) of a multi-core-cpu. Problem: You need installed ring0-drivers (Windows). I use the WinRing0.dll/sys (like e.g. RealTemp). For my Intel i7-2600 (Sandy Bridge) and an 64-Bit-Windows-OS I wrote a test-program with this results:
This is the code; notice: It is for a Sandy Bridge and 64-Bit-Windows and was only for a test!
Code: Select all
;- Infos about Intel Sandy Bridge (my i7-2600)
;- Using the WinRing0-Dll (64-Bit). Copyright (c) 2007-2009 OpenLibSys.org. All rights reserved.
;- "Helle" Klaus Helbing, 29.05.2011, PB 4.51 (x64)
Stepping.l ;Bit 0-3
Model.l ;Bit 4-7
Family.l ;Bit 8-11
Extended_Model.l ;Bit 16-19
Extended_Family.l ;Bit 20-27
HT.l
HTAV.l
AnzCore.l
Cores.l
Hi.l
Lo.l
HiLo1.q
HiLo2.q
HiLo3.q
Usage.d
UsageSum.d
CoreTemp.l
Tj.l = 100 ;100°C for Sandy Bridge
En$ = "Enabled"
Dis$ = "Disabled"
CPUName.q = AllocateMemory(64) ;48 Characters + Zero-Byte (or only 49)
#PROCESSOR_ARCHITECTURE_AMD64 = $9
#IA32_TIME_STAMP_COUNTER = $10
#IA32_PLATFORM_ID = $17
#UnHalted_Core_Cycles = $3C
#IA32_PMC_0 = $C1
#MSR_PLATFORM_INFO = $CE
#IA32_MPERF = $E7
#IA32_APERF = $E8
#IA32_PERFEVTSEL0 = $186
#MSR_PERF_STATUS = $198
#MSR_IA32_THERM_STATUS = $19C
#IA32_MISC_ENABLE = $1A0
#MSR_TURBO_RATIO_LIMIT = $1AD
#IA32_PERF_GLOBAL_CTRL = $38F
#MSR_RAPL_POWER_UNIT = $606
#MSR_PKG_ENERGY_STATUS = $611
#MSR_PP0_ENERGY_STATUS = $639
#Bit0 = $1
#Bit16 = $10000
#Bit17 = $20000
#Bit22 = $400000
#Bit28 = $10000000
#Bit29 = $20000000
#Bit38 = $40 ;only High-DWord!
SI.SYSTEM_INFO ;Structure System_Info
GetSystemInfo_(@SI)
If SI\wProcessorArchitecture <> #PROCESSOR_ARCHITECTURE_AMD64
MessageRequester("Error !", "This is not a 64-Bit-OS !´")
End
EndIf
!PUSH rbx ;for 64-Bit-OS, for 32-Bit use ebx etc. Or Procedure
!XOR eax,eax
!CPUID
!CMP eax,0Dh ;max.Value
!JNE NoSB
!CMP ecx,6C65746Eh ;"letn", Part of Intel-String
!JNE NoSB
!MOV eax,1
!CPUID
!MOV edx,eax
!AND edx,1111b
!MOV [v_Stepping],edx
!MOV edx,eax
!SHR edx,8
!AND edx,1111b
!MOV [v_Family],edx
!CMP edx,6
!JNE NoSB
!MOV [v_Extended_Family],edx
!MOV edx,eax
!SHR edx,4
!AND edx,1111b
!MOV [v_Model],edx
!MOV ecx,eax
!SHR ecx,16
!AND ecx,1111b
!SHL ecx,4
!ADD edx,ecx
!CMP edx,2Ah
!JNE NoSB
!MOV [v_Extended_Model],edx
!XOR ecx,ecx
!MOV eax,0Bh
!CPUID
!MOV [v_HT],ebx
!MOV ecx,1
!MOV eax,0Bh
!CPUID
!MOV [v_Cores],ebx
j = 1
hThread = GetCurrentThread_()
OldThreadAffinityMask = SetThreadAffinityMask_(hThread, j)
While SetThreadAffinityMask_(hThread, j)
AnzCore + 1
!MOV eax,1
!CPUID
!SHR ebx,24 ;Initial APIC ID. Bit24: 0=phys., 1=log.Core. Bit 25-31: "Basic"-Core
!AND ebx,0FFh
!TEST ebx,1
!JNZ @f
CoreSequence$ + "P"
!JMP NextCore
!@@:
CoreSequence$ + "L"
HTAV + 1
!NextCore:
j << 1
Wend
SetThreadAffinityMask_(hThread, OldThreadAffinityMask) ;restore
If HTAV
HTAV$ = "Yes"
Else
HTAV$ = "No"
EndIf
;read CPU-String
!PUSH rdi
!PUSH rsi
!MOV rsi,[v_CPUName]
!XOR rdi,rdi
!@@:
!MOV eax,80000002h
!ADD eax,edi
!CPUID
!MOV [rsi],eax
!MOV [rsi+4],ebx
!MOV [rsi+8],ecx
!MOV [rsi+12],edx
!INC rdi
!CMP rdi,3
!JE @f
!ADD rsi,16
!JMP @b
!@@:
!POP rsi
!POP rdi
!JMP @f
!NoSB:
!POP rbx
MessageRequester("Error !", "This CPU is not an Intel ´Sandy Bridge´ !")
End
!@@:
!POP rbx
If OpenLibrary(0, "WinRing0x64.dll") = 0 ;load the 64-Bit-Version
MessageRequester("Error !", "Could not load WinRing0x64.dll !")
End
EndIf
Global Dim IA32_PERF_GLOBAL_CTRL_HI.l(AnzCore - 1)
Global Dim IA32_PERF_GLOBAL_CTRL_LO.l(AnzCore - 1)
Global Dim IA32_TIME_STAMP_COUNTER.q(AnzCore - 1)
If OpenWindow(0, 0, 0, 325, 385 + AnzCore * 15 * 3, "Helles CPU-Infos Sandy Bridge", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_MinimizeGadget)
Prototype.q ProtoWinRing0_0()
WR0_InitializeOls.ProtoWinRing0_0 = GetFunction(0, "InitializeOls")
WR0_DeinitializeOls.ProtoWinRing0_0 = GetFunction(0, "DeinitializeOls")
WR0_IsMsr.ProtoWinRing0_0 = GetFunction(0, "IsMsr")
Prototype.q ProtoWinRing0_3(V1l.l, V2l.l, V3l.l)
WR0_Rdmsr.ProtoWinRing0_3 = GetFunction(0, "Rdmsr")
Prototype.q ProtoWinRing0_4(V1l.l, V2l.l, V3l.l, V4l.l)
WR0_RdmsrTx.ProtoWinRing0_4 = GetFunction(0, "RdmsrTx")
WR0_WrmsrTx.ProtoWinRing0_4 = GetFunction(0, "WrmsrTx")
TextGadget(1, 10, 5, 60, 15, "CPU-Name :")
TextGadget(2, 70, 5, 245, 15, LTrim(PeekS(CPUName, -1, #PB_Ascii)), #PB_Text_Right)
TextGadget(3, 10, 20, 60, 15, "Stepping :")
TextGadget(4, 250, 20, 65, 15, "$" + Hex(Stepping), #PB_Text_Right)
TextGadget(5, 10, 35, 60, 15, "Model :")
TextGadget(6, 250, 35, 65, 15, "$" + Hex(Model), #PB_Text_Right)
TextGadget(7, 10, 50, 90, 15, "Extended Model :")
TextGadget(8, 250, 50, 65, 15, "$" + Hex(Extended_Model), #PB_Text_Right)
TextGadget(9, 10, 65, 60, 15, "Family :")
TextGadget(10, 250, 65, 65, 15, "$" + Hex(Family), #PB_Text_Right)
TextGadget(11, 10, 80, 90, 15, "Extended Family :")
TextGadget(12, 250, 80, 65, 15, "$" + Hex(Extended_Family), #PB_Text_Right)
If WR0_InitializeOls() And WR0_IsMsr()
WR0_Rdmsr(#IA32_PLATFORM_ID, @Lo, @Hi)
PlatformID = (Hi >> 18) & %111 ;Bits 50-52
TextGadget(13, 10, 95, 220, 15, "PlatformID :")
TextGadget(14, 240, 95, 75, 15, "$" + Hex(PlatformID), #PB_Text_Right)
If HT >= 2
HT$ = "Yes"
Else
HT$ = "No"
EndIf
TextGadget(120, 10, 110, 170, 15, "Hyper Threading (CPU/Available) :")
TextGadget(121, 240, 110, 75, 15, HT$ + "/" + HTAV$, #PB_Text_Right)
TextGadget(122, 10, 125, 220, 15, "Number of Cores (CPU/Available) :")
TextGadget(123, 240, 125, 75, 15, Str(Cores) + "/" + Str(AnzCore), #PB_Text_Right)
TextGadget(124, 10, 140, 230, 15, "Core-Sequence (0-" + Str(AnzCore - 1) + ", P=Physical, L=Logical) :")
TextGadget(125, 240, 140, 75, 15, CoreSequence$, #PB_Text_Right)
WR0_Rdmsr(#MSR_PLATFORM_INFO, @Lo, @Hi)
BaseRatio = (Lo >> 8) & $FF
TextGadget(15, 10, 155, 150, 15, "Maximum Non-Turbo Ratio :")
TextGadget(16, 170, 155, 145, 15, Str(BaseRatio) + " (=" + Str(BaseRatio * 100) + " MHz)", #PB_Text_Right)
MinRatio = (Hi >> 8) & $FF
TextGadget(17, 10, 170, 100, 15, "Minimum Ratio :")
TextGadget(18, 170, 170, 145, 15, Str(MinRatio) + " (=" + Str(MinRatio * 100) + " MHz)", #PB_Text_Right)
RatioLimit = Lo & #Bit28
If RatioLimit
RatioLimit$ = En$
Else
RatioLimit$ = Dis$
EndIf
TextGadget(19, 10, 185, 220, 15, "Programmable Ratio Limit for Turbo Mode :")
TextGadget(20, 240, 185, 75, 15, RatioLimit$, #PB_Text_Right)
TDPLimit = Lo & #Bit29
If TDPLimit
TDPLimit$ = En$
Else
TDPLimit$ = Dis$
EndIf
TextGadget(21, 10, 200, 220, 15, "Programmable TDP Limit for Turbo Mode :")
TextGadget(22, 240, 200, 75, 15, TDPLimit$, #PB_Text_Right)
WR0_Rdmsr(#IA32_MISC_ENABLE, @Lo, @Hi)
SpeedStep = Lo & #Bit16
If SpeedStep
SpeedStep$ = En$
Else
SpeedStep$ = Dis$
EndIf
TextGadget(23, 10, 215, 220, 15, "Enhanced Intel SpeedStep Technology :")
TextGadget(24, 240, 215, 75, 15, SpeedStep$, #PB_Text_Right)
TurboModeDisable = Hi & #Bit38
If TurboModeDisable
TurboMode$ = Dis$
Else
TurboMode$ = En$
EndIf
TextGadget(25, 10, 230, 220, 15, "Turbo Mode :")
TextGadget(26, 240, 230, 75, 15, TurboMode$, #PB_Text_Right)
WR0_Rdmsr(#MSR_TURBO_RATIO_LIMIT, @Lo, @Hi)
Ratio = Lo & $FF
TextGadget(27, 10, 245, 200, 15, "Maximum Turbo-Ratio for 1 Core :")
TextGadget(28, 220, 245, 95, 15, Str(Ratio) + " (=" + Str(Ratio * 100) + " MHz)", #PB_Text_Right)
Ratio = (Lo >> 8) & $FF ;or test for numbers of phys. cores
TextGadget(29, 10, 260, 200, 15, "Maximum Turbo-Ratio for 2 Cores :")
TextGadget(30, 220, 260, 95, 15, Str(Ratio) + " (=" + Str(Ratio * 100) + " MHz)", #PB_Text_Right)
Ratio = (Lo >> 16) & $FF
TextGadget(31, 10, 275, 200, 15, "Maximum Turbo-Ratio for 3 Cores :")
TextGadget(32, 220, 275, 95, 15, Str(Ratio) + " (=" + Str(Ratio * 100) + " MHz)", #PB_Text_Right)
Ratio = (Lo >> 24) & $FF
TextGadget(33, 10, 290, 200, 15, "Maximum Turbo-Ratio for 4 Cores :")
TextGadget(34, 220, 290, 95, 15, Str(Ratio) + " (=" + Str(Ratio * 100) + " MHz)", #PB_Text_Right)
WR0_Rdmsr(#MSR_RAPL_POWER_UNIT, @Lo, @Hi)
PowerUnit = Lo & %1111
EnergyUnit = (Lo >> 8) & %11111
TimeUnit = (Lo >> 16) & %1111
TextGadget(35, 10, 305, 140, 15, "Current Core Voltage (V) :")
TextGadget(36, 220, 305, 95, 15, "", #PB_Text_Right)
TextGadget(39, 10, 320, 230, 15, "Current Power Consumtion compl. CPU (Watts) :")
TextGadget(40, 270, 320, 45, 15, "", #PB_Text_Right)
TextGadget(41, 10, 335, 220, 15, "Current Power Consumtion only Cores (Watts) :")
TextGadget(42, 270, 335, 45, 15, "", #PB_Text_Right)
TextGadget(37, 10, 350, 170, 15, "Current general CPU-Multiplier :")
TextGadget(38, 190, 350, 125, 15, "", #PB_Text_Right)
AMode = #UnHalted_Core_Cycles | #Bit16 | #Bit17 | #Bit22 ;All (User Mode and Operating System Mode)
j = 1
For i = 0 To AnzCore - 1
TextGadget(80 + i, 10, 365 + 15 * i, 280, 15, "Current average (last 0.5s) Frequency CPU-Core" + Str(i) + " (MHz) :")
TextGadget(88 + i, 290, 365 + 15 * i, 25, 15, "", #PB_Text_Right)
TextGadget(43 + i, 10, 365 + 15 * i + AnzCore * 15, 180, 15, "Current Temperature CPU-Core" + Str(i) + " (°C) :")
TextGadget(51 + i, 270, 365 + 15 * i + AnzCore * 15, 45, 15, "", #PB_Text_Right)
WR0_RdmsrTx(#IA32_PERF_GLOBAL_CTRL, @Lo, @Hi, j)
IA32_PERF_GLOBAL_CTRL_HI(i) = Hi ;save
IA32_PERF_GLOBAL_CTRL_LO(i) = Lo
Lo = Lo | #Bit0 ;activate Counter0
WR0_WrmsrTx(#IA32_PERF_GLOBAL_CTRL, Lo, Hi, j)
TextGadget(100 + i, 10, 365 + 15 * i + AnzCore * 15 * 2, 180, 15, "Current CPU-Usage Core" + Str(i) + " (%) :")
TextGadget(108 + i, 270, 365 + 15 * i + AnzCore * 15 * 2, 45, 15, "", #PB_Text_Right)
;definierte Werte für Core-Frequenzen usw.
WR0_WrmsrTx(#IA32_MPERF, 0, 0, j) ;set to Zero
WR0_WrmsrTx(#IA32_APERF, 0, 0, j)
WR0_WrmsrTx(#IA32_PERFEVTSEL0, AMode, 0, j)
WR0_WrmsrTx(#IA32_PMC_0, 0, 0, j)
j << 1
Next
TextGadget(116, 10, 365 + 15 * i + AnzCore * 15 * 2, 230, 15, "Current CPU-Usage average all Cores" + " (%) :")
TextGadget(117, 270, 365 + 15 * i + AnzCore * 15 * 2, 45, 15, "", #PB_Text_Right)
;definierte Werte für EnergyOldCPU und EnergyOldCore erhalten
WR0_Rdmsr(#MSR_PKG_ENERGY_STATUS, @Lo, @Hi)
EnergyOldCPU = Lo
WR0_Rdmsr(#MSR_PP0_ENERGY_STATUS, @Lo, @Hi)
EnergyOldCore = Lo
EnergyCoreOld = -1 ;<> 0; Kosmetik
AddWindowTimer(0, 0, 500) ;Achtung: Timer-Wert geht bei Energie mit ein!
Repeat
If Event = #PB_Event_Timer And EventTimer() = 0 ;Aktualisierung und Anzeige ca. alle 0.5 Sekunden
WR0_Rdmsr(#MSR_PERF_STATUS, @Lo, @Hi)
CoreVoltage = Hi & $FFFF
If CoreVoltage <> CoreVoltageOld
SetGadgetText(36, StrF(CoreVoltage / 8192, 3))
CoreVoltageOld = CoreVoltage
EndIf
Multi = (Lo >> 8) & $FF
If Multi <> MultiOld
SetGadgetText(38, Str(Multi) + " (=" + Str(Multi * 100) + " MHz)")
MultiOld = Multi
EndIf
WR0_Rdmsr(#MSR_PKG_ENERGY_STATUS, @Lo, @Hi)
Energy = (Lo - EnergyOldCPU) >> (EnergyUnit - 1) ;1=500ms, the Timer-Value. Precision is enough
EnergyOldCPU = Lo
If Energy <> EnergyCPUOld
SetGadgetText(40, StrU(Energy, #PB_Long))
EnergyCPUOld = Energy
EndIf
WR0_Rdmsr(#MSR_PP0_ENERGY_STATUS, @Lo, @Hi)
Energy = (Lo - EnergyOldCore) >> (EnergyUnit - 1) ;1=500ms, the Timer-Value. Precision is enough
EnergyOldCore = Lo
If Energy <> EnergyCoreOld
SetGadgetText(42, StrU(Energy, #PB_Long))
EnergyCoreOld = Energy
EndIf
j = 1
UsageSum = 0
For i = 0 To AnzCore - 1
WR0_RdmsrTx(#MSR_IA32_THERM_STATUS, @Lo, @Hi, j)
CoreTemp = Lo & %11111110000000000000000 ;Bits 16-22
WR0_RdmsrTx(#IA32_MPERF, @Lo, @Hi, j)
WR0_WrmsrTx(#IA32_MPERF, 0, 0, j) ;set to Zero
!mov edx,[v_Hi]
!mov eax,[v_Lo]
!mov dword[v_HiLo1+4],edx
!mov dword[v_HiLo1],eax
WR0_RdmsrTx(#IA32_APERF, @Lo, @Hi, j)
WR0_WrmsrTx(#IA32_APERF, 0, 0, j) ;set to Zero
!mov edx,[v_Hi]
!mov eax,[v_Lo]
!mov dword[v_HiLo2+4],edx
!mov dword[v_HiLo2],eax
SetGadgetText(88 + i, StrF((HiLo2 / HiLo1) * BaseRatio * 100, 0))
SetGadgetText(51 + i, Str(Tj - (CoreTemp >> 16))) ;Tj=100
WR0_RdmsrTx(#IA32_TIME_STAMP_COUNTER, @Lo, @Hi, j)
HiLo2 = IA32_TIME_STAMP_COUNTER(i)
!mov edx,[v_Hi]
!mov eax,[v_Lo]
!mov dword[v_HiLo1+4],edx
!mov dword[v_HiLo1],eax
IA32_TIME_STAMP_COUNTER(i) = HiLo1
WR0_RdmsrTx(#IA32_PMC_0, @Lo, @Hi, j) ;read Core(j)
WR0_WrmsrTx(#IA32_PMC_0, 0, 0, j) ;set to Zero
!mov edx,[v_Hi]
!mov eax,[v_Lo]
!mov dword[v_HiLo3+4],edx
!mov dword[v_HiLo3],eax
Usage = (HiLo3 / (HiLo1 - HiLo2)) * 100 * BaseRatio / Multi
SetGadgetText(108 + i, StrD(Usage, 1))
UsageSum + Usage
j << 1
Next
SetGadgetText(117, StrD(UsageSum / AnzCore, 1))
EndIf
Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
j = 1
For i = 0 To AnzCore - 1
WR0_WrmsrTx(#IA32_PERF_GLOBAL_CTRL, IA32_PERF_GLOBAL_CTRL_LO(i), IA32_PERF_GLOBAL_CTRL_HI(i), j) ;Counter0 set back
j << 1
Next
WR0_DeinitializeOls()
EndIf
EndIf
End