CPU-Auslastung auslesen

Für allgemeine Fragen zur Programmierung mit PureBasic.
Benutzeravatar
Bisonte
Beiträge: 2427
Registriert: 01.04.2007 20:18

Re: CPU-Auslastung auslesen

Beitrag von Bisonte »

texti hat geschrieben:Was muß da alles angepaßt werden, damit es für mehr als 4 Cores läuft? Mein schöner neuer AMD mit 8 Kernen und damit 16 Threads soll ja glänzen :wink:
Eigentlich muss nichts angepasst werden. Es wird die Anzahl der Cores ermittelt während der Laufzeit.
PureBasic 6.04 LTS (Windows x86/x64) | Windows10 Pro x64 | Asus TUF X570 Gaming Plus | R9 5900X | 64GB RAM | GeForce RTX 3080 TI iChill X4 | HAF XF Evo | build by vannicom​​
Benutzeravatar
TheCube
Beiträge: 150
Registriert: 20.07.2010 23:59
Computerausstattung: Risen 3400G 16MB Win10-64Bit
Wohnort: NRW

Re: CPU-Auslastung auslesen

Beitrag von TheCube »

Ich glaube texti meint diese Stelle hier in SBonds Code :

Code: Alles auswählen

 ... 
Core = AllocateMemory(64)        ; für max. 4 Cores, 0-15=Counter, 16-31=PdhStatus, 32-63=dblValue    oder Structure
... 
War auch schon mal darüber gestolpert und habe dann einstweilen einen anderen Code genommen.
texti
Beiträge: 42
Registriert: 13.03.2009 13:24

Re: CPU-Auslastung auslesen

Beitrag von texti »

Genau das meine ich. Der Code erzeugt folgende Ausgabe
Bild
Wie zu sehen ist, werden nur die ersten 4 Kerne ausgelesen.

An TheCube: welchen Code hast du genommen? Der von Helle läuft bei mir nicht. Es gibt immer Initialisierungsfehler.
Nichts wissen macht nichts. Man muß nur wissen, wo es steht, oder wen man fragen kann . . .
Benutzeravatar
TheCube
Beiträge: 150
Registriert: 20.07.2010 23:59
Computerausstattung: Risen 3400G 16MB Win10-64Bit
Wohnort: NRW

Re: CPU-Auslastung auslesen

Beitrag von TheCube »

Welchen Code genau müsste ich erst gucken ... auch schon wieder 1-2 Jährchen her.

Warum probierst du nicht erstmal den AllocateMemory(64) auf wenigstens AllocateMemory(128) zu erhöhen ?
Habe leider nichts da mit mehr als 4 Kernen um es selber zu testen.
Benutzeravatar
RSBasic
Admin
Beiträge: 8022
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Re: CPU-Auslastung auslesen

Beitrag von RSBasic »

TheCube hat geschrieben:Habe leider nichts da mit mehr als 4 Kernen um es selber zu testen.
+1
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Re: CPU-Auslastung auslesen

Beitrag von Helle »

Ja ja, die gute alte PDH.DLL :D ! Nutze ich schon lange nicht mehr, ich zapfe lieber die MSRs der CPU direkt an. Das Problem mit der hier veröffentlichen Inkarnation ist die Sprach-Abhängigkeit; "Prozessor" und "Prozessorzeit" müssen landesspezifisch und als ASCII übergeben werden. Gibt auch andere Möglichkeiten (LookUpTable), bläst das Ganze aber auf. Hier eine simple Version für deutsches OS und rel.neue PB-Version (geht da um die Float-/Double-Rückgabe), mit/ohne Unicode:

Code: Alles auswählen

