다음을 통해 공유


TraceProcessor에서 스트리밍 사용

기본적으로 TraceProcessor는 추적이 처리될 때 메모리에 로드하여 데이터에 액세스합니다. 이 버퍼링 방법은 사용하기 쉽지만 메모리 사용량 측면에서 비용이 많이 들 수 있습니다.

TraceProcessor는 trace.UseStreaming()을 제공하며, 이는 여러 유형의 추적 데이터를 스트리밍 방식으로 액세스할 수 있도록 지원합니다 (추적 파일에서 데이터를 읽을 때 바로 처리하며, 메모리에 그 데이터를 버퍼링하지 않습니다). 예를 들어, syscalls 추적은 매우 클 수 있으며, 추적에서 전체 syscalls 목록을 버퍼링하면 비용이 많이 들 수 있습니다.

버퍼링된 데이터 액세스

다음 코드는 추적을 통해 일반 버퍼링된 방식으로 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 추적을 사용하면 메모리에서 syscall 데이터를 버퍼링하려고 하면 비용이 많이 들거나 불가능할 수도 있습니다. 다음 코드는 trace.UseSyscalls()를 trace.UseStreaming().UseSyscalls()로 대체하여 동일한 syscall 데이터를 스트리밍 방식으로 액세스하는 방법을 보여줍니다.

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 데이터가 스트리밍되기 전에 스레드 데이터가 버퍼링됩니다. 따라서 버퍼링된 스레드 데이터를 가져오기 위해 한 번, 이제 사용 가능한 버퍼링된 스레드 데이터를 사용하여 스트리밍 syscall 데이터에 액세스하기 위해 두 번째로 추적을 읽어야 합니다. 이러한 방식으로 스트리밍과 버퍼링을 결합하기 위해, 이 예제에서는 ConsumerSchedule.SecondPass를 trace.UseStreaming().UseSyscalls()에 전달하여, 추적의 두 번째 패스를 통해 syscall 처리가 이루어지도록 합니다. 두 번째 패스에서 실행할 때, syscall 콜백은 syscall을 처리할 때 trace.UseThreads()로부터 보류 중인 결과에 접근할 수 있습니다. 이 선택적 인수가 없으면 syscall 스트리밍은 추적을 통과하는 첫 번째 패스에서 실행되어야 하고(단일 패스만 있다면), 추적의 UseThreads()로부터의 대기 중인 결과는 아직 사용할 수 없습니다. 이 경우 콜백은 여전히 syscall에서 ThreadId에 액세스할 수 있지만 스레드에 대한 프로세스에 액세스할 수 없습니다(연결 데이터를 처리하는 스레드는 아직 처리되지 않았을 수 있는 다른 이벤트를 통해 제공되기 때문).

버퍼링과 스트리밍 간 사용의 몇 가지 주요 차이점:

  1. 버퍼링은 IPendingResult <T>를 반환하며, 보류된 결과는 추적이 처리되기 전에만 사용할 수 있습니다. 추적이 처리된 후 foreach 및 LINQ와 같은 기술을 사용하여 결과를 열거할 수 있습니다.
  2. 스트리밍은 void를 반환하고 대신 콜백 인수를 사용합니다. 각 항목을 사용할 수 있게 되면 콜백을 한 번 호출합니다. 데이터는 버퍼링되지 않으므로 foreach 또는 LINQ를 사용하여 열거할 결과 목록이 없습니다. 스트리밍 콜백은 처리가 완료된 후 사용하기 위해 저장하려는 데이터의 어떤 부분을 버퍼링해야 합니다.
  3. 버퍼링된 데이터를 처리하는 코드는 trace.Process() 호출 후, 보류 중인 결과를 사용할 수 있을 때 나타납니다.
  4. trace.Process() 호출 전에, trace.UseStreaming.Use...() 메서드의 콜백으로 스트리밍 데이터를 처리하는 코드가 나타납니다.
  5. 스트리밍 소비자는 컨텍스트를 호출하여 스트림의 일부만 처리하고 이후 콜백을 취소하도록 선택할 수 있습니다. Cancel(). 버퍼링 소비자는 항상 완전하고 버퍼링된 목록을 받습니다.

상호 관련된 스트리밍 데이터

경우에 따라 추적 데이터가 일련의 이벤트로 제공됩니다. 예를 들어 syscall은 별도의 Enter 및 Exit 이벤트를 통해 기록되지만 두 이벤트의 결합된 데이터가 더 유용할 수 있습니다. 메서드 trace.UseStreaming().UseSyscalls()는 두 이벤트의 데이터를 연결하고 쌍이 사용 가능해지면 이를 제공합니다. 추적을 통해 몇 가지 유형의 상관 관계 데이터를 사용할 수 있습니다. UseStreaming():

코드 설명
추적.UseStreaming().UseContextSwitchData() 상호 관련된 컨텍스트 스위치 데이터를 스트림합니다(압축 이벤트 및 압축되지 않은 이벤트에서 원시 비콤팩트 이벤트보다 더 정확한 SwitchInThreadIds 사용).
추적.UseStreaming().UseScheduledTasks() 상호 관련된 예약된 작업 데이터를 스트리밍합니다.
추적.UseStreaming().UseSyscalls() 상호 관련된 시스템 호출 데이터를 스트리밍합니다.
자취. UseStreaming(). UseWindowInFocus() 포커스된 창의 상호 관련 데이터를 스트리밍합니다.

독자적 스트리밍 이벤트

또한 trace.UseStreaming()은 여러 가지 다른 독립 실행형 이벤트 유형에 대해 구문 분석된 이벤트를 제공합니다.

코드 설명
트레이스. UseStreaming(). UseLastBranchRecordEvents() LBR(마지막 분기 레코드) 이벤트를 구문 분석한 스트림입니다.
자취. UseStreaming(). UseReadyThreadEvents() 준비된 스레드 이벤트를 구문 분석한 스트림입니다.
트레이스.UseStreaming().UseThreadCreateEvents() 구문 분석된 스레드 생성 이벤트를 스트림합니다.
추적.UseStreaming().UseThreadExitEvents() 구문 분석된 스레드 종료 이벤트를 스트림합니다.
트레이스.UseStreaming().UseThreadRundownStartEvents() 구문 분석된 스레드 런다운 시작 이벤트를 스트림합니다.
추적.UseStreaming().UseThreadRundownStopEvents() 구문 분석된 스레드 런다운 중지 이벤트를 스트림합니다.
자취. UseStreaming(). UseThreadSetNameEvents() 구문 분석된 스레드 집합 이름 이벤트를 스트림합니다.

상관 관계가 있는 데이터에 대한 기본 스트리밍 이벤트

마지막으로, trace.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() 구문 분석된 syscall을 스트리밍하여 이벤트를 입력합니다. 추적.UseStreaming().UseSyscalls()
자취. UseStreaming(). UseSyscallExitEvents() 구문이 분석된 시스템 호출 종료 이벤트를 스트리밍합니다. 추적.UseStreaming().UseSyscalls()

다음 단계

이 자습서에서는 스트리밍을 사용하여 추적 데이터에 즉시 액세스하고 메모리를 적게 사용하는 방법을 알아보았습니다.

다음 단계는 추적에서 원하는 데이터에 액세스하는 것입니다. 몇 가지 아이디어를 위해 샘플을 살펴보세요. 모든 추적에 모든 지원되는 데이터 유형이 포함되지는 않습니다.