Freigeben über


Verwenden von Streaming mit TraceProcessor

Standardmäßig greift TraceProcessor auf Daten zu, indem sie in den Arbeitsspeicher geladen werden, während die Verarbeitung der Ablaufverfolgung stattfindet. Dieser Pufferansatz ist einfach zu verwenden, kann aber im Hinblick auf die Speicherauslastung teuer sein.

TraceProcessor stellt auch trace.UseStreaming() bereit, das den Zugriff auf mehrere Arten von Ablaufverfolgungsdaten in Streaming-Manier unterstützt (Verarbeitung der Daten direkt beim Einlesen aus der Ablaufverfolgungsdatei, anstatt diese Daten im Arbeitsspeicher zwischenzuspeichern). Beispielsweise kann eine Ablaufverfolgung von Systemaufrufen sehr groß sein, und das Zwischenspeichern der gesamten Liste kann sehr teuer sein.

Zugreifen auf gepufferte Daten

Der folgende Code zeigt den Zugriff auf Syscall-Daten auf normale, gepufferte Weise über trace.UseSyscalls():

using Microsoft.Windows.EventTracing;
using Microsoft.Windows.EventTracing.Processes;
using Microsoft.Windows.EventTracing.Syscalls;
using System;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
        if (args.Length != 1)
        {
            Console.Error.WriteLine("Usage: <trace.etl>");
            return;
        }

        using (ITraceProcessor trace = TraceProcessor.Create(args[0]))
        {
            IPendingResult<ISyscallDataSource> pendingSyscallData = trace.UseSyscalls();

            trace.Process();

            ISyscallDataSource syscallData = pendingSyscallData.Result;

            Dictionary<IProcess, int> syscallsPerCommandLine = new Dictionary<IProcess, int>();

            foreach (ISyscall syscall in syscallData.Syscalls)
            {
                IProcess process = syscall.Thread?.Process;

                if (process == null)
                {
                    continue;
                }

                if (!syscallsPerCommandLine.ContainsKey(process))
                {
                    syscallsPerCommandLine.Add(process, 0);
                }

                ++syscallsPerCommandLine[process];
            }

            Console.WriteLine("Process Command Line: Syscalls Count");

            foreach (IProcess process in syscallsPerCommandLine.Keys)
            {
                Console.WriteLine($"{process.CommandLine}: {syscallsPerCommandLine[process]}");
            }
        }
    }
}

Zugreifen auf Streamingdaten

Bei einer großen Protokollierung von Systemaufrufen kann der Versuch, die Daten der Systemaufrufe im Arbeitsspeicher zu puffern, recht kostspielig sein, oder es ist möglicherweise nicht einmal möglich. Der folgende Code zeigt, wie Sie auf die gleichen Syscall-Daten in Form eines Streams zugreifen, indem Sie `trace.UseSyscalls()` durch `trace.UseStreaming().UseSyscalls()` ersetzen.

using Microsoft.Windows.EventTracing;
using Microsoft.Windows.EventTracing.Processes;
using Microsoft.Windows.EventTracing.Syscalls;
using System;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
        if (args.Length != 1)
        {
            Console.Error.WriteLine("Usage: <trace.etl>");
            return;
        }

        using (ITraceProcessor trace = TraceProcessor.Create(args[0]))
        {
            IPendingResult<IThreadDataSource> pendingThreadData = trace.UseThreads();

            Dictionary<IProcess, int> syscallsPerCommandLine = new Dictionary<IProcess, int>();

            trace.UseStreaming().UseSyscalls(ConsumerSchedule.SecondPass, context =>
            {
                Syscall syscall = context.Data;
                IProcess process = syscall.GetThread(pendingThreadData.Result)?.Process;

                if (process == null)
                {
                    return;
                }

                if (!syscallsPerCommandLine.ContainsKey(process))
                {
                    syscallsPerCommandLine.Add(process, 0);
                }

                ++syscallsPerCommandLine[process];
            });

            trace.Process();

            Console.WriteLine("Process Command Line: Syscalls Count");

            foreach (IProcess process in syscallsPerCommandLine.Keys)
            {
                Console.WriteLine($"{process.CommandLine}: {syscallsPerCommandLine[process]}");
            }
        }
    }
}