If OpenLibrary(0, "PDH.DLL")                     ;MS-File in \System32
  SI.SYSTEM_INFO
  #PDH_CSTATUS_NEW_DATA = $1
 
  GetSystemInfo_(@SI)                            ;Anzahl der Cores ermitteln
  AnzCore.l = SI\dwNumberOfProcessors
  Buffer.i = AllocateMemory(8 * AnzCore)
  CoreLast.d
  hQuery.l

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

  P1$ = "Prozessor"                    ;gilt nur für deutsche Version! Sprachabhängig!
  P2$ = "Prozessorzeit"  

  OpenQuery.ProtoOpenQuery = GetFunction(0, "PdhVbOpenQuery")
  CloseQuery.ProtoCloseQuery = GetFunction(0, "PdhCloseQuery")       ;PdhVbCloseQuery z.B. nicht für Server 2003! 
  CollectData.ProtoCollectData = GetFunction(0, "PdhCollectQueryData")
  AddCounter.ProtoAddCounter = GetFunction(0, "PdhVbAddCounter")
  Auslastung.ProtoAuslastung = GetFunction(0, "PdhVbGetDoubleCounterValue")
 
  RetVal = OpenQuery(@hQuery)
  If RetVal
    MessageRequester("Fehler !", "Aufruf von PdhVbOpenQuery fehlgeschlagen!")  ;Error-Message OpenQuery
    End
  EndIf

  Proz$=""
  For i = 0 To AnzCore - 1
    Proz1$ = "\" + P1$ + "(" + Str(i) + ")\" + P2$ + " (%)"
    CompilerIf #PB_Compiler_Unicode
      PokeS(@Proz$, Proz1$, -1, #PB_Ascii)
     CompilerElse
      Proz$ = Proz1$
    CompilerEndIf
    RetVal = AddCounter(hQuery, @Proz$, Buffer + (i << 2))
    If RetVal
      MessageRequester("Fehler !", "Aufruf von PdhVbAddCounter für Core"+ Str(i) + " fehlgeschlagen!")  ;Error-Message AddCounter
      ;End          ;normalerweise Ende
    EndIf
  Next
  
  Repeat
    CollectData(hQuery) 
    Auslastung$ = ""
    For i = 0 To AnzCore - 1
      CoreLast = Auslastung(PeekL(Buffer + (4 * i)), PeekL(Buffer + (4 * AnzCore) + (i << 2)))     ;für neuere PB-Versionen!
      Auslastung$ + "Core" + Str(i) + " = " + StrD(CoreLast, 2) + "%" + Space(4)
      If PeekL(Buffer + (4 * AnzCore) + (i << 2)) > #PDH_CSTATUS_NEW_DATA ;s.o.
        A = -1                                   ;war kein gültiger Wert
        Break
      EndIf     
    Next
    If A <> -1
      Debug Auslastung$
    EndIf
    Delay(1000)
  ForEver
  
  CloseQuery(hQuery)
  CloseLibrary(0)
EndIf
Getestet mit KabyLake und Ryzen unter Win7/64.
Viel Spaß!
Helle
texti
Beiträge: 42
Registriert: 13.03.2009 13:24

Re: CPU-Auslastung auslesen

Beitrag von texti »

@helle: cool, danke, funzt!
du hast was von möglichen alternativen zur "PDH.DLL" geschrieben. wie geht das? hast du vielleicht ein beispiel?
danke und gruß
gorden
Nichts wissen macht nichts. Man muß nur wissen, wo es steht, oder wen man fragen kann . . .
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Re: CPU-Auslastung auslesen

Beitrag von Helle »

Es ist keine DLL-Alternative, sondern ein anderer Lösungs-Ansatz. Mittels WinRing0 (s.div.Beispiele von mir hier im Forum) wird für jeden CPU-Core der Time-Stamp-Counter sowie wieviel Ticks dieser Core im C0-State war ausgelesen. Der Quotient ist die Auslastung. Nachfolgender Code ist nur für AMDs Ryzen (ließ sich dafür schön vereinfachen :) ). Für einen Test werden benötigt: Win-64-Bit, User muß Administrator sein (nicht Rechte, sondern User!), WinRing0x64.dll und WinRing0x64.sys und in Compiler-Optionen muss Temporäre Exe erstellen ausgewählt sein.

Code: Alles auswählen

;Temporäre Exe erstellen unter Compiler-Optionen festlegen!
;WinRing0x64.dll und WinRing0x64.sys müssen in diesem Verzeichnis liegen!
;Nur für AMDs Ryzen! (zur Sicherheit...)
;getestet mit Win7/64

#IA32_TIME_STAMP_COUNTER = $10
#IA32_MPERF_READ_ONLY = $C00000E7

AnzCore.l
HiLo1.q
HiLo2.q
HiLo3.q
HiLo4.q

