.NET TraceProcessing でシンボルを使用する

TraceProcessor では、複数のデータ ソースからシンボルを読み込み、スタックを取得することをサポートしています。 次のコンソール アプリケーションでは、CPU のサンプルを調べ、(トレースの CPU 使用率の統計サンプリングに基づいて) 特定の関数が実行されていた推定所要時間を出力します。

using Microsoft.Windows.EventTracing;
using Microsoft.Windows.EventTracing.Cpu;
using Microsoft.Windows.EventTracing.Symbols;
using System;
using System.Collections.Generic;

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

        string tracePath = args[0];
        string imageName = args[1];
        string functionName = args[2];
        Dictionary<string, Duration> matchDurationByCommandLine = new Dictionary<string, Duration>();

        using (ITraceProcessor trace = TraceProcessor.Create(tracePath))
        {
            IPendingResult<ISymbolDataSource> pendingSymbolData = trace.UseSymbols();
            IPendingResult<ICpuSampleDataSource> pendingCpuSamplingData = trace.UseCpuSamplingData();

            trace.Process();

            ISymbolDataSource symbolData = pendingSymbolData.Result;
            ICpuSampleDataSource cpuSamplingData = pendingCpuSamplingData.Result;

            symbolData.LoadSymbolsForConsoleAsync(SymCachePath.Automatic, SymbolPath.Automatic).GetAwaiter().GetResult();

            Console.WriteLine();
            IThreadStackPattern pattern = AnalyzerThreadStackPattern.Parse($"{imageName}!{functionName}");

            foreach (ICpuSample sample in cpuSamplingData.Samples)
            {
                if (sample.Stack != null && sample.Stack.Matches(pattern))
                {
                    string commandLine = sample.Process.CommandLine;

                    if (!matchDurationByCommandLine.ContainsKey(commandLine))
                    {
                        matchDurationByCommandLine.Add(commandLine, Duration.Zero);
                    }

                    matchDurationByCommandLine[commandLine] += sample.Weight;
                }
            }

            foreach (string commandLine in matchDurationByCommandLine.Keys)
            {
                Console.WriteLine($"{commandLine}: {matchDurationByCommandLine[commandLine]}");
            }
        }
    }
}

このプログラムを実行すると、次のような出力が生成されます。

C:\GetCpuSampleDuration\bin\Debug\> GetCpuSampleDuration.exe C:\boot.etl user32.dll LoadImageInternal
0.0% (0 of 1165; 0 loaded)
<snip>
100.0% (1165 of 1165; 791 loaded)
wininit.exe: 15.99 ms
C:\Windows\Explorer.EXE: 5 ms
winlogon.exe: 20.15 ms
"C:\Users\AdminUAC\AppData\Local\Microsoft\OneDrive\OneDrive.exe" /background: 2.09 ms

(出力の詳細はトレースによって異なります)。

シンボルの形式

TraceProcessor では、内部的に、PDB に格納されている一部のデータのキャッシュである SymCache 形式を使用します。 シンボルを読み込むときに、TraceProcessor では、これらの SymCache ファイルを使用する場所 (SymCache パス) を指定し、必要に応じて PDB にアクセスするための SymbolPath を指定する必要があります。 SymbolPath が指定されると、TraceProcessor では必要に応じて、PDB ファイルから SymCache ファイルを作成します。また、同じデータの後続の処理では、パフォーマンス向上のために SymCache ファイルを直接使用できます。

次のステップ

このチュートリアルでは、トレースを処理するときにシンボルを読み込む方法について説明しました。

次の手順では、ストリーミングを使用して、すべてをメモリ内にバッファリングすることなく、トレース データにアクセスする方法について説明します。