|
15 | 15 | # limitations under the License.
|
16 | 16 |
|
17 | 17 | from __future__ import print_function
|
| 18 | +import itertools |
| 19 | +import multiprocessing |
18 | 20 | import sys
|
19 | 21 | from color import Coloring
|
20 | 22 | from command import Command
|
21 | 23 |
|
| 24 | +# Number of projects to submit to a single worker process at a time. |
| 25 | +# This number represents a tradeoff between the overhead of IPC and finer |
| 26 | +# grained opportunity for parallelism. This particular value was chosen by |
| 27 | +# iterating through powers of two until the overall performance no longer |
| 28 | +# improved. The performance of this batch size is not a function of the |
| 29 | +# number of cores on the system. |
| 30 | +WORKER_BATCH_SIZE = 32 |
| 31 | + |
22 | 32 |
|
23 | 33 | class BranchColoring(Coloring):
|
24 | 34 | def __init__(self, config):
|
@@ -97,20 +107,32 @@ class Branches(Command):
|
97 | 107 |
|
98 | 108 | """
|
99 | 109 |
|
| 110 | + def _Options(self, p): |
| 111 | + """Add flags to CLI parser for this subcommand.""" |
| 112 | + default_jobs = min(multiprocessing.cpu_count(), 8) |
| 113 | + p.add_option( |
| 114 | + '-j', |
| 115 | + '--jobs', |
| 116 | + type=int, |
| 117 | + default=default_jobs, |
| 118 | + help='Number of worker processes to spawn ' |
| 119 | + '(default: %s)' % default_jobs) |
| 120 | + |
100 | 121 | def Execute(self, opt, args):
|
101 | 122 | projects = self.GetProjects(args)
|
102 | 123 | out = BranchColoring(self.manifest.manifestProject.config)
|
103 | 124 | all_branches = {}
|
104 | 125 | project_cnt = len(projects)
|
| 126 | + with multiprocessing.Pool(processes=opt.jobs) as pool: |
| 127 | + project_branches = pool.imap_unordered( |
| 128 | + expand_project_to_branches, projects, chunksize=WORKER_BATCH_SIZE) |
105 | 129 |
|
106 |
| - for project in projects: |
107 |
| - for name, b in project.GetBranches().items(): |
108 |
| - b.project = project |
| 130 | + for name, b in itertools.chain.from_iterable(project_branches): |
109 | 131 | if name not in all_branches:
|
110 | 132 | all_branches[name] = BranchInfo(name)
|
111 | 133 | all_branches[name].add(b)
|
112 | 134 |
|
113 |
| - names = list(sorted(all_branches)) |
| 135 | + names = sorted(all_branches) |
114 | 136 |
|
115 | 137 | if not names:
|
116 | 138 | print(' (no branches)', file=sys.stderr)
|
@@ -180,3 +202,19 @@ def Execute(self, opt, args):
|
180 | 202 | else:
|
181 | 203 | out.write(' in all projects')
|
182 | 204 | out.nl()
|
| 205 | + |
| 206 | + |
| 207 | +def expand_project_to_branches(project): |
| 208 | + """Expands a project into a list of branch names & associated information. |
| 209 | +
|
| 210 | + Args: |
| 211 | + project: project.Project |
| 212 | +
|
| 213 | + Returns: |
| 214 | + List[Tuple[str, git_config.Branch]] |
| 215 | + """ |
| 216 | + branches = [] |
| 217 | + for name, b in project.GetBranches().items(): |
| 218 | + b.project = project |
| 219 | + branches.append((name, b)) |
| 220 | + return branches |
0 commit comments