If OpenLibrary(0, "WinRing0x64.dll") = 0    ;64-Bit-Version
  MessageRequester("Fehler !", "WinRing0x64.dll und WinRing0x64.sys!")
  End
EndIf

SI.SYSTEM_INFO
GetSystemInfo_(@SI)                    ;Anzahl der Cores ermitteln
AnzCore = SI\dwNumberOfProcessors

Dim IA32_TIME_STAMP_COUNTER.q(AnzCore - 1)
Dim IA32_MPERF_READ_ONLY.q(AnzCore - 1)

Prototype.i ProtoWinRing0_0()
  WR0_InitializeOls.ProtoWinRing0_0   = GetFunction(0, "InitializeOls")
  WR0_DeinitializeOls.ProtoWinRing0_0 = GetFunction(0, "DeinitializeOls") ;für ordentliche Naturen hier schon mal aufführen
  WR0_IsMsr.ProtoWinRing0_0           = GetFunction(0, "IsMsr")

Prototype.i ProtoWinRing0_4(V1l.l, V2l.l, V3l.l, V4l.l)
  WR0_RdmsrTx.ProtoWinRing0_4 = GetFunction(0, "RdmsrTx")  

If WR0_InitializeOls() And WR0_IsMsr() ;User-Rechte! Administrator!
  Repeat 
    Auslastung$ = ""
    j = 1                              ;Core-Zuordnung
  
    For i = 0 To AnzCore - 1
      WR0_RdmsrTx(#IA32_TIME_STAMP_COUNTER, @HiLo1, @HiLo1 + 4, j)
        HiLo2 = IA32_TIME_STAMP_COUNTER(i)  ;alter Wert
        IA32_TIME_STAMP_COUNTER(i) = HiLo1  ;neuer Wert

      WR0_RdmsrTx(#IA32_MPERF_READ_ONLY, @HiLo3, @HiLo3 + 4, j)
        HiLo4 = IA32_MPERF_READ_ONLY(i)     ;alter Wert
        IA32_MPERF_READ_ONLY(i) = HiLo3     ;neuer Wert

      Auslastung$ + "Core" + Str(i) + " = " + StrD((HiLo3 - HiLo4) * 100 / (HiLo1 - HiLo2), 2) + "%" + Space(4)
      j << 1
    Next

    Debug Auslastung$
    Delay(1000)
  ForEver
EndIf
Benutzeravatar
TheCube
Beiträge: 150
Registriert: 20.07.2010 23:59
Computerausstattung: Risen 3400G 16MB Win10-64Bit
Wohnort: NRW

Re: CPU-Auslastung auslesen

Beitrag von TheCube »

Interessant, dann hat texti ja jetzt sein Beispiel für eine Alternative zur "PDH.DLL".
Wenn dieser Thread in ein paar Jahren traditionell wieder ausgegraben wird, können es auch
ein paar mehr Ryzen-Leute ausprobieren ... :lol:

Was anderes, bzgl. AllocateMemory der Codes hier von SBond und Helle:
SBond fordert für (max.) 4 Kerne 64 Byte an.
Helle fordert für 4 Kerne (errechnet) nur 32 Byte an.

Wer machts genau richtig ?
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Re: CPU-Auslastung auslesen

Beitrag von Helle »

Ryzen ist nur der AMD-Prozi, mit dem ich es testen konnte (und den texti eben hat). Entscheidend für meinen simplen Code ist das Vorhandensein des nur-lesbaren MPERF-Registers. Das gibt es aber seit mind. Kaveri, also müsste es auch mit früheren AMD-CPUs funktionieren.
Zu den Bytes: Für die Parameter-Übergabe werden pro Core nur 8 (2x4) Bytes benötigt. Ich hatte aber seinerzeit noch 8 Bytes pro Core für den Rückgabewert (Double) vorgesehen. Hier sollten dann (vom Programmierer) die Doubles reinkopiert werden zur weiteren Nutzung im Programm. Die sofortige Debug-Ausgabe war ja nur als Provisorium (Demo) vorgesehen; aber nichts hält länger als...
4 Cores: Ich hatte das Ganze so um 2008 geschrieben, und da waren 4 Cores eben der Gipfel der Glückseligkeit :mrgreen: !
Antworten