Funktionsweise des Streamings

Standardmäßig werden alle Streamingdaten während des ersten Durchlaufs des Protokollierungsvorgangs bereitgestellt, und gepufferte Daten aus anderen Quellen sind nicht verfügbar. Das obige Beispiel zeigt, wie Streaming mit Pufferung kombiniert wird – Threaddaten werden gepuffert, bevor syscall-Daten gestreamt werden. Daher muss die Ablaufverfolgung zweimal gelesen werden – einmal, um gepufferte Threaddaten abzurufen, und ein zweites Mal, um auf Streaming-Syscall-Daten mit den gepufferten Threaddaten zuzugreifen, die jetzt verfügbar sind. Um Streaming und Pufferung auf diese Weise zu kombinieren, übergibt das Beispiel ConsumerSchedule.SecondPass an trace.UseStreaming().UseSyscalls(), was bewirkt, dass die Syscall-Verarbeitung in einem zweiten Durchlauf der Ablaufverfolgung erfolgt. Durch einen erneuten Durchgang kann der Syscall-Rückruf auf das ausstehende Ergebnis von trace.UseThreads() zugreifen, wenn er jeden Syscall verarbeitet. Ohne dieses optionale Argument wäre das Syscall-Streaming im ersten Durchlauf der Ablaufverfolgung ausgeführt worden (es gäbe nur einen Durchlauf), und das ausstehende Ergebnis von Ablaufverfolgung.UseThreads() wäre noch nicht verfügbar. In diesem Fall hätte der Rückruf weiterhin Zugriff auf die ThreadId vom Syscall, jedoch keinen Zugriff auf den Prozess für den Thread, da die Verbindung zwischen Thread und Prozess durch andere Ereignisse bereitgestellt wird, die möglicherweise noch nicht verarbeitet worden sind.

Einige wichtige Unterschiede bei der Verwendung zwischen Puffern und Streaming:

  1. Die Pufferung gibt eine IPendingResult<T>zurück, und das darin enthaltene Ergebnis ist nur verfügbar, bevor die Protokollierung verarbeitet wurde. Nachdem die Ablaufverfolgung verarbeitet wurde, können die Ergebnisse mithilfe von Techniken wie foreach und LINQ aufgezählt werden.
  2. Streaming gibt nichts zurück und verwendet stattdessen ein Rückrufargument. Er ruft den Rückruf einmal auf, sobald jedes Element verfügbar wird. Da die Daten nicht gepuffert werden, gibt es nie eine Liste der Ergebnisse, die mit "foreach" oder "LINQ" aufgezählt werden können – der Streamingrückruf muss jeden Teil der Daten puffern, den er speichern möchte, nachdem die Verarbeitung abgeschlossen ist.
  3. Der Code zur Verarbeitung gepufferter Daten erscheint nach dem Aufruf von trace.Process(), sobald die ausstehenden Ergebnisse verfügbar sind.
  4. Der Code zur Verarbeitung von Streamingdaten wird vor dem Aufruf von trace.Process() angezeigt, als Rückruf der trace.UseStreaming.Use...() Methode.
  5. Ein Streaming-Consumer kann sich entscheiden, nur einen Teil des Datenstroms zu verarbeiten und zukünftige Rückrufe abzubrechen, indem der Befehl context.Cancel() aufgerufen wird. Einem puffernden Verbraucher wird immer eine vollständige, gepufferte Liste zur Verfügung gestellt.

Korrelierte Streamingdaten

Manchmal kommen Tracing-Daten in einer Abfolge von Ereignissen vor – z. B. werden Syscalls über separate Eintritts- und Austrittsereignisse protokolliert, aber die kombinierten Daten aus beiden Ereignissen können hilfreicher sein. Die Methode trace.UseStreaming().UseSyscalls() korreliert die Daten aus beiden Ereignissen und stellt sie zur Verfügung, sobald das Paar verfügbar wird. Einige Arten korrelierter Daten sind über trace.UseStreaming() verfügbar.

