Skip to content

Commit

Permalink
Rearrange allocation profiling in Julia manual (JuliaLang#48713)
Browse files Browse the repository at this point in the history
As mentioned in JuliaLang#48070, the allocation profiler now provides better functionality than the `--track-allocation` option. This rearranges the sections in the manual to reflect this, and adds a note to that effect.

It also mentions ProfileCanvas.jl, which seems to be better supported than PProf.jl.
  • Loading branch information
simonbyrne committed Apr 25, 2023
1 parent 3db036e commit bc5dd53
Showing 1 changed file with 35 additions and 25 deletions.
60 changes: 35 additions & 25 deletions doc/src/manual/profile.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ One "family" of visualizers is based on [FlameGraphs.jl](https://github.com/timh
- [StatProfilerHTML.jl](https://github.com/tkluck/StatProfilerHTML.jl) produces HTML and presents some additional summaries, and also integrates well with Jupyter notebooks
- [ProfileSVG.jl](https://github.com/timholy/ProfileSVG.jl) renders SVG
- [PProf.jl](https://github.com/JuliaPerf/PProf.jl) serves a local website for inspecting graphs, flamegraphs and more
- [ProfileCanvas.jl](https://github.com/pfitzseb/ProfileCanvas.jl) is a HTML canvas based profile viewer UI, used by the [Julia VS Code extension](https://www.julia-vscode.org/), but can also generate interactive HTML files.

An entirely independent approach to profile visualization is [PProf.jl](https://github.com/vchuravy/PProf.jl), which uses the external `pprof` tool.

Expand Down Expand Up @@ -308,26 +309,6 @@ and specific lines triggering allocation can often be inferred from profiling vi
collection that these lines incur. However, sometimes it is more efficient to directly measure
the amount of memory allocated by each line of code.

### Line-by-Line Allocation Tracking

To measure allocation line-by-line, start Julia with the `--track-allocation=<setting>` command-line
option, for which you can choose `none` (the default, do not measure allocation), `user` (measure
memory allocation everywhere except Julia's core code), or `all` (measure memory allocation at
each line of Julia code). Allocation gets measured for each line of compiled code. When you quit
Julia, the cumulative results are written to text files with `.mem` appended after the file name,
residing in the same directory as the source file. Each line lists the total number of bytes
allocated. The [`Coverage` package](https://github.com/JuliaCI/Coverage.jl) contains some elementary
analysis tools, for example to sort the lines in order of number of bytes allocated.

In interpreting the results, there are a few important details. Under the `user` setting, the
first line of any function directly called from the REPL will exhibit allocation due to events
that happen in the REPL code itself. More significantly, JIT-compilation also adds to allocation
counts, because much of Julia's compiler is written in Julia (and compilation usually requires
memory allocation). The recommended procedure is to force compilation by executing all the commands
you want to analyze, then call [`Profile.clear_malloc_data()`](@ref) to reset all allocation counters.
Finally, execute the desired commands and quit Julia to trigger the generation of the `.mem`
files.

### GC Logging

While [`@time`](@ref) logs high-level stats about memory usage and garbage collection over the course
Expand All @@ -337,17 +318,20 @@ and how much garbage it collects each time. This can be enabled with
[`GC.enable_logging(true)`](@ref), which causes Julia to log to stderr every time
a garbage collection happens.

### Allocation Profiler
### [Allocation Profiler](@id allocation-profiler)

!!! compat "Julia 1.8"
This functionality requires at least Julia 1.8.

The allocation profiler records the stack trace, type, and size of each
allocation while it is running. It can be invoked with
[`Profile.Allocs.@profile`](@ref).

This information about the allocations is returned as an array of `Alloc`
objects, wrapped in an `AllocResults` object. The best way to visualize
these is currently with the [PProf.jl](https://github.com/JuliaPerf/PProf.jl)
package, which can visualize the call stacks which are making the most
allocations.
objects, wrapped in an `AllocResults` object. The best way to visualize these is
currently with the [PProf.jl](https://github.com/JuliaPerf/PProf.jl) and
[ProfileCanvas.jl](https://github.com/pfitzseb/ProfileCanvas.jl) packages, which
can visualize the call stacks which are making the most allocations.

The allocation profiler does have significant overhead, so a `sample_rate`
argument can be passed to speed it up by making it skip some allocations.
Expand All @@ -364,6 +348,32 @@ Passing `sample_rate=1.0` will make it record everything (which is slow);
You can read more about the missing types and the plan to improve this, here:
[issue #43688](https://github.com/JuliaLang/julia/issues/43688).

#### Line-by-Line Allocation Tracking

An alternative way to measure allocations is to start Julia with the `--track-allocation=<setting>` command-line
option, for which you can choose `none` (the default, do not measure allocation), `user` (measure
memory allocation everywhere except Julia's core code), or `all` (measure memory allocation at
each line of Julia code). Allocation gets measured for each line of compiled code. When you quit
Julia, the cumulative results are written to text files with `.mem` appended after the file name,
residing in the same directory as the source file. Each line lists the total number of bytes
allocated. The [`Coverage` package](https://github.com/JuliaCI/Coverage.jl) contains some elementary
analysis tools, for example to sort the lines in order of number of bytes allocated.

In interpreting the results, there are a few important details. Under the `user` setting, the
first line of any function directly called from the REPL will exhibit allocation due to events
that happen in the REPL code itself. More significantly, JIT-compilation also adds to allocation
counts, because much of Julia's compiler is written in Julia (and compilation usually requires
memory allocation). The recommended procedure is to force compilation by executing all the commands
you want to analyze, then call [`Profile.clear_malloc_data()`](@ref) to reset all allocation counters.
Finally, execute the desired commands and quit Julia to trigger the generation of the `.mem`
files.

!!! note

`--track-allocation` changes code generation to log the allocations, and so the allocations may
be different than what happens without the option. We recommend using the
[allocation profiler](@ref allocation-profiler) instead.

## External Profiling

Currently Julia supports `Intel VTune`, `OProfile` and `perf` as external profiling tools.
Expand Down

0 comments on commit bc5dd53

Please sign in to comment.