dotnet-inspect-performance

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

dotnet-inspect: performance analysis and triage

dotnet-inspect:性能分析与调优

Use this skill to find the members worth optimizing or hardening first in a .NET assembly, and to triage them against actionable rewrite shapes. This analysis is experimental; section names and signal sets may change between releases.
bash
dnx dotnet-inspect -y -- <command>
使用此工具可在.NET程序集中找到最值得优先优化或强化的成员,并针对可落地的重构模式对它们进行分类调优。本分析功能为实验性;版本迭代中,章节名称和信号集可能会发生变化。
bash
dnx dotnet-inspect -y -- <command>

Rank by leverage first

优先按影响力排名

Top Leverage
ranks members by call-graph leverage: direct callers,
Root Reach
(distinct entry points that transitively reach a member), fanout, depth, and loop calls. Start here on a whole library, then narrow to a type.
bash
dnx dotnet-inspect -y -- library MyLib.dll -S "Top Leverage"
dnx dotnet-inspect -y -- type MyType --library MyLib.dll --all -S "Top Leverage"
Ranking rows carry a copyable
Stable
selector,
Visibility
, and
Selector
. Add
--all
to include non-public members.
Top Leverage
(顶级影响力)根据调用图影响力对成员进行排名:直接调用者、
Root Reach
(可间接访问成员的不同入口点)、扇出数、深度以及循环调用。先针对整个类库进行分析,再缩小到特定类型。
bash
dnx dotnet-inspect -y -- library MyLib.dll -S "Top Leverage"
dnx dotnet-inspect -y -- type MyType --library MyLib.dll --all -S "Top Leverage"
排名行包含可复制的
Stable
选择器、
Visibility
(可见性)和
Selector
(选择器)。添加
--all
参数可包含非公开成员。

Triage against rewrite shapes

针对重构模式进行调优

Library triage is split into kind-scoped sections under
@Performance
(
Performance: Boxing
,
Performance: Arrays
,
Performance: Closures and delegates
, and more). Start with discovery or counts, then select the group or one concrete kind. Type/member scope keeps the focused
Performance Triage
lens.
bash
dnx dotnet-inspect -y -- library MyLib.dll -D @Performance
dnx dotnet-inspect -y -- library MyLib.dll -S @Performance --count
dnx dotnet-inspect -y -- library MyLib.dll -S "Performance: Boxing" --jsonl
dnx dotnet-inspect -y -- library MyLib.dll -S "Performance:*" \
  --loop --min-confidence high --top 20 --tsv
dnx dotnet-inspect -y -- library MyLib.dll \
  --triage-shape scan-method-in-loop-call,linq-scan-in-loop,string-build-in-loop \
  --top 20 --tsv
dnx dotnet-inspect -y -- library MyLib.dll --triage-shape capturing-delegate --top 10 --jsonl
Target IL-visible costs (allocations: box, newarr, delegate newobj, ToArray/ToList/Concat), not JIT-handled concerns (isinst/castclass folding, devirtualization, bounds-check elimination, null-check folding).
Use
--loop
for repeated hot costs,
--min-confidence high|medium|low
for a confidence floor,
--triage-shape
for one or more shapes, and
--top N
for the curated ranked prefix. Supplying any of those flags selects the applicable performance lens automatically. In library row formats,
Performance:*
flattens two or more populated kind sections into one table with a leading
Kind
column. If filtering leaves one populated kind, row formats use that kind's concrete schema without
Kind
; use structured
--json
when the kind discriminator must remain explicit.
@Performance
also includes heterogeneous sections, so use it for discovery, counts, Markdown, or JSON documents instead.
--top
narrows ranked data before rendering;
--rows N
caps rendered rows afterward. Common shapes include
capturing-delegate
,
box-value-type
,
small-array
,
linq-scan-in-loop
,
scan-method-in-loop-call
(a linear-scan helper invoked from a caller loop),
materialize-in-loop
(a loop-invariant
ToArray
/
ToList
that can be hoisted),
string-build-in-loop
,
enumerator-allocation
,
async-state-machine
, and
allocation-hotspot
. Query the algorithmic shapes explicitly:
scan-method-in-loop-call
stays low-confidence because static analysis cannot prove that the scanned sequence grows with the caller's loop, so a
--min-confidence high
pass intentionally excludes it.
For registry, pipeline, or object-graph construction that does not match a local rewrite shape, opt into the aggregate allocation fanout:
bash
dnx dotnet-inspect -y -- library MyLib.dll \
  --triage-shape allocation-fanout \
  --order-by "OncePaths desc" --top 20 --tsv
