Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Explicit that calls to external methods should be traced back to MyPackage #43

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,17 @@ that were called by runtime dispatch. Thus, here you could have gotten the same
The key advantage of `@compile_workload` is that it works even if the functions you're calling
have runtime dispatch.

!!! warning
If you want to manually precompile methods defined in *other* packages, you must ensure that the corresponding calls are
made in a method belonging to `MyPackage`, otherwise these calls will not be captured during precompilation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not true, and indeed it's the main reason for the existence of PrecompileTools.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am observing this behavior though, which motivated the PR. Perhaps that is a bug?

The case I stumbled upon was with this precompilation workload on a dummy package:

module TestPackage

using Meshes # package for which to precompile methods
using PrecompileTools

function workload()
  geometry = PolyArea((0, 0), (1, 0), (1, 1), (1, 0))
  simplexify(geometry)
end

@compile_workload begin
  workload()
end

end # module

Essentially, with the workload() function indirection, I get correct precompilation:

julia> using TestPackage

julia> using Test

julia> @time @eval TestPackage.simplexify(TestPackage.PolyArea((0, 0), (1, 0), (1, 1), (1, 0)))
  0.002689 seconds (1.39 k allocations: 64.922 KiB, 91.12% compilation time)

While having an "inline" workload as

@compile_workload begin
  geometry = PolyArea((0, 0), (1, 0), (1, 1), (1, 0))
  simplexify(geometry)
end

does not seem to retain compilation results:

julia> @time @eval TestPackage.simplexify(TestPackage.PolyArea((0, 0), (1, 0), (1, 1), (1, 0)))
  4.072428 seconds (40.46 M allocations: 1.983 GiB, 3.30% gc time, 99.99% compilation time)

Should I file an issue about that? If the function indirection should not be necessary, I can remove that doc change and we can merge the other renamings.

Once you set up a block using `PrecompileTools`, try your package and see if it reduces the time to first execution,
using the same workload you put inside the `@compile_workload` block.

If you're happy with the results, you're done! If you want deeper verification of whether it worked as
expected, or if you suspect problems, the [SnoopCompile package](https://github.com/timholy/SnoopCompile.jl) provides diagnostic tools.
Potential sources of trouble include invalidation (diagnosed with `SnoopCompileCore.@snoopr` and related tools)
and omission of intended calls from inside the `@compile_workload` block (diagnosed with `SnoopCompileCore.@snoopi_deep` and related tools).
Potential sources of trouble include invalidation (diagnosed with `SnoopCompileCore.@snoop_invalidations` and related tools)
and omission of intended calls from inside the `@compile_workload` block (diagnosed with `SnoopCompileCore.@snoop_inference` and related tools).

!!! note
`@compile_workload` works by monitoring type-inference. If the code was already inferred
Expand All @@ -81,7 +85,7 @@ and omission of intended calls from inside the `@compile_workload` block (diagno

You can use multiple `@compile_workload` blocks if you need to interleave `@setup_workload` code with
code that you want precompiled.
You can use `@snoopi_deep` to check for any (re)inference when you use the code in your package.
You can use `@snoop_inference` to check for any (re)inference when you use the code in your package.
To fix any specific problems, you can combine `@compile_workload` with manual `precompile` directives.

## Tutorial: local "Startup" packages
Expand Down Expand Up @@ -226,7 +230,7 @@ In that case, your best option is to fall back on Julia's own `precompile` funct
However, as explained in [How PrecompileTools works](@ref), there are some differences between `precompile` and `@compile_workload`;
most likely, you may need multiple `precompile` directives.
Analysis with [SnoopCompile](https://github.com/timholy/SnoopCompile.jl) may be required to obtain the results you want;
in particular, combining `@snoopi_deep` and `parcel` will allow you to generate a set of `precompile` directives that can be `include`d in your module definition.
in particular, combining `@snoop_inference` and `parcel` will allow you to generate a set of `precompile` directives that can be `include`d in your module definition.

Be aware that `precompile` directives are more specific to the Julia version, CPU (integer width), and OS than running a workload.

Expand Down
Loading