使用 PerfCollect 跟踪 .NET 应用程序

本文适用于:✔️ .NET Core 2.1 SDK 及更高版本

在 Linux 上遇到性能问题时,可使用 perfcollect 收集跟踪,以便收集有关出现性能问题时计算机上发生的状况的详细信息。

perfcollect 是一个 bash 脚本,它使用 Linux 跟踪工具包: 下一代 (LTTng) 收集从运行时或任何 EventSource 写入的事件,并使用 perf 收集目标进程的 CPU 示例。

准备计算机

按照以下步骤准备你的计算机以使用 perfcollect 收集性能跟踪。

注意

如果要从容器内部捕获,则容器必须具有相应的功能。 所需的最少功能是 PERFMONSYS_PTRACE。 如果捕获失败且集最小,请将 SYS_ADMIN 功能添加到容器。 有关使用 PerfCollect 跟踪容器内应用程序的详细信息,请参阅在容器中收集诊断信息

  1. 下载 perfcollect

    curl -OL https://aka.ms/perfcollect
    
  2. 使脚本可执行。

    chmod +x perfcollect
    
  3. 安装跟踪必备组件 - 这些是实际的跟踪库。

    sudo ./perfcollect install
    

    这将在你的计算机上安装以下必备组件:

    1. perf:Linux 性能事件子系统和配套的用户模式收集/查看器应用程序。 perf 是 Linux 内核源的一部分,但是默认情况下通常不安装。

    2. LTTng:用于捕获 CoreCLR 在运行时发出的事件数据。 然后使用这些数据分析各种运行时组件(如 GC、JIT 和线程池)的行为。

最新版本的 .NET Core 和 Linux 性能工具支持自动解析框架代码的方法名称。

若要解析本机运行时 DLL 的方法名称(例如 libcoreclr.so),perfcollect 将在转换数据时为其解析符号,但前提是存在这些二进制文件的符号。 有关详细信息,请参阅获取本机运行时的符号部分。

收集跟踪

  1. 有两个可用的 shell - 一个用于控制跟踪,称为 [Trace],另一个用于运行应用程序,称为 [App] 。

  2. [Trace]:启动收集。

    sudo ./perfcollect collect sampleTrace
    

    预期输出:

    Collection started.  Press CTRL+C to stop.
    
  3. [App]:使用以下环境变量设置应用程序 shell - 这将启用 CoreCLR 的跟踪配置。

    export DOTNET_PerfMapEnabled=1
    export DOTNET_EnableEventLog=1
    

    注意

    使用 .NET 7 执行应用时,除设置上述环境变量之外,还必须设置 DOTNET_EnableWriteXorExecute=0。 例如:

    export DOTNET_EnableWriteXorExecute=0
    

    注意

    .NET 6 为用于配置 .NET 运行时行为的环境变量标准化前缀 DOTNET_ 而不是 COMPlus_。 但是,COMPlus_ 前缀仍将继续正常工作。 如果使用的是早期版本的 .NET 运行时,则环境变量仍应该使用 COMPlus_ 前缀。

  4. [App]:运行应用 - 使其运行捕获性能问题所需的时间。 确切时间可以是所需的最短时间,只要足以捕获要调查的性能问题发生的时间窗口。

    dotnet run
    
  5. [Trace]:停止收集 - 按 CTRL+C。

    ^C
    ...STOPPED.
    
    Starting post-processing. This may take some time.
    
    Generating native image symbol files
    ...SKIPPED
    Saving native symbols
    ...FINISHED
    Exporting perf.data file
    ...FINISHED
    Compressing trace files
    ...FINISHED
    Cleaning up artifacts
    ...FINISHED
    
    Trace saved to sampleTrace.trace.zip
    

    压缩的跟踪文件现存储在当前工作目录中。

查看跟踪

有许多选项可用于查看收集的跟踪。 在 Windows 上,最好使用 PerfView 查看跟踪;但在 Linux 上,可以使用 PerfCollect 本身或 TraceCompass 直接进行查看。

使用 PerfCollect 查看跟踪文件

你可以使用 perfcollect 本身来查看收集的跟踪。 为此,请使用以下命令:

./perfcollect view sampleTrace.trace.zip

默认情况下,这将使用 perf 显示应用程序的 CPU 跟踪。

要查看通过 LTTng 收集的事件,可以传入标志 -viewer lttng 以查看各个事件:

./perfcollect view sampleTrace.trace.zip -viewer lttng

这将使用 babeltrace 查看器打印事件有效负载:

# [01:02:18.189217659] (+0.020132603) ubuntu-xenial DotNETRuntime:ExceptionThrown_V1: { cpu_id = 0 }, { ExceptionType = "System.Exception", ExceptionMessage = "An exception happened", ExceptionEIP = 139875671834775, ExceptionHRESULT = 2148734208, ExceptionFlags = 16, ClrInstanceID = 0 }
# [01:02:18.189250227] (+0.020165171) ubuntu-xenial DotNETRuntime:ExceptionCatchStart: { cpu_id = 0 }, { EntryEIP = 139873639728404, MethodID = 139873626968120, MethodName = "void [helloworld] helloworld.Program::Main(string[])", ClrInstanceID = 0 }

使用 PerfView 打开跟踪文件