Direct Sites
is local to the method.
Once Paths
composes exact intra-assembly callsites and counts repeated callsites separately; conditional, repeated, unknown, cached, and opaque paths remain separate columns. Treat this as IL-visible normal-return-path quantity, not runtime bytes or observed frequency. A high
Opaque Paths
count means virtual, external, delegate, recursive, or runtime-library work still needs a drill or profiler.
Exact rows retain machine-readable provenance from the native Analysis producer in structured JSON:
Candidate
,
Finding
(
analysis.allocation
or
analysis.call-site
),
Provenance=exact
,
Operation
,
Token
, and
IL
. Use these fields for runtime/static joins or to carry one triage row into the matching
diff
/
timeline
confirmation workflow without parsing
Evidence
text:
bash
dnx dotnet-inspect -y -- library MyLib.dll -S "Performance:*" \
  --where "Finding=analysis.allocation" --where "Operation=box" --json
dnx dotnet-inspect -y -- library MyLib.dll -S "Performance:*" \
  --where "Finding=analysis.call-site" --json
Aggregate rows such as
allocation-hotspot
use
Provenance=aggregate
and have a
pt~
candidate id but no exact source Finding, operation, or token.
Provenance=unmatched
flags an instruction-level row that did not join to the expected producer census.
类库调优在
@Performance
下按类型划分为不同章节(
Performance: Boxing
Performance: Arrays
Performance: Closures and delegates
等)。先从发现或统计开始,再选择分组或具体类型。类型/成员范围会保持聚焦的
Performance Triage
(性能调优)视角。
bash
dnx dotnet-inspect -y -- library MyLib.dll -D @Performance
dnx dotnet-inspect -y -- library MyLib.dll -S @Performance --count
dnx dotnet-inspect -y -- library MyLib.dll -S "Performance: Boxing" --jsonl
dnx dotnet-inspect -y -- library MyLib.dll -S "Performance:*" \\
  --loop --min-confidence high --top 20 --tsv
dnx dotnet-inspect -y -- library MyLib.dll \\
  --triage-shape scan-method-in-loop-call,linq-scan-in-loop,string-build-in-loop \\
  --top 20 --tsv
dnx dotnet-inspect -y -- library MyLib.dll --triage-shape capturing-delegate --top 10 --jsonl
针对IL可见的开销(分配:装箱、newarr、委托newobj、ToArray/ToList/Concat),而非JIT处理的问题(isinst/castclass折叠、去虚拟化、边界检查消除、空检查折叠)。
使用
--loop
查找重复的热点开销,
--min-confidence high|medium|low
设置置信度下限,
--triage-shape
指定一种或多种模式,
--top N
筛选排名靠前的精选数据。提供上述任一参数会自动选择适用的性能分析视角。在类库行格式中,
Performance:*
会将两个或多个已填充的类型章节合并为一个带有
Kind
(类型)列的表格。如果过滤后仅剩一个已填充的类型,行格式会使用该类型的具体架构,不再显示
Kind
列;当必须明确区分类型时,请使用结构化的
--json
参数。
@Performance
还包含异构章节,因此可将其用于发现、统计、Markdown或JSON文档。
--top
会在渲染前缩小排名数据范围;
--rows N
会在渲染后限制显示的行数。常见模式包括
capturing-delegate
box-value-type
small-array
linq-scan-in-loop
scan-method-in-loop-call
(从调用者循环中调用的线性扫描助手)、
materialize-in-loop
(可提升到循环外的循环不变量
ToArray
/
ToList
)、
string-build-in-loop
enumerator-allocation
async-state-machine
allocation-hotspot
。可显式查询算法模式:
scan-method-in-loop-call
的置信度较低,因为静态分析无法证明扫描序列会随调用者循环增长,因此
--min-confidence high
的筛选会有意排除它。
对于不匹配本地重构模式的注册表、管道或对象图构造,可选择聚合分配扇出:
bash
dnx dotnet-inspect -y -- library MyLib.dll \\
  --triage-shape allocation-fanout \\
  --order-by "OncePaths desc" --top 20 --tsv
