AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Delphi Auslesen von WMI dauert (zu?) lange

Auslesen von WMI dauert (zu?) lange

Ein Thema von Shark99 · begonnen am 11. Mai 2020 · letzter Beitrag vom 12. Mai 2020
Antwort Antwort
Shark99

Registriert seit: 16. Mai 2007
403 Beiträge
 
#1

Auslesen von WMI dauert (zu?) lange

  Alt 11. Mai 2020, 22:08
Ich bin dabei die Startzeit eines alten Delphi 7 Programms zu optimieren. Deshalb bin ich den ganzen Startvorgang akribisch durchgegangen. Während des Starts wird ein separater Thread erzeugt um verschiedene WMI Werte auszulesen. Weil die UI gesperrt ist bis der Thread ein mal durch ist, verzögert sich der Programmstart um bis zu 3 Sekunden. Es ist aber nicht konsistent. Meist wird der Start um 0.5-0.7 Sekunden verzögert, mit Ausreißern nach oben wenn man den Start oft protokolliert.

Um weiter zu testen habe ich einen der WMI-Aufrufe in ein Testprogramm verfrachtet. Dort mache ich einen einzigen WMI Query und messe dabei die Zeit. Es dauert tatsächlich etwa 300ms pro Query. Mit Pech dauert es 3 Sekunden. Bei hunderten von Starts hatte ich sogar einen Fall wo der erste Aufruf 27 Sekunden brauchte (die folgenden wieder 300ms).

Was ist der Grund wieso der Query so lange dauert? Ist der Code fehlerhaft? Einen Integer aus einer lokalen Datenbank auszulesen sollte doch maximal 10ms dauern.

In einem weiteren Test habe ich ohne einen separaten Thread getestet und dabei bemerkt, dass während der Query läuft man das Fenster nicht verschieben kann. Was ist der Grund? Wird der Message Handler angehalten? Kenne mich leider wenig mit WMI aus. Wird hier mit Callbacks gearbeitet?

Beispielprojekt mit kompilierter Exe habe ich angehängt.

Code:
function VarIsNothing(V: OleVariant): Boolean;
begin
  Result :=
    (TVarData(V).VType = varDispatch)
    and
    (TVarData(V).VDispatch = nil);
end;

function WMI_GetCPUPerformanceData:boolean;
const
  wbemFlagReturnImmediately = $00000010;
  wbemFlagForwardOnly = $00000020;

  Query_PerfFormattedData_Counters_ProcessorInformation_Total = 'SELECT * FROM Win32_PerfFormattedData_Counters_ProcessorInformation Where Name="_Total"';
var
  WbemLocator: OLEVariant;
  WMIService: OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject: OLEVariant;
  oEnum: IEnumvariant;
  dValue: LongWord;
  vArray: variant;
  logtime: TDateTime;
begin;
  Result := False;

  logtime := now;

  try
    try
      WbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
      WMIService := WbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');

      FWbemObjectSet := WMIService.ExecQuery(Query_PerfFormattedData_Counters_ProcessorInformation_Total, 'WQL', wbemFlagReturnImmediately and wbemFlagForwardOnly);
      oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumvariant;
      if oEnum.Next(1, FWbemObject, dValue) = 0 then
      begin
        if not VarIsNothing(FWbemObject) then
        begin
          iCPUFrequency := LongWord(FWbemObject.ProcessorFrequency);
          Result := True;
        end;
      end;
    except
      bCPUFrequencyAvailable := False;
    end;
  finally
    FWbemObject := Unassigned;
    sExecutiontime := inttostr(round((now - logtime) * 86400000));
  end;
end;
Angehängte Dateien
Dateityp: rar WMITest_neu.rar (173,5 KB, 8x aufgerufen)

