From 0ac3ac5aa527cdc60764990cb6e8a3b40f18020a Mon Sep 17 00:00:00 2001 From: David James Date: Tue, 7 Sep 2010 16:57:56 -0700 Subject: [PATCH] Fix cycle cracking once and for all. While testing parallel_emerge, I found more cases where it would fail to crack cycles. The issue is that parallel_emerge simply cracks the first cycle it finds that involves an edge, rather than all cycles that involve an edge. Finding all cycles that involve an edge without looping forever is a rather difficult problem, so I've updated the algorithm to simply keep searching until it runs out of cycles. Testing this, I haven't found any cases where the performance of the cycle cracking is a problem. I updated the algorithm to log its performance stats so we can track this. TEST=emerge -ep portage BUG=none Change-Id: I1cb95ffe9d977b9f8d38626d2d6cdbb766c14669 Review URL: http://codereview.chromium.org/3340010 --- parallel_emerge | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/parallel_emerge b/parallel_emerge index 3f9bbd1b4d..c53d765e0e 100755 --- a/parallel_emerge +++ b/parallel_emerge @@ -829,7 +829,7 @@ class DepGraphGenerator(object): depinfo = depinfo + ", deleting" print " %s -> %s (%s)" % (pkg1, pkg2, depinfo) - def SanitizeTree(cycles): + def SanitizeTree(): """Remove circular dependencies. We prune all dependencies involved in cycles that go against the emerge @@ -839,18 +839,20 @@ class DepGraphGenerator(object): Because we don't treat any dependencies as "soft" unless they're killed by a cycle, we pay attention to a larger number of dependencies when merging. This hurts performance a bit, but helps reliability. - - Args: - cycles: Dict of packages involved in cyclic dependencies, mapping each - package to a list of the cycles the package is involved in. Produced - by FindCycles(). """ - for dep, mycycles in cycles.iteritems(): - for basedep, mycycle in mycycles.iteritems(): - if deps_info[basedep]["idx"] >= deps_info[dep]["idx"]: - PrintCycleBreak(basedep, dep, mycycle) - del deps_map[dep]["needs"][basedep] - deps_map[basedep]["provides"].remove(dep) + start = time.time() + cycles = FindCycles() + while cycles: + for dep, mycycles in cycles.iteritems(): + for basedep, mycycle in mycycles.iteritems(): + if deps_info[basedep]["idx"] >= deps_info[dep]["idx"]: + PrintCycleBreak(basedep, dep, mycycle) + del deps_map[dep]["needs"][basedep] + deps_map[basedep]["provides"].remove(dep) + cycles = FindCycles() + seconds = time.time() - start + if "--quiet" not in emerge.opts and seconds >= 0.1: + print "Tree sanitized in %dm%.1fs" % (seconds / 60, seconds % 60) def AddSecretDeps(): """Find these tagged packages and add extra dependencies. @@ -1129,8 +1131,7 @@ class DepGraphGenerator(object): # we've done that, we also need to recalculate our list of cycles so that # we don't include the installed packages in our cycles. RemoveInstalledPackages() - cycles = FindCycles() - SanitizeTree(cycles) + SanitizeTree() if deps_map: if "--usepkg" in emerge.opts: UsePrebuiltPackages()