Direct Sites
(直接站点)是方法本地的。
Once Paths
(单次路径)组合了精确的程序集内调用站点,并分别统计重复调用站点;条件、重复、未知、缓存和不透明路径仍为单独列。将其视为IL可见的正常返回路径数量,而非运行时字节数或观测频率。
Opaque Paths
(不透明路径)计数较高意味着虚拟、外部、委托、递归或运行时库操作仍需进一步排查或使用分析器。
精确行在结构化JSON中保留了来自原生Analysis生成器的机器可读来源信息:
Candidate
(候选对象)、
Finding
(发现结果,
analysis.allocation
analysis.call-site
)、
Provenance=exact
(来源=精确)、
Operation
(操作)、
Token
(令牌)和
IL
。可使用这些字段进行运行时/静态关联,或将调优行带入匹配的
diff
/
timeline
确认工作流,而无需解析
Evidence
(证据)文本:
bash
dnx dotnet-inspect -y -- library MyLib.dll -S "Performance:*" \\
  --where "Finding=analysis.allocation" --where "Operation=box" --json
dnx dotnet-inspect -y -- library MyLib.dll -S "Performance:*" \\
  --where "Finding=analysis.call-site" --json
聚合行(如
allocation-hotspot
)使用
Provenance=aggregate
(来源=聚合),并带有
pt~
候选ID,但没有精确的来源发现结果、操作或令牌。
Provenance=unmatched
(来源=不匹配)标记未与预期生成器统计数据匹配的指令级行。

Select direct caller-loop repetition

选择直接调用者循环重复情况

A once-per-call allocation can still be repeated by an upstream caller's loop. Select rows with an exact direct invocation receipt:
bash
dnx dotnet-inspect -y -- library MyLib.dll -S "Performance:*" \
  --where "CallerLoop=direct" --json
CallerLoopDepth
and
CallerLoopWitness
identify the deterministic invocation site. This evidence does not change the row's local
Loop
, multiplicity, confidence, weight, candidate identity, or default rank. Use it to select a candidate for profiling, not as proof that the caller is hot or that the loop executes.
Only resolved invocation edges qualify. Function loads and callback registration do not prove callback execution, and recursive traversal does not prove realized depth or frequency. Do not infer either case into caller-loop evidence; require runtime evidence or a stronger product-owned invocation contract.
单次调用的分配仍可能被上游调用者的循环重复执行。选择具有精确直接调用记录的行:
bash
dnx dotnet-inspect -y -- library MyLib.dll -S "Performance:*" \\
  --where "CallerLoop=direct" --json
CallerLoopDepth
(调用者循环深度)和
CallerLoopWitness
(调用者循环证据)用于确定调用站点。此证据不会改变行的本地
Loop
(循环)、多重性、置信度、权重、候选标识或默认排名。可使用它选择候选对象进行分析,但不能作为调用者是热点或循环已执行的证据。
只有已解析的调用边符合条件。函数加载和回调注册不能证明回调已执行,递归遍历也不能证明实际深度或频率。不要将这两种情况推断为调用者循环证据;需要运行时证据或更明确的产品级调用契约。