Geändert von Shark99 (11. Mai 2020 um 22:20 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
38.941 Beiträge
 
Delphi 10.4 Sydney
 
#2

AW: Auslesen von WMI dauert (zu?) lange

  Alt 12. Mai 2020, 03:18
Zitat:
Weil die UI gesperrt ist bis der Thread ein mal durch ist
Also ist der Thread komplett umsonst? Weil sowieso gewartet wird.


Schonmal überlegt, dass es vielleicht dauert, bis die Werte berechnet/gezählt sind?

Wobei WMI sowieso nie darauf ausgelegt war schnell zu sein.


PS: SELECT ProcessorFrequency FROM ...

Was erwartest du von dem AND in wbemFlagReturnImmediately and wbemFlagForwardOnly ?

Und was willst du mit der CPU-Geschwindigkeit?
Eventuell gibt es was Besseres, für deinen Anwendungsfall.
GetProcessTimes, MSDN-Library durchsuchenGetSystemTimes, PerformenceCounters usw.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
Delphi-Tage 2005-2014

Geändert von himitsu (12. Mai 2020 um 03:57 Uhr)
  Mit Zitat antworten Zitat
Shark99

Registriert seit: 16. Mai 2007
403 Beiträge
 
#3

AW: Auslesen von WMI dauert (zu?) lange

  Alt 12. Mai 2020, 22:19
Es ist nicht meine App, habe nur den Optimierungsauftrag bekommen. So wie es sehe wurde in alter Version ein TTimer verwendet um mehrere Werte per WMI zu holen, welche dem User angezeigt werden. Hier trat das Problem auf, dass 30-50% jeder Sekunde der Message Queue von dem Query gelockt wird (Callback?). Das Fenster hängt. Deshalb wurde das ganze in einen TThread verschoben. Der Query blockiert aber den Message Queue auch im Thread, nur nicht ganz so schlimm wie in einem TTimer. Der Thread macht ja schon Sinn, weil jede Sekunde die Werte neu ausgelesen werden.

Heute habe ich Tests mit der Powershell gemacht (Get-CimInstance -Class Win32_PerfRawData_Counters_ProcessorInformation). Dort ist auch alles arschlahm. WMI scheint totaler Müll zu sein!

>Was erwartest du von dem AND in wbemFlagReturnImmediately and wbemFlagForwardOnly ?

Ist nicht mein Code. Ich weiß nicht was hier gemacht wird. Laut MS Docs wird so ein Semisynchronous Call erzeugt, der auch schneller sein sollte.

>Und was willst du mit der CPU-Geschwindigkeit?
>Eventuell gibt es was Besseres, für deinen Anwendungsfall.
>GetProcessTimes, MSDN-Library durchsuchenGetSystemTimes, PerformenceCounters usw.

Diese wird erstmals angezeigt. Funktioniert nur richtig wenn der PC nicht übertaktet wird (sonst aber keine andere Möglichkeit den Wert zu bekommen ohne einen sys Treiber).
Dann kann der User noch konditionell Scripte starten wenn die Last gering ist. Deshalb braucht man den Takt, CPU Usage reicht alleine nicht aus.

Geändert von Shark99 (12. Mai 2020 um 22:29 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
38.941 Beiträge
 
Delphi 10.4 Sydney
 
#4

AW: Auslesen von WMI dauert (zu?) lange

  Alt 12. Mai 2020, 22:43
Zitat:
wbemFlagReturnImmediately and wbemFlagForwardOnly
Mathematik:
Delphi-Quellcode:
$0001 and $0008 = 0 // nichts
$0001 or $0008 = $0009 // Beides

Der Takt hat aber keine Aussagekraft darüber, ob verwendbare Rechenzeiten übrig sind.
Die Zeiten können das aber sagen, unabhängig vom CPU-Takt.

Ein niedriger Takt sagt nur aus, dass schon längere Zeit kaum etwas gerechnet wird,
aber es kann auch aussagen, dass die CPU viel zu sehr ausgelastet ist und wegen Übertemperatur in den Schutzmodus versetzt wurde,
oder ...

Bei diesem PC hier ist es sogar so, dass der aktuell nicht auf "Leistung" optimiert ist, sondern auf Energieverbrauch und Lautstärke. (nur wenn längere Zeit voll ausgelastet, wird hochgetaktet).
Also meistens kann man dem Takt garnicht ansehen, ob und wie hoch die Auslastung ist.

Bei den CPU-Zeiten ist es dagegen recht einfach.
* 4 Kerne haben 400% Rechenzeit
* Wenn also in einer Minute alle Zeiten zusammengerechnet nur 2 Minuten ergeben, ist die CPU somit zu mindestens 50% arbeitslos gewesen. (noch mehr arbeitslos, wenn der Takt noch höher werden kann, aber das ist egal)
* CPUZeiten / Messinterval / AnzahlDerKerne * 100 = Auslastung in Prozenz
* (CPUZeitenJetzt - CPUZeitenLetztesInterval) / (ZeitJetzt - ZeitLetzteMessung) / AnzahlDerKerne * 100 = Auslastung in Prozenz

Diese Berechnung hilft aber nur, wenn man multithreaded arbeitet.
Bei Single-Thread könnte man statt der Zeiten aller Kerne nur den Kern mit der meisten Rechenzeit nehmen, bzw. die freien Zeiten des Kerns, auf dem man grade läuft, bzw. besser die Zeiten seines eigenen Threads/Prozesses.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
Delphi-Tage 2005-2014

Geändert von himitsu (12. Mai 2020 um 22:59 Uhr)
  Mit Zitat antworten Zitat
Shark99

Registriert seit: 16. Mai 2007
403 Beiträge
 
#5

AW: Auslesen von WMI dauert (zu?) lange

  Alt 12. Mai 2020, 23:06
Hab heute mehrere Stunden zu dem Thema gegoogelt, weil ich bei dem Projekt von WMI wegkommen wollte. Derzeit bleibe ich bei WMI, weil viele Werte wie z.B. DPCRate aus Win32_PerfFormattedData_Counters_ProcessorInformat ion nicht ohne WMI oder Kerneltreiber zu emitteln sind.

Bei der CPU Frequenz ist alles sehr problematisch. Irgendwelche Takte zu zählen ist genauso ungenau wie die WMI Werte. Meine Kiste ist von 4 auf 4.6 Ghz übertaktet. Die CPU Frequenz wird von CPU-Z und HWInfo64 korrekt als 4,6 GHz unter Last angezeigt, WMI und die Taktzählerei über Performance Counters ergibt 4.0 GHz. Richtige Werte bekommt man nur über einen Kernel Treiber, was CPUZ und HWInfo 64 ja machen.

Wenn eine x86 CPU überhitzt und drosselt geht sie nicht auf Minimaltakt runter (d.h. unter den Nominaltakt, Turbo bleibt natürlich aus), was bei vielen ARM Prozessoren der Fall ist, sondern lässt Takte aus. Es gibt ein hin und her zwischen C-States und Nominaltakt. CPUZ etc zeigen dann aber konstant den Nominaltakt an.

Wenn weniger als 1GHz anliegt hat die CPU entweder nichs zu tun, oder Stromsparprofil ist aktiv. Wenn weniger als 1GHz anliegt und das Delta von TSystem_Performance_Information64.IdleTime in Vergleich zu Systemtime unter 10% liegt kann man sicher davon ausgehen dass die CPU idle ist. Die alleinige Betrachtung der Idletime reicht auf keinem Fall aus, weil sich die Prozentwerte zu Systemtime zwischen 800Mhz und 4GHz nicht ändern. Ein Idle-Wert von 20% bei 800MHz hat ja eine ganz andere Bedeutung wie ein Idle-Wert von 20% bei 4GHz.

Geändert von Shark99 (12. Mai 2020 um 23:24 Uhr)
  Mit Zitat antworten Zitat
Shark99

Registriert seit: 16. Mai 2007
403 Beiträge
 
#6

AW: Auslesen von WMI dauert (zu?) lange

  Alt 12. Mai 2020, 23:12
Zitat:
wbemFlagReturnImmediately and wbemFlagForwardOnly
Mathematik:
Delphi-Quellcode:
$0001 and $0008 = 0 // nichts
$0001 or $0008 = $0009 // Beides
Ich nehme an der Code wurde von Google übernommen z.B von hier

https://stackoverrun.com/de/q/597183

Wahrscheinlich falsch übersetzt aus MS VB Beispielen. Aus wbemFlagReturnImmediately + wbemFlagForwardOnly in VB wurde ein AND in Delphi. p.s. Ändert aber nichts an der Trägheit des Query. Kein Unterschied zwischen $0 und $9.

Geändert von Shark99 (12. Mai 2020 um 23:22 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
38.941 Beiträge
 
Delphi 10.4 Sydney
 
#7

AW: Auslesen von WMI dauert (zu?) lange

  Alt 12. Mai 2020, 23:59
Nja, ein + gibt es auch im Delphi, aber 4 + 4 = 4, was man nur mit dem OR richtig hinbekommt.

Delphi-Quellcode:
loc := TSWbemLocator.Create(nil);
Services := Loc.ConnectServer(...);
Den Teil könnte man auslagern und anstatt es jedes Mal neu zu machen nur einmal am Anfang, aber der Teil braucht hier auch kaum Zeit.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
Delphi-Tage 2005-2014
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:20 Uhr.
Powered by vBulletin® Copyright ©2000 - 2022, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf