Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2219)

Side by Side Diff: parallel_emerge

Issue 3156018: parallel_emerge: Crack all counter-plan dependencies. (Closed) Base URL: ssh://git@chromiumos-git/crosutils.git
Patch Set: Remove extra space Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python2.6 1 #!/usr/bin/python2.6
2 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 2 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Program to run emerge in parallel, for significant speedup. 6 """Program to run emerge in parallel, for significant speedup.
7 7
8 Usage: 8 Usage:
9 ./parallel_emerge [--board=BOARD] [--workon=PKGS] [--no-workon-deps] 9 ./parallel_emerge [--board=BOARD] [--workon=PKGS] [--no-workon-deps]
10 [emerge args] package" 10 [emerge args] package"
(...skipping 628 matching lines...) Expand 10 before | Expand all | Expand 10 after
639 final_pkgs.add(str(match.cpv)) 639 final_pkgs.add(str(match.cpv))
640 640
641 def FindCycles(): 641 def FindCycles():
642 """Find cycles in the dependency tree. 642 """Find cycles in the dependency tree.
643 643
644 Returns: 644 Returns:
645 Dict of packages involved in cyclic dependencies, mapping each package 645 Dict of packages involved in cyclic dependencies, mapping each package
646 to a list of the cycles the package is involved in. 646 to a list of the cycles the package is involved in.
647 """ 647 """
648 648
649 def FindCyclesAtNode(pkg, cycles, unresolved, resolved): 649 def FindCyclesAtNode(pkg, cycles, unresolved):
650 """Find cycles in cyclic dependencies starting at specified package. 650 """Find cycles in cyclic dependencies starting at specified package.
651 651
652 Args: 652 Args:
653 pkg: Package identifier. 653 pkg: Package identifier.
654 cycles: Set of cycles so far. 654 cycles: Set of cycles so far.
655 unresolved: Nodes that have been visited but are not fully processed. 655 unresolved: Nodes that have been visited but are not fully processed.
656 resolved: Nodes that have been visited and are fully processed.
657 Returns:
658 Whether a cycle was found.
659 """ 656 """
660 if pkg in resolved:
661 return
662 unresolved.append(pkg) 657 unresolved.append(pkg)
658 mycycles = cycles.get(pkg)
659 if mycycles:
660 mycycles = mycycles.get("pkgs")
663 for dep in deps_map[pkg]["needs"]: 661 for dep in deps_map[pkg]["needs"]:
664 if dep in unresolved: 662 if mycycles and dep in mycycles:
663 continue
664 elif dep in unresolved:
665 idx = unresolved.index(dep) 665 idx = unresolved.index(dep)
666 mycycle = unresolved[idx:] + [dep] 666 mycycle = unresolved[idx:] + [dep]
667 for cycle_pkg in mycycle: 667 for cycle_pkg in mycycle:
668 info = cycles.setdefault(cycle_pkg, {}) 668 info = cycles.setdefault(cycle_pkg, {})
669 info.setdefault("pkgs", set()).update(mycycle) 669 info.setdefault("pkgs", set()).update(mycycle)
670 info.setdefault("cycles", []).append(mycycle) 670 info.setdefault("cycles", []).append(mycycle)
671 else: 671 else:
672 FindCyclesAtNode(dep, cycles, unresolved, resolved) 672 FindCyclesAtNode(dep, cycles, unresolved)
673 unresolved.pop() 673 unresolved.pop()
674 resolved.add(pkg)
675 674
676 cycles, unresolved, resolved = {}, [], set() 675 cycles, unresolved = {}, []
677 for pkg in deps_map: 676 for pkg in deps_map:
678 FindCyclesAtNode(pkg, cycles, unresolved, resolved) 677 FindCyclesAtNode(pkg, cycles, unresolved)
679 return cycles 678 return cycles
680 679
681 def RemoveInstalledPackages(): 680 def RemoveInstalledPackages():
682 """Remove installed packages, propagating dependencies.""" 681 """Remove installed packages, propagating dependencies."""
683 682
684 # If we're in non-selective mode, the packages specified on the command 683 # If we're in non-selective mode, the packages specified on the command
685 # line are generally mandatory. 684 # line are generally mandatory.
686 # 685 #
687 # There are a few exceptions to this rule: 686 # There are a few exceptions to this rule:
688 # 1. If the package isn't getting installed because it's in 687 # 1. If the package isn't getting installed because it's in
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
746 745
747 Because we don't treat any dependencies as "soft" unless they're killed 746 Because we don't treat any dependencies as "soft" unless they're killed
748 by a cycle, we pay attention to a larger number of dependencies when 747 by a cycle, we pay attention to a larger number of dependencies when
749 merging. This hurts performance a bit, but helps reliability. 748 merging. This hurts performance a bit, but helps reliability.
750 749
751 Args: 750 Args:
752 cycles: Dict of packages involved in cyclic dependencies, mapping each 751 cycles: Dict of packages involved in cyclic dependencies, mapping each
753 package to a list of the cycles the package is involved in. Produced 752 package to a list of the cycles the package is involved in. Produced
754 by FindCycles(). 753 by FindCycles().
755 """ 754 """
756 for basedep in set(cycles).intersection(deps_map): 755 for basedep, cycle_info in cycles.iteritems():
757 this_pkg = deps_map[basedep] 756 for mycycle in cycle_info["cycles"]:
758 for dep in this_pkg["provides"].intersection(cycles[basedep]["pkgs"]): 757 info = []
759 if deps_info[basedep]["idx"] >= deps_info[dep]["idx"]: 758 broken = False
760 for mycycle in cycles[basedep]["cycles"]: 759 for i in range(len(mycycle) - 1):
761 if dep in mycycle: 760 pkg1, pkg2 = mycycle[i], mycycle[i+1]
762 print "Breaking %s -> %s in cycle:" % (dep, basedep) 761 needs = deps_map[pkg1]["needs"]
763 for i in range(len(mycycle) - 1): 762 depinfo = needs.get(pkg2, "deleted")
764 needs = deps_map[mycycle[i]]["needs"] 763 bad = False
765 deptype = needs.get(mycycle[i+1], "deleted") 764 if (deps_info[pkg1]["idx"] >= deps_info[pkg2]["idx"] and
766 print " %s -> %s (%s)" % (mycycle[i], mycycle[i+1], deptype) 765 depinfo != "deleted"):
767 del deps_map[dep]["needs"][basedep] 766 depinfo = depinfo + ", deleting"
768 this_pkg["provides"].remove(dep) 767 broken = True
769 break 768 del deps_map[pkg1]["needs"][pkg2]
769 deps_map[pkg2]["provides"].remove(pkg1)
770 info.append(" %s -> %s (%s)" % (pkg1, pkg2, depinfo))
771 if broken:
772 print "Breaking cycle:"
773 print "\n".join(info)
770 774
771 def AddSecretDeps(): 775 def AddSecretDeps():
772 """Find these tagged packages and add extra dependencies. 776 """Find these tagged packages and add extra dependencies.
773 777
774 For debugging dependency problems. 778 For debugging dependency problems.
775 """ 779 """
776 for bad in secret_deps: 780 for bad in secret_deps:
777 needed = secret_deps[bad] 781 needed = secret_deps[bad]
778 bad_pkg = None 782 bad_pkg = None
779 needed_pkg = None 783 needed_pkg = None
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after
1062 1066
1063 deps_map = copy.deepcopy(deps_map) 1067 deps_map = copy.deepcopy(deps_map)
1064 install_plan = [] 1068 install_plan = []
1065 plan = set() 1069 plan = set()
1066 for target, info in deps_map.iteritems(): 1070 for target, info in deps_map.iteritems():
1067 if not info["needs"] and target not in plan: 1071 if not info["needs"] and target not in plan:
1068 for item in InstallPlanAtNode(target, deps_map): 1072 for item in InstallPlanAtNode(target, deps_map):
1069 plan.add(item) 1073 plan.add(item)
1070 install_plan.append(self.package_db[item]) 1074 install_plan.append(self.package_db[item])
1071 1075
1076 for pkg in plan:
1077 del deps_map[pkg]
1078
1079 if deps_map:
1080 print "Cyclic dependencies:", " ".join(deps_map)
1081 PrintDepsMap(deps_map)
1082 sys.exit(1)
1083
1072 self.emerge.depgraph.display(install_plan) 1084 self.emerge.depgraph.display(install_plan)
1073 1085
1074 1086
1075 def PrintDepsMap(deps_map): 1087 def PrintDepsMap(deps_map):
1076 """Print dependency graph, for each package list it's prerequisites.""" 1088 """Print dependency graph, for each package list it's prerequisites."""
1077 for i in deps_map: 1089 for i in sorted(deps_map):
1078 print "%s: (%s) needs" % (i, deps_map[i]["action"]) 1090 print "%s: (%s) needs" % (i, deps_map[i]["action"])
1079 needs = deps_map[i]["needs"] 1091 needs = deps_map[i]["needs"]
1080 for j in needs: 1092 for j in sorted(needs):
1081 print " %s" % (j) 1093 print " %s" % (j)
1082 if not needs: 1094 if not needs:
1083 print " no dependencies" 1095 print " no dependencies"
1084 1096
1085 1097
1086 class EmergeJobState(object): 1098 class EmergeJobState(object):
1087 __slots__ = ["done", "filename", "last_output_seek", "last_output_timestamp", 1099 __slots__ = ["done", "filename", "last_output_seek", "last_output_timestamp",
1088 "pkgname", "retcode", "start_timestamp", "target"] 1100 "pkgname", "retcode", "start_timestamp", "target"]
1089 1101
1090 def __init__(self, target, pkgname, done, filename, start_timestamp, 1102 def __init__(self, target, pkgname, done, filename, start_timestamp,
(...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after
1554 world_set.update(new_world_pkgs) 1566 world_set.update(new_world_pkgs)
1555 1567
1556 # Update environment (library cache, symlinks, etc.) 1568 # Update environment (library cache, symlinks, etc.)
1557 if deps.board and "--pretend" not in emerge.opts: 1569 if deps.board and "--pretend" not in emerge.opts:
1558 portage.env_update() 1570 portage.env_update()
1559 1571
1560 print "Done" 1572 print "Done"
1561 1573
1562 if __name__ == "__main__": 1574 if __name__ == "__main__":
1563 main() 1575 main()
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698