Triage exception-path pool churn

调优异常路径池消耗

Select the explicit
Resource Triage
library section to find
ArrayPool<T>
acquisitions whose exact def-use path reaches an external-input boundary before modeled cleanup:
bash
dnx dotnet-inspect -y -- library MyLib.dll -S "Resource Triage" --jsonl
Treat
pool-churn-on-exception
as a profiling and hardening candidate, not a permanent-memory-leak or memory-corruption accusation. Static analysis proves the unprotected boundary shape and API evidence, not runtime frequency. Use
Candidate
,
Finding=analysis.resource-lifecycle
,
Acquire IL
,
Boundary IL
, and
Boundary
to retain exact provenance while drilling the method. Each boundary is one row; a multi-boundary candidate repeats its candidate and acquisition fields so every operation stays paired with its own IL offset.
Not every shape is a pure hot-path win.
async-state-machine
is reported as amortized (low confidence) unless the allocation sits in a loop: async lowering moves work into a state object rather than eliminating it, often once per call/enumeration/subscription. Treat amortized rows as context, and confirm a real per-item cost with a profiler before optimizing.
选择显式的
Resource Triage
(资源调优)类库章节,可找到
ArrayPool<T>
获取操作中,其精确的定义-使用路径在模型化清理前到达外部输入边界的情况:
bash
dnx dotnet-inspect -y -- library MyLib.dll -S "Resource Triage" --jsonl
pool-churn-on-exception
视为分析和强化的候选对象,而非永久内存泄漏或内存损坏的指控。静态分析可证明未受保护的边界模式和API证据,但无法证明运行时频率。使用
Candidate
Finding=analysis.resource-lifecycle
Acquire IL
(获取IL)、
Boundary IL
(边界IL)和
Boundary
(边界)在排查方法时保留精确来源信息。每个边界对应一行;多边界候选对象会重复其候选和获取字段,以便每个操作都与自己的IL偏移量配对。
并非所有模式都能直接提升热点路径性能。
async-state-machine
(异步状态机)会被报告为摊销(低置信度),除非分配位于循环中:异步降级会将工作转移到状态对象中,而非消除它,通常每次调用/枚举/订阅发生一次。将摊销行视为上下文信息,在优化前需使用分析器确认实际的每项成本。

Confirm when an allocation appeared

确认分配出现的时间

Correlate one method's native allocation census across caller-selected package cells:
bash
dnx dotnet-inspect -y -- timeline --package MyLib@1.0.0..2.0.0 \
  -t MyType -m HotPath \
  --finding analysis.allocation --at first --at last
Repeat
--at
for sparse probes or use
--at all
for an explicitly bounded dense traversal. These probes locate a candidate old/new boundary; they do not establish onset. Confirm one method's adjacent pair with Analysis's native allocation Findings:
bash
dnx dotnet-inspect -y -- diff --package MyLib@1.4.0..1.5.0 \
  -t MyType -m HotPath \
  --finding analysis.allocation
The method target must resolve at one or both endpoints.
PairFinding.Added
confirms an allocation occurrence was introduced, while
Present
,
Removed
, and
Changed
identify a wrong boundary, disappearance, or changed allocation facets. The command does not traverse versions; the caller owns the search policy and bound.
在调用者选择的包版本范围内关联某方法的原生分配统计数据:
bash
dnx dotnet-inspect -y -- timeline --package MyLib@1.0.0..2.0.0 \\
  -t MyType -m HotPath \\
  --finding analysis.allocation --at first --at last
重复使用
--at
进行稀疏探测,或使用
--at all
进行明确边界的密集遍历。这些探测用于定位候选对象的新旧边界;但无法确定起始时间。使用Analysis的原生分配发现结果确认某方法的相邻版本对:
bash
dnx dotnet-inspect -y -- diff --package MyLib@1.4.0..1.5.0 \\
  -t MyType -m HotPath \\
  --finding analysis.allocation
