다음을 통해 공유


TraceProcessor로 스트리밍 사용

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

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

버퍼링된 데이터 액세스

다음 코드는 trace.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<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 스트리밍은 추적을 통한 첫 번째 전달에서 실행되고(전달이 하나만 있음) trace.UseThreads()의 보류 중인 결과는 아직 사용할 수 없습니다. 이 경우 콜백은 여전히 syscall에서 ThreadId에 액세스할 수 있지만 스레드에 대한 프로세스에는 액세스할 수 없습니다(연결 데이터를 처리하는 스레드가 아직 처리되지 않았을 수도 있는 다른 이벤트를 통해 제공되기 때문임).

버퍼링과 스트리밍의 사용량에 있어 몇 가지 주요 차이점은 다음과 같습니다.

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

상관 관계가 지정된 스트리밍 데이터

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

코드 설명
trace.UseStreaming().UseContextSwitchData() 상관 관계가 지정된 컨텍스트 전환 데이터를 스트리밍합니다(원시 비압축 이벤트보다 더 정확한 SwitchInThreadIds를 사용하여 압축 및 비압축 이벤트에서).
trace.UseStreaming().UseScheduledTasks() 상관 관계가 지정된 예약된 작업 데이터를 스트리밍합니다.
trace.UseStreaming().UseSyscalls() 상관 관계가 지정된 시스템 호출 데이터를 스트리밍합니다.
trace.UseStreaming().UseWindowInFocus() 상관 관계가 지정된 window-in-focus 데이터를 스트리밍합니다.

독립 실행형 스트리밍 이벤트

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

코드 설명
trace.UseStreaming().UseLastBranchRecordEvents() 구문 분석된 LBR(Last Branch Record) 이벤트를 스트리밍합니다.
trace.UseStreaming().UseReadyThreadEvents() 구문 분석된 준비 스레드 이벤트를 스트리밍합니다.
trace.UseStreaming().UseThreadCreateEvents() 구문 분석된 스레드 생성 이벤트를 스트리밍합니다.
trace.UseStreaming().UseThreadExitEvents() 구문 분석된 스레드 종료 이벤트를 스트리밍합니다.
trace.UseStreaming().UseThreadRundownStartEvents() 구문 분석된 스레드 런다운 시작 이벤트를 스트리밍합니다.
trace.UseStreaming().UseThreadRundownStopEvents() 구문 분석된 스레드 런다운 중지 이벤트를 스트리밍합니다.
trace.UseStreaming().UseThreadSetNameEvents() 구문 분석된 스레드 집합 이름 이벤트를 스트리밍합니다.

상관 관계가 지정된 데이터에 대한 기본 스트리밍 이벤트

마지막으로 trace.UseStreaming()은 위 목록의 데이터에 상관 관계를 지정하는 데 사용되는 기본 이벤트도 제공합니다. 이러한 기본 이벤트는 다음과 같습니다.

코드 설명 포함된 운영 체제
trace.UseStreaming().UseCompactContextSwitchEvents() 구문 분석된 압축 컨텍스트 전환 이벤트를 스트리밍합니다. trace.UseStreaming().UseContextSwitchData()
trace.UseStreaming().UseContextSwitchEvents() 구문 분석된 컨텍스트 전환 이벤트를 스트리밍합니다. SwitchInThreadIds는 경우에 따라 정확하지 않을 수 있습니다. trace.UseStreaming().UseContextSwitchData()
trace.UseStreaming().UseFocusChangeEvents() 구문 분석된 창 포커스 변경 이벤트를 스트리밍합니다. trace.UseStreaming().UseWindowInFocus()
trace.UseStreaming().UseScheduledTaskStartEvents() 구문 분석된 예약된 작업 시작 이벤트를 스트리밍합니다. trace.UseStreaming().UseScheduledTasks()
trace.UseStreaming().UseScheduledTaskStopEvents() 구문 분석된 예약된 작업 중지 이벤트를 스트리밍합니다. trace.UseStreaming().UseScheduledTasks()
trace.UseStreaming().UseScheduledTaskTriggerEvents() 구문 분석된 예약된 작업 트리거 이벤트를 스트리밍합니다. trace.UseStreaming().UseScheduledTasks()
trace.UseStreaming().UseSessionLayerSetActiveWindowEvents() 구문 분석된 세션 계층 활성 창 설정 이벤트를 스트리밍합니다. trace.UseStreaming().UseWindowInFocus()
trace.UseStreaming().UseSyscallEnterEvents() 구문 분석된 syscall enter 이벤트를 스트리밍합니다. trace.UseStreaming().UseSyscalls()
trace.UseStreaming().UseSyscallExitEvents() 구문 분석된 syscall exit 이벤트를 스트리밍합니다. trace.UseStreaming().UseSyscalls()

다음 단계

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

다음 단계에서는 추적에서 원하는 데이터에 대한 액세스를 확인합니다. 샘플에서 몇 가지 아이디어를 살펴보세요. 일부 추적에는 지원되는 모든 데이터 유형이 포함되지 않습니다.