Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
По умолчанию TraceProcessor обращается к данным, загружая его в память по мере обработки трассировки. Этот подход к буферизации прост в использовании, но он может быть дорогостоящим с точки зрения использования памяти.
TraceProcessor также предоставляет функцию UseStreaming(), которая поддерживает доступ к нескольким типам данных трассировки в потоковом режиме (обрабатывая данные во время их чтения из файла трассировки, а не буферизируя эти данные в памяти). Например, трассировка системных вызовов может быть довольно большой, а буферизация всего списка системных вызовов в трассировке может быть довольно дорогой.
Доступ к буферным данным
В следующем коде показан доступ к данным syscall в обычном буферизованном режиме с помощью трассировки. 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]}");
}
}
}
}
Доступ к потоковым данным
При большой трассировке системных вызовов попытка буферизовать данные системных вызовов в памяти может быть довольно дорогой или даже невозможной. В следующем коде показано, как получить доступ к тем же данным syscall в потоковом режиме, заменив trace.UseSyscalls() на 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]}");
}
}
}
}
Как работает потоковая передача
По умолчанию все данные потоковой передачи предоставляются во время первого прохождения трассировки, а буферированные данные из других источников недоступны. В приведенном выше примере показано, как объединить потоковую передачу с буферизацией — данные потока буфериируются перед потоковой передачей данных syscall. В результате трассировка должна быть прочитана дважды: один раз, чтобы получить буферированные данные потока, и второй раз, чтобы получить доступ к потоковым данным системных вызовов с предварительно полученными буферированными данными потока. Для объединения потоковой передачи и буферизации таким образом, пример передает ConsumerSchedule.SecondPass в методы trace.UseStreaming().UseSyscalls(), что вызывает обработку системных вызовов во втором проходе через трассировку. Выполнив второй проход, обратный вызов системного вызова может получить доступ к результату, который находится в ожидании, из trace.UseThreads() при обработке каждого системного вызова. Без этого необязательного аргумента потоковая передача системных вызовов выполнялась бы при первом проходе через трассировку (был бы только один проход), и ожидаемый результат от вызова trace.UseThreads() еще не был бы доступен. В этом случае обратный вызов по-прежнему будет иметь доступ к идентификатору потока из системного вызова, но он не будет иметь доступа к процессу, к которому относится поток (так как данные о связывании потока с процессом предоставляются через другие события, которые, возможно, еще не были обработаны).
Некоторые ключевые различия в использовании между буферизацией и потоковой передачей:
- Буферизация возвращает IPendingResult<T>, и результат, который он содержит, доступен только до того, как трассировка будет обработана. После обработки трассировки результаты можно перечислить с помощью таких методов, как foreach и LINQ.
- Потоковая передача возвращает void и вместо этого принимает аргумент обратного вызова. Он вызывает обратный вызов один раз, когда каждый элемент становится доступным. Поскольку данные не буферизованы, никогда не существует списка результатов для перечисления с помощью foreach или LINQ. Обратный вызов потоковой передачи должен буферировать любую часть данных, которую он хочет сохранить для использования после завершения обработки.
- Код для обработки буферированных данных появляется после вызова trace.Process(), когда доступны необработанные результаты.
- Код для обработки потоковых данных располагается перед вызовом trace.Process(), как обратный вызов метода trace.UseStreaming.Use...().
- Пользователь потокового сервиса может обрабатывать только часть потока и отменить будущие обратные вызовы, вызвав метод context.Cancel(). Потребитель буферизации всегда предоставляет полный буферный список.
Коррелированные данные потоковой передачи
Иногда данные трассировки представляют собой последовательность событий, например, системные вызовы (syscalls) регистрируются через отдельные события входа и выхода, но объединенные данные из обоих событий могут оказаться более полезными. Метод trace.UseStreaming().UseSyscalls() сопоставляет данные из обоих этих событий и предоставляет их по мере доступности. Через трассировку с использованием UseStreaming() можно получить несколько типов коррелированных данных.
| Код | Описание |
|---|---|
| след.UseStreaming().UseContextSwitchData() | Потоки данных связаны с данными переключения контекста (из компактных и некомпактных событий с более точными идентификаторами SwitchInThreadIds, чем в необработанных некомпактных событиях). |
| след. UseStreaming(). UseScheduledTasks() | Потоки, связанные с данными запланированной задачи. |
| трассировка.UseStreaming().UseSyscalls() | Потоки с коррелированными данными системных вызовов. |
| след. UseStreaming(). UseWindowInFocus() | Потоки коррелируют данные с фокусом окна. |
Автономные события потоковой передачи
Кроме того, трассировка. UseStreaming() предоставляет проанализированные события для ряда различных автономных типов событий:
| Код | Описание |
|---|---|
| трассировка.UseStreaming().UseLastBranchRecordEvents() | Потоки анализирует события последней записи ветви (LBR). |
| след. UseStreaming(). UseReadyThreadEvents() | Потоки анализирует события готового потока. |
| трейс.UseStreaming().UseThreadCreateEvents() | Потоки синтаксического анализа создают события. |
| след. UseStreaming().UseThreadExitEvents() | Потоки обрабатывают события выхода из потока. |
| трассировка.UseStreaming().UseThreadRundownStartEvents() | Анализируемые потоки начинают обработку событий запуска завершения потока. |
| трассировка.UseStreaming().UseThreadRundownStopEvents() | Потоки синтаксического анализа событий остановки запуска потока. |
| отслеживать.UseStreaming().UseThreadSetNameEvents() | Потоки обрабатывают события назначения имен набора потоков. |
Базовые события потоковой передачи для коррелированных данных
Наконец, трассировка, используя UseStreaming(), также предоставляет базовые события, используемые для сопоставления данных в списке выше. Ниже приведены следующие базовые события:
| Код | Описание | Включен в |
|---|---|---|
| след. UseStreaming(). UseCompactContextSwitchEvents() | Потоки анализируют события компактного переключения контекста. | след.UseStreaming().UseContextSwitchData() |
| трассировка.UseStreaming(). UseContextSwitchEvents() | Потоки обрабатывают события переключения контекста. SwitchInThreadIds может быть не точным в некоторых случаях. | след.UseStreaming().UseContextSwitchData() |
| Следите за изменениями с помощью UseStreaming(). UseFocusChangeEvents() | Потоки анализируемых событий изменения фокуса окна. | след. UseStreaming(). UseWindowInFocus() |
| след. UseStreaming(). UseScheduledTaskStartEvents() | Потоки, анализирующие события начала запланированных задач. | след. UseStreaming(). UseScheduledTasks() |
| след. UseStreaming(). UseScheduledTaskStopEvents() | Потоки обрабатывают события остановки запланированных задач. | след. UseStreaming(). UseScheduledTasks() |
| трассировка.UseStreaming().UseScheduledTaskTriggerEvents() | Потоки анализируют события триггеров запланированной задачи. | след. UseStreaming(). UseScheduledTasks() |
| след. UseStreaming(). UseSessionLayerSetActiveWindowEvents() | Потоки, обрабатывающие события уровня сеансов, устанавливают события активного окна. | след. UseStreaming(). UseWindowInFocus() |
| трассировка.UseStreaming().UseSyscallEnterEvents() | Потоки, обрабатывающие входящие события системных вызовов. | трассировка.UseStreaming().UseSyscalls() |
| трассировка.UseStreaming().UseSyscallExitEvents() | Потоки анализируют события выхода системных вызовов. | трассировка.UseStreaming().UseSyscalls() |
Дальнейшие шаги
В этом руководстве вы узнали, как использовать потоковую передачу для доступа к данным трассировки сразу и использовать меньше памяти.
Следующим шагом является получение доступа к нужным данным из ваших трассировок. Посмотрите на образцы , чтобы получить идеи. Обратите внимание, что не все трассировки включают все поддерживаемые типы данных.
Windows developer