查看用于 .NET 的 Application Insights Profiler 数据
假设要运行 Web 性能测试。 需要借助跟踪来了解 Web 应用在承受负载情况下的运行性能。 在本文中,你将:
- 通过启动 Web 性能测试或启动 Profiler 按需会话来为 Web 应用生成流量。
- 在负载测试或 Profiler 会话后查看 Profiler 跟踪。
- 了解如何读取 Profiler 性能数据和调用堆栈。
为 Azure 服务生成流量
要使 .NET Profiler 上传跟踪,服务必须主动处理请求。
如果 Azure 服务已有传入流量,或者只想手动生成流量,请跳过负载测试并启动 Profiler 按需会话:
在 Azure 服务的“Application Insights 概述”页中,从左侧菜单中选择“性能”。
在性能窗格中,从 Profiler 设置的顶部菜单中选择 Profiler。
加载 Profiler 设置页面后,选择立即配置文件。
查看跟踪
跟踪浏览器会显示以下信息:
筛选器 | 说明 |
---|---|
配置文件树 v. 火焰图 | 以树形式或图形形式查看跟踪。 |
热路径 | 选择以打开最大的叶节点。 大多数情况下,此节点与性能瓶颈相邻。 |
框架依赖项 | 选择以查看与跟踪关联的每个跟踪框架依赖项。 |
隐藏事件 | 键入要从跟踪视图中隐藏的字符串。 为建议选择“建议”事件 。 |
事件 | 事件或函数名称。 树中显示了代码与发生的事件(例如 SQL 和 HTTP 事件)的混合形式。 最前面的事件表示请求总持续时间。 |
模块 | 发生跟踪事件或函数的模块。 |
线程时间 | 从操作开始到操作结束之间的时间间隔。 |
时间线 | 运行函数或事件的时间,此值相对于运行其他函数的时间。 |
如何读取性能数据
.NET Profiler 结合使用采样方法和检测来分析应用程序的性能。 在执行详细收集时,.NET Profiler:
- 每毫秒对每个计算机 CPU 的指令指针进行采样。
- 每个样本都捕获了线程的整个调用堆栈,其中提供了高层和底层抽象的详细信息。
- 收集事件以跟踪活动关联和因果关系,包括:
- 上下文切换事件
- 任务并行库 (TPL) 事件
- 线程池事件
时间线视图中显示的调用堆栈是采样和检测的结果。 由于每个样本会捕获线程的整个调用堆栈,因此包含 Microsoft .NET Framework 中的代码,以及引用的任何其他框架中的代码。
对象分配 (clr!JIT_New or clr!JIT_Newarr1)
clr!JIT_New 和 clr!JIT_Newarr1 是 .NET Framework 中的 helper 函数,用于分配托管堆中的内存。
- 分配对象时,将调用 clr!JIT_New。
- 分配对象数组时,将调用 clr!JIT_Newarr1。
这两个函数通常可快速工作。 如果时间线中的 clr!JIT_New 或 clr!JIT_Newarr1 花费了时间,则可能表示代码分配了很多对象,从而消耗了大量的内存。
加载代码 (clr!ThePreStub)
Clr!ThePreStub 是 .NET Framework 中的帮助程序函数,用于准备初始执行的代码,通常包括实时 (JIT) 编译。 对于每个 C# 方法,在进程的生存期内,最多只应调用 clr!ThePreStub 一次。
如果 clr!ThePreStub 针对某个请求花费了额外的时间,则表示这是第一个执行该方法的请求。 .NET Framework 运行时需要大量时间来加载第一个方法。 请注意以下几点:
- 在用户访问该代码部分之前使用执行该代码部分的预热进程。
- 在程序集上运行本机映像生成器 (ngen.exe)。
锁争用 (clr!JITutil_MonContention or clr!JITutil_MonEnterWorker)
clr!JITutil_MonContention 或 clr!JITutil_MonEnterWorker 指示当前线程正在等待释放锁。 此文本通常在以下情况下显示:
- 执行 C# LOCK 语句,
- 调用 Monitor.Enter 方法,或
- 使用 MethodImplOptions.Synchronized 属性调用方法。
如果线程 A 获取了某个锁,而线程 B 在线程 A 释放该锁之前尝试获取同一个锁,此时通常会发生锁争用。
加载代码 ([COLD])
如果 .NET Framework 运行时首次执行未优化的代码,则方法名称将包含 [COLD]:
mscorlib.ni![COLD]System.Reflection.CustomAttribute.IsDefined
对于每个方法,在进程的生存期内,它最多只应显示一次。
如果针对某个请求加载代码花费的时间很长,则表示这是第一个执行该方法的未优化部分的请求。 请考虑在用户访问该代码部分之前使用执行该代码部分的预热进程。
发送 HTTP 请求
HttpClient.Send 等方法指示代码正在等待某个 HTTP 请求完成。
数据库操作
SqlCommand.Execute 等方法指示代码正在等待某个数据库操作完成。
等待 (AWAIT_TIME)
AWAIT_TIME 指示代码正在等待另一个任务完成。 这种延迟会发生在 C# AWAIT 语句上。 当代码执行 C# AWAIT 时:
- 线程展开并将控制权返回到线程池。
- 没有阻止的线程等待 AWAIT 完成。
但是,从逻辑上讲,执行 AWAIT 的线程会被“阻止”,等待该操作完成。 AWAIT_TIME 语句指示等待任务完成的阻止时间。
如果“AWAIT_TIME”显示为框架代码而不是你的代码,则 .NET Profiler 可能会显示:
- 用于执行“AWAIT”的框架代码
- 用于记录有关“AWAIT”的遥测数据的代码
可以取消选中页面顶部的“框架依赖项”复选框,以便仅显示你的代码且更轻松地查看“AWAIT”的来源。
阻塞时间
BLOCKED_TIME 指示代码正在等待另一个资源变为可用。 例如,它可能在等待:
- 同步对象
- 要可用的线程
- 完成请求
非托管异步
为了跨线程跟踪异步调用,.NET Framework 会发出 ETW 事件并在线程之间传递活动 ID。 由于非托管(本机)代码和某些较旧的异步代码样式缺少这些事件和活动 ID,因此 .NET Profiler 无法跟踪线程和线程上运行的函数。 此项在调用堆栈中标记为“非托管异步”。 下载 ETW 文件以使用 PerfView 获取更多见解。
CPU 时间
CPU 正忙于执行指令。
磁盘时间
应用程序正在执行磁盘操作。
网络时间
应用程序正在执行网络操作。
“时间”列
“时间”列是针对节点收集的各种“非独占”样本随时间发生的可视化效果。 请求的总范围被划分为 32 个时间段,节点的非独占样本在其中累积。 每个存储桶用一个条形表示。 条形的高度表示缩放后的值。 对于以下节点,条表示存储桶中某个资源的消耗量:
- 标记为 CPU_TIME 或 BLOCKED_TIME 的节点。
- 与使用资源 ((例如 CPU、磁盘或线程) )具有明显关系的节点。
如果消耗多个资源,这些指标的值可能大于 100%。 例如,如果在某个时间间隔内平均使用两个 CPU,则指标值为 200%。
后续步骤
了解如何...