Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Par défaut, TraceProcessor accède aux données en les chargeant en mémoire, car la trace est traitée. Cette approche de mise en mémoire tampon est facile à utiliser, mais elle peut être coûteuse en termes d’utilisation de la mémoire.
TraceProcessor fournit également trace.UseStreaming(), qui prend en charge l’accès à plusieurs types de données de trace de manière continue (traitement des données telles qu’elles sont lues à partir du fichier de trace, au lieu de mettre en mémoire tampon ces données). Par exemple, une trace syscalls peut être assez volumineuse et mettre en mémoire tampon toute la liste des syscalls dans une trace peut être assez coûteuse.
Accès aux données mises en mémoire tampon
Le code suivant montre l'accès aux données de syscall de manière normale et mis en mémoire tampon via 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]}");
}
}
}
}
Accès aux données de streaming
Avec une trace de syscalls volumineuse, essayer de mettre en mémoire tampon les données des syscalls peut être assez coûteux, voire impossible. Le code suivant montre comment accéder aux mêmes données syscall de manière continue, en remplaçant trace.UseSyscalls() avec trace.UseStreaming().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<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]}");
}
}
}
}
Fonctionnement de la diffusion en continu
Par défaut, toutes les données de diffusion en continu sont fournies pendant la première passe par la trace, et les données mises en mémoire tampon provenant d’autres sources ne sont pas disponibles. L’exemple ci-dessus montre comment combiner la diffusion en continu avec la mise en mémoire tampon : les données de thread sont mises en mémoire tampon avant que les données syscall ne sont diffusées en continu. Par conséquent, la trace doit être lue deux fois : une fois pour obtenir des données de fil mises en mémoire tampon, et une deuxième fois pour accéder aux données de streaming syscall, les données de fil mises en mémoire tampon étant désormais disponibles. Pour combiner la diffusion en continu et la mise en mémoire tampon de cette façon, l’exemple passe ConsumerSchedule.SecondPass à trace.UseStreaming().UseSyscalls(), ce qui provoque le traitement des appels systèmes lors d'un deuxième passage à travers la trace. En s’exécutant dans une deuxième passe, le rappel syscall peut accéder au résultat en attente à partir de la trace. UseThreads() quand il traite chaque syscall. Sans cet argument facultatif, le streaming des appels système aurait été exécuté lors de la première passe à travers la trace (il n’y aurait qu’une seule passe), et le résultat en attente du trace.UseThreads() ne serait pas encore disponible. Dans ce cas, le rappel aurait toujours accès à ThreadId à partir de l'appel système, mais il n'aurait pas accès au processus du thread (car les données de liaison du thread au processus sont fournies via d'autres événements qui n'ont peut-être pas encore été traités).
Voici quelques principales différences d’utilisation entre la mise en mémoire tampon et la diffusion en continu :
- La mise en mémoire tampon retourne un IPendingResult<T>, et le résultat qu’il contient est disponible uniquement avant le traitement de la trace. Une fois la trace traitée, les résultats peuvent être énumérés à l’aide de techniques telles que foreach et LINQ.
- La diffusion en continu renvoie void et prend au lieu de cela un argument de callback. Il appelle le rappel une fois que chaque élément devient disponible. Étant donné que les données ne sont pas mises en mémoire tampon, il n’existe jamais de liste de résultats à énumérer avec foreach ou LINQ . Le rappel de diffusion en continu doit mettre en mémoire tampon quelle que soit la partie des données qu’il souhaite enregistrer pour une utilisation une fois le traitement terminé.
- Le code pour le traitement des données mises en mémoire tampon s’affiche après l’appel à la trace. Processus(), lorsque les résultats en attente sont disponibles.
- Le code pour le traitement des données de diffusion en continu apparaît avant l'appel à trace.Process(), comme un rappel pour la méthode trace.UseStreaming.Use...().
- Un consommateur de streaming peut choisir de traiter uniquement une partie du flux et d’annuler les rappels futurs en appelant le contexte. Cancel(). Un consommateur en mémoire tampon reçoit toujours une liste complète et mise en mémoire tampon.
Données de streaming corrélées
Parfois, les données de trace se trouvent dans une séquence d’événements : par exemple, les syscalls sont enregistrés via des événements d’entrée et de sortie distincts, mais les données combinées des deux événements peuvent être plus utiles. La méthode trace.UseStreaming().UseSyscalls() met en corrélation les données de ces deux événements et les fournit au fur et à mesure que la paire devient disponible. Quelques types de données corrélées sont disponibles via la trace. UseStreaming() :
| Code | Descriptif |
|---|---|
| trace. UseStreaming(). UseContextSwitchData() | Transmission de données liées aux commutations de contexte (provenant d’événements compacts et non compacts, avec des SwitchInThreadIds plus précis que ceux des événements bruts non compacts). |
| trace. UseStreaming(). UseScheduledTasks() | Flux de données de tâches planifiées corrélées. |
| trace. UseStreaming(). UseSyscalls() | Flux de données d’appel système corrélées. |
| trace. UseStreaming(). UseWindowInFocus() | Flux de données de fenêtre en focus corrélées. |
Événements de diffusion en continu autonomes
En outre, trace. UseStreaming() fournit des événements analysés pour un certain nombre de différents types d’événements autonomes :
| Code | Descriptif |
|---|---|
| trace. UseStreaming(). UseLastBranchRecordEvents() | Les flux analysent les événements des enregistrements de la dernière branche (LBR). |
| trace. UseStreaming(). UseReadyThreadEvents() | Diffuse en continu les événements de thread prêts à l’analyse. |
| trace. UseStreaming(). UseThreadCreateEvents() | Flux d’événements de création de thread analysés. |
| trace. UseStreaming(). UseThreadExitEvents() | Diffuse des événements de sortie de thread analysés. |
| trace. UseStreaming(). UseThreadRundownStartEvents() | Diffuse en continu les événements de démarrage de thread analysés. |
| trace. UseStreaming(). UseThreadRundownStopEvents() | Diffuse les événements d'arrêt du flux de threads analysés. |
| trace. UseStreaming(). UseThreadSetNameEvents() | Diffuse les événements de noms de groupes de threads analysés. |
Événements de streaming sous-jacents pour les données corrélées
Enfin, trace. UseStreaming() fournit également les événements sous-jacents utilisés pour mettre en corrélation les données dans la liste ci-dessus. Ces événements sous-jacents sont les suivants :
| Code | Descriptif | Inclus dans |
|---|---|---|
| trace. UseStreaming(). UseCompactContextSwitchEvents() | Flux d’événements de commutateur de contexte compact analysés. | trace. UseStreaming(). UseContextSwitchData() |
| trace. UseStreaming(). UseContextSwitchEvents() | Diffuse en continu les événements de commutateur de contexte analysés. SwitchInThreadIds peut ne pas être exact dans certains cas. | trace. UseStreaming(). UseContextSwitchData() |
| trace. UseStreaming(). UseFocusChangeEvents() | Flux d’événements de modification du focus de fenêtre analysés. | trace. UseStreaming(). UseWindowInFocus() |
| trace. UseStreaming(). UseScheduledTaskStartEvents() | Diffuse en continu les événements de démarrage de tâche planifiée analysés. | trace. UseStreaming(). UseScheduledTasks() |
| trace. UseStreaming(). UseScheduledTaskStopEvents() | Diffuse les événements d’arrêt de tâche planifiée analysés. | trace. UseStreaming(). UseScheduledTasks() |
| trace. UseStreaming(). UseScheduledTaskTriggerEvents() | Diffuse en continu les événements de déclencheur de tâche planifiés analysés. | trace. UseStreaming(). UseScheduledTasks() |
| trace. UseStreaming(). UseSessionLayerSetActiveWindowEvents() | Flux d’événements de fenêtre actifs analysés par la couche session. | trace. UseStreaming(). UseWindowInFocus() |
| trace. UseStreaming(). UseSyscallEnterEvents() | Les flux analysent les événements d'entrée des appels système. | trace. UseStreaming(). UseSyscalls() |
| trace. UseStreaming(). UseSyscallExitEvents() | Flux d’événements de sortie syscall analysés. | trace. UseStreaming(). UseSyscalls() |
Étapes suivantes
Dans ce tutoriel, vous avez appris à utiliser la diffusion en continu pour accéder immédiatement aux données de trace et à utiliser moins de mémoire.
L’étape suivante consiste à obtenir les données que vous souhaitez à partir de vos traces. Examinez les exemples pour quelques idées. Notez que toutes les traces n’incluent pas tous les types de données pris en charge.
Windows developer