Freigeben über


Übung 3: Grundlegende Informationen zur Analyse des kritischen Pfads und von Wartevorgängen

Szenarios und Aktivitäten können unerwartet verzögert werden. Beispielsweise kann das Öffnen einer Registerkarte in Microsoft Edge manchmal länger dauern als erwartet.

Eine Aktivität wird als Reihe von (sequenziellen und parallelen) Vorgängen definiert, die von einem Startereignis bis zu einem Endereignis ablaufen. Ein Start-/Endereignispaar in einer Ablaufverfolgung kann als Aktivität betrachtet werden. Der längste Pfad durch diese Reihe von Vorgängen wird als kritischer Pfad bezeichnet. Die Verringerung der Dauer eines Vorgangs im kritischen Pfad wirkt sich direkt auf die Dauer der gesamten Aktivität aus.

Es wird empfohlen, den Prozess und den Thread zu identifizieren, die die Aktivität abgeschlossen haben, und vom Abschlusszeitpunkt aus rückwärts vorzugehen. Analysieren Sie zunächst den Thread, der die Aktivität abgeschlossen hat, um zu ermitteln, womit der Thread die meiste Zeit verbracht hat und in welchem Status: running (Wird ausgeführt), ready (Bereit) oder waiting (Wartet).

Erhebliche Laufzeiten weisen darauf hin, dass die direkte CPU-Nutzung sich auf die Dauer des kritischen Pfads auswirkt. Im Status Bereit verbrachte Zeit deutet darauf hin, dass andere Threads sich auf die Dauer des kritischen Pfads auswirken, indem ein Thread im kritischen Pfad von der Ausführung abgehalten wird. Im Status Wartet verbrachte Zeit deutet darauf hin, dass der aktuelle Thread auf E/A-Vorgänge, Timer oder andere Threads und Prozesse im kritischen Pfad wartet.

Jeder Thread, der zur Bereitschaft des aktuellen Threads beiträgt, ist wahrscheinlich ein weiterer Bestandteil des kritischen Pfads und kann analysiert und für die Dauer des kritischen Pfads berücksichtigt werden.

Alle erforderlichen Informationen werden im Diagramm CPU Usage (Precise) (CPU-Auslastung (präzise)) und in der Tabelle WPA erfasst. Ereignisse zur CPU-Auslastung, die vom Verteiler protokolliert werden, werden Kontextwechseln zugeordnet. Diese Tabelle konzentriert sich auf den eingefügten Thread NewThread. Jede Zeile stellt einen Kontextwechsel dar. Daten werden für die folgende Ereignissequenz gesammelt:

Diagramm: Workflow der Datensammlung

  1. NewThread wird aufgrund eines blockierenden Funktionsaufrufs entfernt.

  2. NewThread wird von einem anderen Thread für die Ausführung vorbereitet.

  3. NewThread wird eingefügt, wodurch ein älterer Thread entfernt wird.

  4. NewThread wird wieder entfernt.

Die folgenden Spalten der Tabelle CPU-Auslastung (präzise) sind relevant:

Column Details
% CPU Usage Die CPU-Auslastung des neuen Threads nach dem Wechsel. Dieser Wert wird als Prozentsatz der gesamten CPU-Zeit für den aktuell sichtbaren Zeitraum angegeben.
Count Die Anzahl der Kontextwechsel, die durch die Zeile dargestellt werden. Für einzelne Zeilen lautet dieser Wert immer 1.
CPU Usage (ms) Die CPU-Auslastung des neuen Threads nach dem Kontextwechsel
NewProcess Der Prozess des neuen Threads
NewThreadId Die Thread-ID des neuen Threads
NewThreadStack Der Stapel des neuen Threads, wenn dieser eingefügt wird. Dieser gibt in der Regel an, weshalb der Thread blockiert wurde oder gewartet hat.
Ready(s) Die Zeit, die der Thread in der Warteschlange „Bereit“ verbracht hat (aufgrund von Vorwegname oder CPU-Mangel)
ReadyingThreadId Die Thread-ID des vorbereitenden Threads
ReadyingProcess Der Besitzerprozess des vorbereitenden Threads
ReadyThreadStack Der Stapel des vorbereitenden Threads
ReadyTime (s) Die Vorbereitungsdauer für den neuen Thread
SwitchInTime(s) Der Zeitpunkt, zu dem der neue Thread eingefügt wurde
Waits (s) Die Dauer, die ein Thread auf eine logische oder physische Ressource gewartet hat. Die Wartezeit endet, wenn NewThreadId durch ReadyingThreadId signalisiert wird.