Programmcode BESCHREIBUNG
Spur. UseStreaming(). UseContextSwitchData() Datenströme mit korrelierten Kontextwechselevents (aus kompakten und nicht-kompakten Ereignissen, mit genaueren SwitchInThreadIds als die von nicht-kompakten Ereignissen).
Spur. UseStreaming(). UseScheduledTasks() Datenströme korrelierte geplante Vorgangsdaten.
Spur. UseStreaming(). UseSyscalls() Streamt korrelierte Systemaufrufdaten.
Spur. UseStreaming(). UseWindowInFocus() Datenströme korrelierte Fenster-in-Fokus-Daten.

Eigenständige Streamingereignisse

Darüber hinaus stellt Trace.UseStreaming() analysierte Ereignisse für eine Reihe verschiedener eigenständiger Ereignistypen bereit.

Programmcode BESCHREIBUNG
Spur. UseStreaming(). UseLastBranchRecordEvents() Datenströme analysierte Ereignisse des letzten Verzweigungsdatensatzes (LAST Branch Record, LBR).
Spur. UseStreaming(). UseReadyThreadEvents() Datenströme analysierte bereite Threadereignisse.
Spur. UseStreaming(). UseThreadCreateEvents() Datenströme, die analysierten Threadereignisse erstellen.
Spur. UseStreaming(). UseThreadExitEvents() Datenströme analysierte Threadausgangsereignisse.
Spur. UseStreaming(). UseThreadRundownStartEvents() Datenströme analysierte Threadausführungsstartereignisse.
trace.VerwendenStreaming().VerwendenThreadRundownStopEvents() Streams analysierte Threadausführungsstoppereignisse.
Spur. UseStreaming(). UseThreadSetNameEvents() Streamt analysierte Ereignisse von Threadset-Namen.

Zugrunde liegende Streamingereignisse für korrelierte Daten

Schließlich stellt trace.UseStreaming() auch die zugrunde liegenden Ereignisse bereit, die zum Korrelieren der Daten in der obigen Liste verwendet werden. Diese zugrunde liegenden Ereignisse sind:

Programmcode BESCHREIBUNG Enthalten in
Tracing.UseStreaming().UseCompactContextSwitchEvents() Datenströme analysierte Compact Context Switch-Ereignisse. Spur. UseStreaming(). UseContextSwitchData()
Spur. UseStreaming(). UseContextSwitchEvents() Datenströme analysierte Kontextwechselereignisse. SwitchInThreadIds sind in einigen Fällen möglicherweise nicht korrekt. Spur. UseStreaming(). UseContextSwitchData()
Spur. UseStreaming(). UseFocusChangeEvents() Datenströme analysierte Fensterfokusänderungsereignisse. Spur. UseStreaming(). UseWindowInFocus()
Spur. UseStreaming(). UseScheduledTaskStartEvents() Datenströme analysierte geplante Vorgangsstartereignisse. Spur. UseStreaming(). UseScheduledTasks()
Spur. UseStreaming(). UseScheduledTaskStopEvents() Datenströme analysierte geplante Vorgangsstoppereignisse. Spur. UseStreaming(). UseScheduledTasks()
Spur. UseStreaming(). UseScheduledTaskTriggerEvents() Datenströme analysierte geplante Aufgabentriggerereignisse. Spur. UseStreaming(). UseScheduledTasks()
Spur. UseStreaming(). UseSessionLayerSetActiveWindowEvents() Datenströme, die analysiert wurden, auf Sitzungsebene festgelegte aktive Fensterereignisse. Spur. UseStreaming(). UseWindowInFocus()
Spur. UseStreaming(). UseSyscallEnterEvents() Datenströme, die syscall analysiert haben, geben Ereignisse ein. Spur. UseStreaming(). UseSyscalls()
Spur. UseStreaming(). UseSyscallExitEvents() Datenströme analysierte Syscall-Beendigungsereignisse. Spur. UseStreaming(). UseSyscalls()

Nächste Schritte

In diesem Tutorial haben Sie gelernt, wie Sie mithilfe des Streamings direkten Zugriff auf Ablaufverfolgungsdaten erhalten und dabei weniger Arbeitsspeicher verwenden.

Der nächste Schritt besteht darin, aus Ihren Ablaufverfolgungen auf die gewünschten Daten zuzugreifen. Schauen Sie sich die Beispiele für einige Ideen an. Beachten Sie, dass nicht alle Ablaufverfolgungen alle unterstützten Datentypen enthalten.