要查看 CPU 示例和事件的聚合视图,可以在 Windows 计算机上使用 PerfView

  1. 将 trace.zip 文件从 Linux 复制到 Windows 计算机。

  2. https://aka.ms/perfview 下载 PerfView。

  3. 运行 PerfView.exe

    PerfView.exe <path to trace.zip file>
    

PerfView 将基于跟踪文件中包含的数据显示受支持的视图列表。

  • 对于 CPU 调查,请选择“CPU 堆栈”。

  • 有关 GC 的详细信息,请选择“GCStats”。

  • 有关每个进程/模块/方法的 JIT 信息,请选择“JITStats”。

  • 如果没有所需信息的视图,可以尝试在原始事件视图中查找事件。 选择“事件”。

有关如何在 PerfView 中解释视图的详细信息,请参见视图本身的帮助链接,或者从 PerfView 的主窗口中,选择“帮助”->“用户指南”。

注意

通过 System.Diagnostics.Tracing.EventSource API 编写的事件(包括 Framework 中的事件)不会显示在其提供程序名称下。 相反,它们被编写为 Microsoft-Windows-DotNETRuntime 提供程序下的 EventSourceEvent 事件,其有效负载是经过 JSON 序列化的。

注意

如果在方法名称和调用堆栈中观察到 [unknown] /memfd:doublemapper 帧,请先设置 DOTNET_EnableWriteXorExecute=0,然后再运行使用 perfcollect 跟踪的应用。

使用 TraceCompass 打开跟踪文件

Eclipse TraceCompass 是另一个可用于查看跟踪的选项。 TraceCompass 也可以在 Linux 计算机上工作,因此不需要将跟踪移到 Windows 计算机上。 要使用 TraceCompass 打开跟踪文件,需要解压缩该文件。

unzip myTrace.trace.zip

perfcollect 将它收集的 LTTng 跟踪保存为 CTF 文件格式,位于 lttngTrace 的子目录中。 具体来说,CTF 文件将位于类似于 lttngTrace/auto-20201025-101230\ust\uid\1000\64-bit\ 的目录中。

可以通过选择 File -> Open Trace 打开 TraceCompass 中的 CTF 跟踪文件,然后选择 metadata 文件。

有关详细信息,请参阅 TraceCompass 文档

获取本机运行时的符号

大多数情况下,你感兴趣的是自己的代码,perfcollect 默认解析这些代码。 有时查看 .NET DLL 内部的情况很有用(这是上一节讨论的内容),但有时查看本机运行时 dll 中的情况(通常为 libcoreclr.so)也很有趣。 perfcollect 在转换其数据时将解析这些符号,但前提是存在这些本机 DLL 的符号(并且位于它们所对应的库的旁边)。

有一个名为 dotnet-symbol 的全局命令可以执行此操作。 使用 dotnet-symbol 获取本机运行时符号:

  1. 安装 dotnet-symbol

    dotnet tool install -g dotnet-symbol
    
  2. 下载符号。 如果你安装的 .NET Core 运行时版本是 2.1.0,则执行此操作的命令是:

    mkdir mySymbols
    dotnet symbol --symbols --output mySymbols  /usr/share/dotnet/shared/Microsoft.NETCore.App/2.1.0/lib*.so
    
  3. 将符号复制到正确的位置。

    sudo cp mySymbols/* /usr/share/dotnet/shared/Microsoft.NETCore.App/2.1.0
    

    如果由于没有对相应目录的写入访问权限而无法完成此操作,可以使用 perf buildid-cache 添加符号。

此后,当你运行 perfcollect 时,应获取本机 dll 的符号名称。

在 Docker 容器中收集信息

有关如何在容器环境中使用 perfcollect 的详细信息,请参阅在容器中收集诊断信息

了解有关集合选项的详细信息

你可以使用 perfcollect 指定以下可选标志,以更好地满足诊断需求。

在特定的时间内收集

如果要收集特定时间内的跟踪,可以使用 -collectsec 选项后跟一个数字,该数字指定收集跟踪的总秒数。

收集线程时间跟踪

使用 perfcollect 指定 -threadtime 可让你收集每个线程的 CPU 使用率数据。 从而分析每个线程将 CPU 时间用在何处。

收集托管内存和垃圾回收器性能的跟踪

以下选项可让你专门收集运行时中的 GC 事件。

  • perfcollect collect -gccollectonly

仅收集一组最少的 GC 收集事件。 这是最不详细的 GC 事件收集配置文件,对目标应用性能的影响最小。 此命令类似于 PerfView 中的 PerfView.exe /GCCollectOnly collect 命令。

  • perfcollect collect -gconly

收集更详细的 GC 收集事件,包括 JIT、加载程序和异常事件。 这会请求更详细的事件(例如分配信息和 GC 联接信息),对目标应用性能产生的影响比 -gccollectonly 选项产生的影响更大。 此命令类似于 PerfView 中的 PerfView.exe /GCOnly collect 命令。

  • perfcollect collect -gcwithheap

收集最详细的 GC 收集事件(用于跟踪堆的存活和移动情况)。 这会对 GC 行为进行深入分析,但会对性能产生较大的影响,因为每个 GC 都可能需要两倍的时间。 建议在生产环境中进行跟踪时,了解使用此跟踪选项的性能影响。