Schritt 1: Erfassen und Öffnen einer Ablaufverfolgung für Verzögerungsprobleme mit der Benutzeroberfläche

Für diese Übung wird ein Dummyprozess mit einer nicht reagierenden Benutzeroberfläche verwendet. Der Prozess ist eine einfache Windows Forms-Anwendung mit einer Schaltfläche und einem Textfeld. Wenn auf die Schaltfläche geklickt wird, reagiert die Benutzeroberfläche für 20 Sekunden nicht mehr, bis das Textfeld aktualisiert wird. Sie analysieren den kritischen Pfad dieses Vorgangs.

Screenshot: Dialogfeld im UIDelay-Beispiel

  1. Laden Sie UIDelay.exehier herunter.

  2. Starten Sie UIDelay.exe.

  3. Öffnen Sie WPR über das Startmenü.

  4. Ändern Sie die Ablaufverfolgungskonfiguration.

    1. Wählen Sie First Level Triage (Selektierung auf oberster Ebene) und CPU Usage (CPU-Auslastung) aus.

    2. Wählen Sie General (Allgemein) als Leistungsszenario aus.

    3. Wählen Sie Verbose (Ausführlich) als Detailgrad aus.

      Screenshot: WPR-Dialogfeld

  5. Klicken Sie auf Start (Starten).

  6. Klicken Sie in UIDelay.exe auf die Schaltfläche Click (Klicken).

    • Warten Sie, bis im Textfeld „Done!“ angezeigt wird.
  7. Speichern Sie in WPR die Ablaufverfolgung, und öffnen Sie sie mit WPA.

  8. Öffnen Sie das Menü Trace (Ablaufverfolgung), und wählen Sie Configure symbols path (Symbolpfad konfigurieren) aus.

    • Geben Sie den Pfad des Symbolcaches an. Weitere Informationen zu Symbolen finden Sie auf der Seite Symbolunterstützung auf MSDN.
  9. Öffnen Sie das Menü Ablaufverfolgung, und wählen Sie Load symbols (Symbole laden) aus.

Schritt 2: Identifizieren des verzögerten Benutzeroberflächenthreads

Vor der Analyse des kritischen Pfads müssen Sie zunächst die Start- und Endereignisse der Aktivität ermitteln.

  1. Suchen Sie das Diagramm UI Delays (Benutzeroberflächenverzögerungen) im Knoten System Activity (Systemaktivität) von Graph Explorer.

    Screenshot: Benutzeroberfläche von Graph Explorer

  2. Verschieben Sie das Diagramm UI Delays per Drag & Drop auf die Registerkarte „Analysis“ (Analyse).

  3. Suchen Sie den Prozess UIDelay.exe.

    1. Dessen Dauer sollte etwa 20 Sekunden betragen. Das bedeutet, dass es eine Verzögerung von 20 Sekunden im Benutzeroberflächenthread von UIDelay.exe gab.

    2. Den Threadbezeichner für die Benutzeroberfläche finden Sie in der Spalte Thread Id (Thread-ID). In diesem Beispiel lautet dieser 24174. Dieser Wert unterscheidet sich in der Ablaufverfolgung, die Sie auf Ihrem Computer erfasst haben. Notieren Sie sich die Thread-ID.

      Screenshot der Beispieldaten

  4. Wählen Sie das gesamte Zeitintervall von UIDelay.exe aus, klicken Sie mit der rechten Maustaste, und vergrößern Sie es.

    Screenshot: Zoomoption

Sie sollten immer die Bereiche vergrößern, die Sie analysieren möchten. Dadurch werden Sie nicht so sehr von unzusammenhängenden Aktivitäten abgelenkt.

Schritt 3: Analysieren des kritischen Pfads der Benutzeroberflächenverzögerung

Da Sie mit der Thread-ID und den Zeitstempeln nun einen guten Ausgangspunkt haben, können Sie sich den kritischen Pfad der Aktivität näher ansehen, um den Ablauf der Ereignisse nachzuvollziehen, die zu einer 20-sekündigen Verzögerung des Benutzeroberflächenthreads geführt haben.