目标方法必须在一个或两个端点解析。
PairFinding.Added
(配对发现结果:新增)确认分配已引入,而
Present
(存在)、
Removed
(移除)和
Changed
(变更)则标识错误边界、消失或分配方面的变更。该命令不会遍历版本;调用者需自行制定搜索策略和边界。

Trace a likely cause to a new call

追踪可能的原因到新调用

After confirming an allocation boundary, compare the same caller method's direct-call census:
bash
dnx dotnet-inspect -y -- diff --package MyLib@1.4.0..1.5.0 \
  -t MyType -m HotPath \
  --finding analysis.call-site
The target method is the caller and each row identifies a callee.
PairFinding.Added
confirms a new call occurrence, such as a newly introduced
Enumerable.ToArray
.
Changed
can show that an existing call moved into a loop or changed dispatch/opcode facets. Use the single-version
Calls
section while probing versions; use this final adjacent comparison as the onset proof.
确认分配边界后,比较同一调用者方法的直接调用统计数据:
bash
dnx dotnet-inspect -y -- diff --package MyLib@1.4.0..1.5.0 \\
  -t MyType -m HotPath \\
  --finding analysis.call-site
目标方法是调用者,每行标识一个被调用者。
PairFinding.Added
确认新调用已引入,例如新添加的
Enumerable.ToArray
Changed
可显示现有调用已移入循环或调度/操作码方面已变更。在探测版本时使用单版本的
Calls
(调用)章节;使用此最终相邻比较作为起始证明。

Drill a candidate

排查候选对象

Call Graph
is a bounded bidirectional graph: inbound callers up to entry points and outbound calls, centred on the selected member. Project per-node cost with
--fields
(alloc, copy, unsafe, reflection, throw/exception, catch/finally). Its default Markdown edge table is best for comparing relationships and cost cues. Use
--tree
when the path toward or away from the candidate matters,
--mermaid
for a standalone diagram, or
--markdown --mermaid
to embed the diagram. Use
--tsv
or
--jsonl
when a script will consume the same edge rows. Requested cost cues remain annotations in the node labels; they do not become separate machine columns.
bash
dnx dotnet-inspect -y -- member MyType Method:1 --library MyLib.dll -S "Call Graph,Facts"
dnx dotnet-inspect -y -- member MyType Method:1 --library MyLib.dll -S "Call Graph" --fields "Throw,Catch,Finally"
dnx dotnet-inspect -y -- member MyType Method:1 --library MyLib.dll -S "Call Graph" --fields "Alloc,Loop" --tree
dnx dotnet-inspect -y -- member MyType Method:1 --library MyLib.dll -S "Call Graph" --jsonl
Call Graph
(调用图)是一个有界双向图:以所选成员为中心,包含向上到入口点的入站调用者和出站调用。使用
--fields
(分配、复制、不安全、反射、抛出/异常、捕获/finally)展示每个节点的成本。其默认的Markdown边表最适合比较关系和成本线索。当候选对象的路径方向很重要时使用
--tree
,使用
--mermaid
生成独立图表,或使用
--markdown --mermaid
嵌入图表。当脚本需要使用相同的边行时,使用
--tsv
--jsonl
。请求的成本线索会保留在节点标签中作为注释;不会成为单独的机器列。
bash
dnx dotnet-inspect -y -- member MyType Method:1 --library MyLib.dll -S "Call Graph,Facts"
dnx dotnet-inspect -y -- member MyType Method:1 --library MyLib.dll -S "Call Graph" --fields "Throw,Catch,Finally"
dnx dotnet-inspect -y -- member MyType Method:1 --library MyLib.dll -S "Call Graph" --fields "Alloc,Loop" --tree
dnx dotnet-inspect -y -- member MyType Method:1 --library MyLib.dll -S "Call Graph" --jsonl
```",