查看用于 .NET 的 Application Insights Profiler 数据
假设要运行 Web 性能测试。 需要借助跟踪来了解 Web 应用在承受负载情况下的运行性能。 在本文中,你将:
- 通过启动 Web 性能测试或启动 Profiler 按需会话来为 Web 应用生成流量。
- 在负载测试或 Profiler 会话后查看 Profiler 跟踪。
- 了解如何读取 Profiler 性能数据和调用堆栈。
要使 .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 和 clr!JIT_Newarr1 是 .NET Framework 中的 helper 函数,用于分配托管堆中的内存。
- 分配对象时,将调用 clr!JIT_New。
- 分配对象数组时,将调用 clr!JIT_Newarr1。
这两个函数通常可快速工作。 如果时间线中的 clr!JIT_New 或 clr!JIT_Newarr1 花费了时间,则可能表示代码分配了很多对象,从而消耗了大量的内存。
Clr!ThePreStub 是 .NET Framework 中的帮助程序函数,用于准备初始执行的代码,通常包括实时 (JIT) 编译。 对于每个 C# 方法,在进程的生存期内,最多只应调用 clr!ThePreStub 一次。
如果 clr!ThePreStub 针对某个请求花费了额外的时间,则表示这是第一个执行该方法的请求。 .NET Framework 运行时需要大量时间来加载第一个方法。 请注意以下几点:
- 在用户访问该代码部分之前使用执行该代码部分的预热进程。
- 在程序集上运行本机映像生成器 (ngen.exe)。
clr!JITutil_MonContention 或 clr!JITutil_MonEnterWorker 指示当前线程正在等待释放锁。 此文本通常在以下情况下显示:
- 执行 C# LOCK 语句,
- 调用 Monitor.Enter 方法,或
- 使用 MethodImplOptions.Synchronized 属性调用方法。
如果线程 A 获取了某个锁,而线程 B 在线程 A 释放该锁之前尝试获取同一个锁,此时通常会发生锁争用。
如果 .NET Framework 运行时首次执行未优化的代码,则方法名称将包含 [COLD]:
mscorlib.ni![COLD]System.Reflection.CustomAttribute.IsDefined
对于每个方法,在进程的生存期内,它最多只应显示一次。
如果针对某个请求加载代码花费的时间很长,则表示这是第一个执行该方法的未优化部分的请求。 请考虑在用户访问该代码部分之前使用执行该代码部分的预热进程。
HttpClient.Send 等方法指示代码正在等待某个 HTTP 请求完成。
SqlCommand.Execute 等方法指示代码正在等待某个数据库操作完成。
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 正忙于执行指令。
应用程序正在执行磁盘操作。
应用程序正在执行网络操作。
“时间”列是针对节点收集的各种“非独占”样本随时间发生的可视化效果。 请求的总范围被划分为 32 个时间段,节点的非独占样本在其中累积。 每个存储桶用一个条形表示。 条形的高度表示缩放后的值。 对于以下节点,条表示存储桶中某个资源的消耗量:
- 标记为 CPU_TIME 或 BLOCKED_TIME 的节点。
- 与使用资源 ((例如 CPU、磁盘或线程) )具有明显关系的节点。
如果消耗多个资源,这些指标的值可能大于 100%。 例如,如果在某个时间间隔内平均使用两个 CPU,则指标值为 200%。
了解如何...