Skip to content

Commit

Permalink
Fix algorithmic complexity of cycle detection
Browse files Browse the repository at this point in the history
The circular dependency detection in `precompile` has poor algorithmic
complexity. In a project with deep and broad dependency trees of hundreds
of packages, this introduces a significant delay before the start of
precompilation work. Fix that by switching the cycle detection to a
simple open-coded DFS walk.
  • Loading branch information
Keno committed Oct 13, 2023
1 parent 0e0cf45 commit aafcc01
Showing 1 changed file with 28 additions and 6 deletions.
34 changes: 28 additions & 6 deletions src/API.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1208,13 +1208,35 @@ function precompile(ctx::Context, pkgs::Vector{PackageSpec}; internal_call::Bool

# find and guard against circular deps
circular_deps = Base.PkgId[]
function in_deps(_pkgs, deps, dmap)
isempty(deps) && return false
!isempty(intersect(_pkgs, deps)) && return true
return any(dep->in_deps(vcat(_pkgs, dep), dmap[dep], dmap), deps)
# Three states
# !haskey -> never visited
# true -> could be part of a cycle
# false -> not part of a cycle
could_be_cycle = Dict{Base.PkgId, Bool}()
dfs_num = 0
function scan_pkg!(pkg, dmap)
did_visit_dep = true
inpath = get!(could_be_cycle, pkg) do
did_visit_dep = false
return true
end
if did_visit_dep ? inpath : scan_deps!(pkg, dmap)
# Found a cycle. Delete this and all parents
# to let this cycle be found again by another toplevel dep
delete!(could_be_cycle, pkg)
return true
end
return false
end
for (pkg, deps) in depsmap
if in_deps([pkg], deps, depsmap)
function scan_deps!(pkg, dmap)
for dep in dmap[pkg]
scan_pkg!(dep, dmap) && return true
end
could_be_cycle[pkg] = false
return false
end
for pkg in keys(depsmap)
if scan_pkg!(pkg, depsmap)
push!(circular_deps, pkg)
notify(was_processed[pkg])
end
Expand Down

0 comments on commit aafcc01

Please sign in to comment.