Performance bei Zugriff auf WMI-Objekt

  • Hallo Gemeinde,

    derzeit Laufe ich auf ein Performance-Problem, für das ich keine Erklärung habe.

    Hier erstmal der Code.

    Spoiler anzeigen
    [autoit]


    $strSQL = "SELECT * FROM Win32_NTLogEvent WHERE LogFile=""System"" AND SourceName =""Eventlog"" AND EventCode=""6005"""
    $colItems = $objWMIService.ExecQuery($strSQL)
    $strListe=""
    $begin=TimerInit()
    MsgBox(0,"Erster Zugriff auf Collection","Anzahl: " & $colItems.Count & " Zeit: " & TimerDiff($begin))

    $begin=TimerInit()
    For $objItem in $colItems
    MsgBox(0,"For..IN",TimerDiff($begin))
    $begin=TimerInit()
    $strServerStartTime = $objItem.TimeWritten
    MsgBox(0,"TimeWritten",TimerDiff($begin))
    ExitLoop
    Next

    [/autoit]

    Das ExecQuery geht sehr schnell von statten.
    Problematisch wird es beim ersten Zugriff auf $colItems.
    MsgBox(0,"Erster Zugriff auf Collection","Anzahl: " & $colItems.Count
    Der dauert über 100 Sekunden.
    Interessanterweise verlagert sich das Problem in die Zeile
    For $objItem in $colItems
    , wenn man die oben angesprochenen Zeile auskommentiert.

    Hat jemand eine zündende Idee?

    Gruß,
    exbge

    • Offizieller Beitrag

    Ich habe mal mit Sciptomatic folgendes erstellt und die Selct-Anweisung angepasst!

    Spoiler anzeigen
    [autoit]

    ; Erstellt von AutoIt Scriptomatic
    $wbemFlagReturnImmediately=0x10
    $wbemFlagForwardOnly=0x20
    $colItems=""
    $strComputer="localhost"
    $Output=""
    $Output&="Computer: " &$strComputer & @CRLF
    $Output&="==========================================" & @CRLF
    $objWMIService=ObjGet("winmgmts:\\" &$strComputer &"\root\CIMV2")
    $colItems=$objWMIService.ExecQuery("SELECT * FROM Win32_NTLogEvent WHERE LogFile='System' AND SourceName ='Eventlog' AND EventCode='6005'", "WQL");, _
    ;~ $wbemFlagReturnImmediately + $wbemFlagForwardOnly)

    [/autoit] [autoit][/autoit] [autoit]

    $begin=TimerInit()
    MsgBox(0,"Erster Zugriff auf Collection","Anzahl: " & $colItems.Count & " Zeit: " & TimerDiff($begin))

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    If IsObj($colItems) Then
    For $objItem In $colItems
    $Output&="Category: " &$objItem.Category & @CRLF
    $Output&="CategoryString: " &$objItem.CategoryString & @CRLF
    $Output&="ComputerName: " &$objItem.ComputerName & @CRLF
    $strData=$objItem.Data(0)
    $Output&="Data: " &$strData & @CRLF
    $Output&="EventCode: " &$objItem.EventCode & @CRLF
    $Output&="EventIdentifier: " &$objItem.EventIdentifier & @CRLF
    $Output&="EventType: " &$objItem.EventType & @CRLF
    $strInsertionStrings=$objItem.InsertionStrings(0)
    $Output&="InsertionStrings: " &$strInsertionStrings & @CRLF
    $Output&="Logfile: " &$objItem.Logfile & @CRLF
    $Output&="Message: " &$objItem.Message & @CRLF
    $Output&="RecordNumber: " &$objItem.RecordNumber & @CRLF
    $Output&="SourceName: " &$objItem.SourceName & @CRLF
    $Output&="TimeGenerated: " & WMIDateStringToDate($objItem.TimeGenerated) & @CRLF
    $Output&="TimeWritten: " & WMIDateStringToDate($objItem.TimeWritten) & @CRLF
    $Output&="Type: " &$objItem.Type & @CRLF
    $Output&="User: " &$objItem.User & @CRLF
    If Msgbox(1, "WMI-Ausgabe", $Output)=2 then ExitLoop
    $Output=""
    Next
    Else
    Msgbox(0, "WMI-Ausgabe","Keine WMI-Objekte gefunden für Klasse: " & "Win32_NTLogEvent")
    Endif

    [/autoit] [autoit][/autoit] [autoit]

    Func WMIDateStringToDate($dtmDate)
    Return (StringMid($dtmDate, 5, 2) &"/" &StringMid($dtmDate, 7, 2) &"/" &StringLeft($dtmDate, 4) & " " &StringMid($dtmDate, 9, 2) &":" &StringMid($dtmDate, 11, 2) &":" &StringMid($dtmDate,13, 2))
    EndFunc

    [/autoit]

    Bei mir ist die Laufzeit bis zur 1. Anzeige < 1s, Du weißt aber schon das TimeDiff die Zeit in ms zurückgibt!

  • Hallo,

    ich habe mal mein Script umgestellt, dass es den lokalen Rechner abfragt.
    Wie gesagt das ExecQuery ist nicht das Problem. Das geht schnell.

    bernd670
    Von daher ist die Umbennung des Themas auch nicht richtig.
    Außerdem ist mein Zeitgefühl noch relativ ok.
    Ich merke schon den Unterschied zwischen ms und s.
    ;)

    Wie gesagt es hängt am ersten Zugriff auf $colItems.

    [autoit]

    $begin=TimerInit()
    MsgBox(0,"Erster Zugriff auf Collection","Anzahl: " & $colItems.Count & " Zeit: " & TimerDiff($begin))

    [/autoit]


    Bei Abfrage meines lokalen Rechners dauert das ca 10 Sek. (Anzahl 463)
    Bei Abfrage eines entfernten Servers dauer das ca 110 Sek. (Anzahl 90)

    Abgesehen davon, dass auch 10 Sekunden indiskutabel sind wundert es mich doch ziemlich, dass nicht die SQl-Abfrage so lange dauert, sondern der erste Zugriff auf das Resultat.

    Ich habe bei mir jetzt mal das System Eventlog geleert.
    Dauer jetzt <2ms.
    Die Größe von $colItems scheint wohl eine Rolle zu spielen.

    Wie dem auch sei hier mal das ganze Script.

    Spoiler anzeigen
    [autoit]

    #include <GUIConstants.au3>
    #include <GUIListView.au3>
    #include <Process.au3>
    #include <date.au3>

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    #Region ### START Koda GUI section ### Form=m:\personal data\scritps\servercheck\frmservercheck.kxf
    $ServerCheck = GUICreate("ServerCheck", 633, 454, 193, 115)
    $btnCheck = GUICtrlCreateButton("Check", 496, 64, 115, 41, 0)
    $btnCancel = GUICtrlCreateButton("Cancel",496,192,115,41,0)

    [/autoit] [autoit][/autoit] [autoit]

    GUISetState(@SW_SHOW)
    #EndRegion ### END Koda GUI section ###

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    case $btnCheck
    $objWMIService = ObjGet("winmgmts:\\localhost\root\CIMV2")

    [/autoit] [autoit][/autoit] [autoit]

    $begin=TimerInit()
    ;$strSQL = "SELECT * FROM Win32_NTLogEvent WHERE LogFile=""System"" AND SourceName =""Eventlog"" AND EventCode=""6005"""
    $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_NTLogEvent WHERE LogFile='System' AND SourceName ='Eventlog' AND EventCode='6005'", "WQL")
    MsgBox(0,"ExecQuery","Dauer: " & TimerDiff($begin))
    $strListe=""
    $begin=TimerInit()
    $intAnzahl=$colItems.Count
    $ende=TimerDiff($begin)
    MsgBox(0,"Erster Zugriff auf Collection","Anzahl: " & $intAnzahl & " Zeit: " & $ende)

    $begin=TimerInit()
    For $objItem in $colItems
    msgBox(0,"For..IN",TimerDiff($begin))
    $begin=TimerInit()
    $strServerStartTime = $objItem.TimeWritten
    MsgBox(0,"TimeWritten",TimerDiff($begin))
    ExitLoop
    Next
    ;Msgbox (0, "Description: ", $colItems, 2)


    Case $btnCancel
    ExitLoop

    Case $GUI_EVENT_CLOSE
    Exit

    [/autoit] [autoit][/autoit] [autoit]

    EndSwitch
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit]

    Sollte ich eventuell $colItems vorher deklarieren?

    Um ein Problem mit meinem Rechner auszuschließen habe ich das Script einem Kollegen geschickt. Dort ist die Performance auch ähnlich schlecht.

    Hat noch wer eine Idee.

    Gruß.
    exbge

    • Offizieller Beitrag

    Hallo!

    Die Umbenennung ist schon korrekt, in deinem Script sehe ich keine einzigen Zugriff auf ein Array.

    Ich habe mal den Zugriff auf einen entfernen Server getestet und komme auf eine Zeit (beim 1. Zugriff) von 18 sek. bei 68 Einträgen. Alle weiteren Zugriffe liegen zwischen 2 und 4 ms.

  • Hi,

    Zitat

    Original von bernd670
    Hallo!

    Die Umbenennung ist schon korrekt, in deinem Script sehe ich keine einzigen Zugriff auf ein Array.


    Hmm, eventuell stehe ich da jetzt auf dem Schlauch.
    Bitte berichtige mich, wenn ich falsch liege.
    Nach meinem bisherigen Verständnis hat eine ExecQuery-Abfrage eine Collection als Ergebnis. Ist eine Collection nicht in etwa sowas wie ein Array?


    Zitat


    Ich habe mal den Zugriff auf einen entfernen Server getestet und komme auf eine Zeit (beim 1. Zugriff) von 18 sek. bei 68 Einträgen. Alle weiteren Zugriffe liegen zwischen 2 und 4 ms.


    Auch wenn ich jetzt nerve, aber was dauert 18 Sekunden, das ExecQuery oder der erste Zugriff auf das Ergebnis von ExecQuery?

    Mir will nicht in den Sinn, warum so simple Sachen wie eine Count-Property derart viel Zeit in Anspruch nehmen.
    Es wird ja schließlich keine Abfrage mehr gemacht.

    Eventuell gibt es ja einen Workaround für mein Ansinnen.
    ich möchte alle Error-Einträge im System-Eventlog seit dem letzten Reboot haben.


    Viele Grüße,
    exbge

    • Offizieller Beitrag

    Hallo!

    Zitat

    Hmm, eventuell stehe ich da jetzt auf dem Schlauch.
    Bitte berichtige mich, wenn ich falsch liege.
    Nach meinem bisherigen Verständnis hat eine ExecQuery-Abfrage eine Collection als Ergebnis. Ist eine Collection nicht in etwa sowas wie ein Array?


    Eine Collection ist eher mit einem Struct in C oder einem Record in Delphi zu vergleichen.

    Zitat

    Auch wenn ich jetzt nerve, aber was dauert 18 Sekunden, das ExecQuery oder der erste Zugriff auf das Ergebnis von ExecQuery?


    Mit 1. Zugriff meine ich immer den 1. Zugriff auf das Ergebnis!