-
-
Notifications
You must be signed in to change notification settings - Fork 270
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
Parallelize Pkg.precompile #2018
Changes from 3 commits
9937dea
6fb919d
4708b59
5b0e5ac
7b98298
4b2eef4
84697d7
8f73605
2b1379e
10cbdc0
a4bdd79
52ef225
ab03371
22c4687
dd0ad54
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -895,14 +895,22 @@ end | |
precompile() = precompile(Context()) | ||
function precompile(ctx::Context) | ||
printpkgstyle(ctx, :Precompiling, "project...") | ||
|
||
man = Pkg.Types.read_manifest(ctx.env.manifest_file) | ||
pkgids = [Base.PkgId(first(dep), last(dep).name) for dep in man if !Pkg.Operations.is_stdlib(first(dep))] | ||
pkg_dep_lists = [collect(keys(last(dep).deps)) for dep in man if !Pkg.Operations.is_stdlib(first(dep))] | ||
filter!.(!Pkg.Operations.is_stdlib, pkg_dep_lists) | ||
|
||
pkgids = [Base.PkgId(uuid, name) for (name, uuid) in ctx.env.project.deps if !is_stdlib(uuid)] | ||
if ctx.env.pkg !== nothing && isfile( joinpath( dirname(ctx.env.project_file), "src", ctx.env.pkg.name * ".jl") ) | ||
push!(pkgids, Base.PkgId(ctx.env.pkg.uuid, ctx.env.pkg.name)) | ||
end | ||
push!(pkg_dep_lists, collect(keys(ctx.env.project.deps))) | ||
end | ||
|
||
precomp_list = String[] | ||
precomp_tasks = Task[] | ||
IanButterworth marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# TODO: since we are a complete list, but not topologically sorted, handling of recursion will be completely at random | ||
for pkg in pkgids | ||
for (i, pkg) in pairs(pkgids) | ||
IanButterworth marked this conversation as resolved.
Show resolved
Hide resolved
|
||
paths = Base.find_all_in_cache_path(pkg) | ||
sourcepath = Base.locate_package(pkg) | ||
sourcepath === nothing && continue | ||
|
@@ -917,9 +925,21 @@ function precompile(ctx::Context) | |
break | ||
end | ||
if stale | ||
Base.compilecache(pkg, sourcepath) | ||
t = @async begin | ||
staticfloat marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if length(pkg_dep_lists[i]) > 0 # if pkg has deps | ||
while length(precomp_list) == 0 || !all(map(x->in(x, precomp_list), pkg_dep_lists[i])) # if all deps not precomped | ||
sleep(0.001) | ||
end | ||
fredrikekre marked this conversation as resolved.
Show resolved
Hide resolved
|
||
end | ||
Base.compilecache(pkg, sourcepath) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To limit parallelization, I suggest launching a million tasks like this, but then creating a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice. Ok There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens if this throws? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @staticfloat aren't you describing a (counting) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, pretty much. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This PR now has a Semafore approach, and I tried out a channel-based approach here, which doesn't seem simpler master...ianshmean:ib/parallel_precomp_chanelbased What should we move forward with? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cc @tkf just to bring the conversation to a single thread There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd actually implement But this is the kind of thing the trade-off is not completely clear until you have a concrete implementation. So, I think it's reasonable to defer this to future refactoring. |
||
push!(precomp_list, pkg.name) | ||
end | ||
push!(precomp_tasks, t) | ||
else | ||
push!(precomp_list, pkg.name) | ||
end | ||
end | ||
wait.(precomp_tasks) | ||
nothing | ||
end | ||
|
||
|
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 know this filtering was here before, but why is it necessary to filter out stdlibs?
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.
Aren't stdlib's always going to be precompiled already, and if you're dev-ing them they'd need to have their uuid removed, so wouldn't identify as stdlibs in that check?
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.
Right, forgot to say that this is when you compile Julia without them in the sysimg. Perhaps we can instead filter based on if the package is already loaded? That should work for both regular packages and stdlibs. If it is a stdlib that is in the sysimg it doesn't need to precompile, and if it is a regular package that is already loaded in the session it is probably just precompiled from the
using
?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.
But what if they're loaded, and in need of recompiling? Perhaps the filter just isn't needed at all?
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.
Yea I am not sure what happens if you try to precompile stdlibs that are loaded though? Since no precompiles files exist, will that spend time on precompiling them anyway? At least we can add the filter I suggested to the stdlibs.
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.
#2021 updated with this now (the PkgId version)
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 thought the stdlib check was for some kind of optimization (launching
julia
takes a few hundreds of ms even if you don't do anything). So, I think the correct predicate here is "is it in sysimage?" than "is it a stdlib?" since non-stdlib packages can be in sysimage and there is no point in callingcompilecache
for them. This also covers the exotic situation where some stdlibs are not in sysimage.I think
is_stdlib_and_loaded
is better than nothing. But I feel it's a bit half-way solution if my assumption (the stdlib check was optimization) is correct.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.
Thats true, I didn't think about regular packages in the sysimg. But perhaps #2018 (comment) is a good enough approximation of that? It seems pretty strange to (i) load a dependency, (ii) update its version, (iii) pkg> precompile, (iv) restart Julia and expect everything to be precompiled?
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.
Although #2021 is looking good, I do like the properness of
in_sysimage
. It explains exactly why we'd always want to skip. I'll prepare a PRThere 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.
@fredrikekre Hmm... That was my expectation, actually. I generally expect
pkg> $cmd
andshell> jlpkg $cmd
to be identical (when a project is not activated). Anyway, what do you think about #2021 + JuliaLang/julia#37652? I thinkin_sysimage
is simple enough and nice to have.