debug profile
for debug
Signature
> debug profile {flags} (closure)
Flags
--spans, -s
: Collect spans of profiled elements--expand-source, -e
: Collect full source fragments of profiled elements--values, -v
: Collect pipeline element output values--lines, -l
: Collect line numbers--max-depth, -m {int}
: How many blocks/closures deep to step into (default 2)
Parameters
closure
: The closure to profile.
Input/output types:
input | output |
---|---|
any | table |
Examples
Profile config evaluation
> debug profile { source $nu.config-path }
Profile config evaluation with more granularity
> debug profile { source $nu.config-path } --max-depth 4
Notes
The profiler profiles every evaluated instruction inside a closure, stepping into all commands calls and other blocks/closures.
The output can be heavily customized. By default, the following columns are included:
- depth : Depth of the instruction. Each entered block adds one level of depth. How many blocks deep to step into is controlled with the --max-depth option.
- id : ID of the instruction
- parent_id : ID of the instruction that created the parent scope
- source : Source code that generated the instruction. If the source code has multiple lines, only the first line is used and
...
is appended to the end. Full source code can be shown with the --expand-source flag. - pc : The index of the instruction within the block.
- instruction : The pretty printed instruction being evaluated.
- duration_ms : How long it took to run the instruction in milliseconds.
- (optional) span : Span associated with the instruction. Can be viewed via the
view span
command. Enabled with the --spans flag. - (optional) output : The output value of the instruction. Enabled with the --values flag.
To illustrate the depth and IDs, consider debug profile { do { if true { echo 'spam' } } }
. A unique ID is generated each time an instruction is executed, and there are two levels of depth:
depth id parent_id source pc instruction
0 0 0 debug profile { do { if true { 'spam' } } } 0 <start>
1 1 0 { if true { 'spam' } } 0 load-literal %1, closure(2164)
1 2 0 { if true { 'spam' } } 1 push-positional %1
1 3 0 { do { if true { 'spam' } } } 2 redirect-out caller
1 4 0 { do { if true { 'spam' } } } 3 redirect-err caller
1 5 0 do 4 call decl 7 "do", %0
2 6 5 true 0 load-literal %1, bool(true)
2 7 5 if 1 not %1
2 8 5 if 2 branch-if %1, 5
2 9 5 'spam' 3 load-literal %0, string("spam")
2 10 5 if 4 jump 6
2 11 5 { if true { 'spam' } } 6 return %0
1 12 0 { do { if true { 'spam' } } } 5 return %0
Each block entered increments depth by 1 and each block left decrements it by one. This way you can control the profiling granularity. Passing --max-depth=1 to the above would stop inside the do
at if true { 'spam' }
. The id is used to identify each element. The parent_id tells you that the instructions inside the block are being executed because of do
(5), which in turn was spawned from the root debug profile { ... }
.
For a better understanding of how instructions map to source code, see the view ir
command.
Note: In some cases, the ordering of pipeline elements might not be intuitive. For example, [ a bb cc ] | each { $in | str length }
involves some implicit collects and lazy evaluation confusing the id/parent_id hierarchy. The --expr flag is helpful for investigating these issues.