In diesem Schritt steht NewThreadId für den in Schritt 2 ermittelten Thread (Thread 24174 im Prozess UIDelay.exe).

  1. Fügen Sie das Diagramm CPU-Auslastung (präzise) zur Registerkarte Analyse hinzu, und wenden Sie die Voreinstellung Utilization by Process, Thread (Auslastung nach Prozess und Thread) an.

    Screenshot: Beispieldaten in WPA und Graph Explorer mit Auslastung nach Prozess und Thread

  2. Klicken Sie mit der rechten Maustaste auf die Spaltenüberschriften, und blenden Sie die Spalten NewThreadStack, ReadyThreadStack und CPU Usage (ms) ein.

  3. Entfernen Sie die Spalten Ready (us) [Max] und Waits (us) [Max]. Ihre Ansicht sollte nun folgendermaßen aussehen:

    Screenshot: Beispieldaten in WPA mit vergrößerter Ansicht der CPU-Auslastung nach Prozess und Thread für die Serie namens „UIDelay.exe“

  4. Suchen und erweitern Sie den Prozess UIDelay.exe in der Spalte NewProcess, und sortieren Sie nach Waits (us) [Sum], indem Sie auf die Spaltenüberschrift klicken.

  5. Suchen Sie im Prozess UIDelay.exe nach NewThreadId, und analysieren Sie die im Status „Wird ausgeführt“, „Bereit“ und „Wartet“ verbrachte Zeit.

    • Im folgenden Beispiel erkennen Sie:

      • Der Thread verbraucht 10,025 Sekunden CPU-Zeit.

      • Der Thread wartet 5,159 Sekunden lang.

      • Der Thread befindet sich für vernachlässigbare Zeit (10 ms) im Status „Bereit“.

      Screenshot: Beispieldaten in WPA mit doppelter Linie durch die Skala des neuen Prozesses „UIDelay.exe“

    Hinweis: Sie können die 10-sekündige CPU-Aktivität auch mit der in Schritt 4 von Übung 2 beschriebenen Vorgehensweise analysieren. Verwenden Sie hierzu das Diagramm CPU Usage (sampled) (CPU-Auslastung (aus Stichproben)) und den Prozess UIDelay.exe.

  6. Um zu ermitteln, worauf NewThreadId gewartet hat, erweitern Sie die Gruppe NewThreadId, damit NewThreadStack angezeigt wird.

  7. Erweitern Sie [Root], und ermitteln Sie die Funktionsaufrufe, die zu Wartezeiten führen.

    Screenshot: Beispieltabelle in WPA mit Daten zum Click-Ereignis von UIDelay.exe

In diesem Beispiel wartet der Thread mit der Thread-ID 24174 von UIDelay.exe für 5,073 Sekunden auf zugrunde liegende, blockierende Funktionsaufrufe, wenn die Click-Funktion ausgelöst wird:

  • 5,021 Sekunden sind auf die Vorgänge der Funktion ExecuteWMICall zurückzuführen.

  • 35 Millisekunden sind auf die Vorgänge der Funktion PingServer zurückzuführen.

Schritt 3.1: Untersuchen des Codepfads von ExecuteWMICall

Wenn Sie den Aufrufstapel unter ExecuteWMICall erweitern, können Sie mit einem expliziten Aufruf von Thread.Sleep herausfinden, dass der Benutzeroberflächenthread für fünf Sekunden im Standbymodus war.

Screenshot: Beispieldaten in WPA

Ein solches Verhalten sollte um jeden Preis vermieden werden, da es sich direkt auf die Reaktionsfähigkeit auswirkt. Wenn der Code auf Informationen warten muss, sollte dies asynchron in einem separaten Thread erfolgen, und eine ereignisgesteuerte Methode sollte verwendet werden.

Schritt 3.2: Untersuchen des Codes von PingServer

Wenn Sie den Aufrufstapel unter PingServer erweitern, stellen Sie fest, dass der Benutzeroberflächenthread über E/A-Abhängigkeiten verfügt, da er Pingbefehle über das Netzwerk sendet.

Screenshot: Beispieltabelle in WPA mit erweitertem Knoten „UIDelay.exe“, sodass die Details von „System.ni.dll“ angezeigt werden

Auch wenn es sich um eine kurze Verzögerung (35 ms) handelt, sollte sie in einem Benutzeroberflächenthread vermieden werden. Durchschnittliche Benutzer*innen bemerken jede Benutzeroberflächenverzögerung von über 100 Millisekunden. Dieser Vorgang könnte die insgesamt verstrichene Zeit für die Aktivität auf über 100 Millisekunden erhöhen, wodurch Benutzer*innen einen schlechten Eindruck von der Reaktionsfähigkeit bekommen.

Diese Vorgänge sollten asynchron in einem separaten Thread erfolgen und die Benutzeroberfläche nicht blockieren.