-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Add devdocs on fixing precompile hangs #50914
Closed
Closed
Changes from 4 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
813dc37
Add devdocs on fixing precompile hangs
timholy d395d08
crop the screenshot
timholy ead2903
clarify commenting
timholy 6284153
Add infrastructure for hang-on-exit
timholy c0d99cf
wait_task -> kill_tasks
timholy b557a0f
Improve docs
timholy 1465235
Add a test
timholy File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
timholy marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
# Fixing precompilation hangs due to open tasks or IO | ||
|
||
On Julia 1.10 or higher, you might see the following message: | ||
|
||
![Screenshot of precompilation hang](./img/precompilation_hang.png) | ||
|
||
If you follow the advice and hit `Ctrl-C`, you might see | ||
|
||
``` | ||
^C Interrupted: Exiting precompilation... | ||
|
||
1 dependency had warnings during precompilation: | ||
┌ Test1 [ac89d554-e2ba-40bc-bc5c-de68b658c982] | ||
│ [pid 2745] waiting for IO to finish: | ||
│ TYPE[FD/PID] @UV_HANDLE_T->DATA | ||
│ timer @0x55580decd1e0->0x7f94c3a4c340 | ||
``` | ||
|
||
and, depending on how long you waited, this may repeat. | ||
|
||
This message conveys two key pieces of information: | ||
|
||
- the hang is occurring during precompilation of `Test1`, a dependency of `Test2` (the package we were trying to load with `using Test2`) | ||
- during precompilation of `Test1`, Julia created a `Timer` object (use `?Timer` if you're unfamiliar with Timers) which is still open; until that closes, the process is hung | ||
|
||
If this is enough of a hint for you to figure out how that `Timer` object is being created, one good solution is to `close(obj::Timer)` before the final `end` of the module. | ||
timholy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
However, there are cases that may not be that straightforward. Usually the best option is to start by determining whether the hang is due to code in Test1 or whether it is due to one of Test1's dependencies: | ||
timholy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
1. `Pkg.develop("Test1")` | ||
2. Comment out all the code `include`d or defined in `Test1`, *except* the `using/import` statements | ||
3. Try `using Test2` (or even `using Test1` assuming that hangs too) again | ||
|
||
Now we arrive at a fork in the road: either | ||
|
||
- the hang persists, indicating it is due to one of your dependencies | ||
- the hang disappears, indicating that it is due to something in your code | ||
|
||
## If the hang is due to a package dependency | ||
|
||
Use a binary search to identify the problematic dependency: start by commenting out half your dependencies, then when you isolate which half is responsible comment out half of that half, etc. (You don't have to remove them from the project, just comment out the `using`/`import` statements.) | ||
|
||
Once you've identified a suspect (here we'll call it `ThePackageYouThinkIsCausingTheProblem`), first try precompiling that package. If it also hangs during precompilation, continue chasing the problem backwards. | ||
|
||
However, most likely `ThePackageYouThinkIsCausingTheProblem` will precompile fine. This suggests it's in the function `ThePackageYouThinkIsCausingTheProblem.__init__`, which does not run during precompilation of `ThePackageYouThinkIsCausingTheProblem` but *does* in any package that loads `ThePackageYouThinkIsCausingTheProblem`. To test this theory, set up a minimal working example (MWE), something like | ||
|
||
```julia | ||
(@v1.10) pkg> generate MWE | ||
Generating project MWE: | ||
MWE\Project.toml | ||
MWE\src\MWE.jl | ||
``` | ||
|
||
where the source code of `MWE.jl` is | ||
|
||
```julia | ||
module MWE | ||
using ThePackageYouThinkIsCausingTheProblem | ||
end | ||
``` | ||
|
||
and you've added `ThePackageYouThinkIsCausingTheProblem` to MWE's dependencies. | ||
|
||
If that MWE reproduces the hang, you've found your culprit: | ||
`ThePackageYouThinkIsCausingTheProblem.__init__` must be creating the `Timer` object. If the timer object can be safely `close`d, that's a good option. Otherwise, the most common solution is to avoid creating the timer while *any* package is being precompiled: add | ||
|
||
```julia | ||
ccall(:jl_generating_output, Cint, ()) == 1 && return nothing | ||
``` | ||
|
||
as the first line of `ThePackageYouThinkIsCausingTheProblem.__init__`, and it will avoid doing any initialization in any Julia process whose purpose is to precompile packages. | ||
|
||
## If the hang is in your code | ||
|
||
Search your package for suggestive words (here like "Timer") and see if you can identify where the problem is being created. Note that a method *definition* like | ||
|
||
```julia | ||
maketimer() = Timer(timer -> println("hi"), 0; interval=1) | ||
``` | ||
|
||
is not problematic in and of itself: it can cause this problem only if `maketimer` gets called while the module is being defined. This might be happening from a top-level statement such as | ||
|
||
```julia | ||
const GLOBAL_TIMER = maketimer() | ||
``` | ||
|
||
or it might conceivably occur in a [precomile workload](https://github.com/JuliaLang/PrecompileTools.jl). | ||
timholy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
If you struggle to identify the causative lines, then consider doing a binary search: comment out sections of your package (or `include` lines to omit entire files) until you've reduced the problem in scope. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
naming bikeshedding time: should we say this is
exit(0, process=true)
, since it specifies whether this call just kills this task or all tasks?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went with
kill_tasks=true
.