summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKimiyuki Onaka <kimiyuki@google.com>2020-08-28 10:05:27 +0900
committerMike Frysinger <vapier@google.com>2020-09-09 03:52:24 +0000
commit0501b29e7ae072e0b10ea9ddd913ec6d5975f690 (patch)
tree95cc04852cbebe2365d0667c865c3995780fdda7
parent4e1fc1013c9203d3f5e7bdfba909d175a522c1f3 (diff)
downloadgit-repo-0501b29e7ae072e0b10ea9ddd913ec6d5975f690.tar.gz
status: Use multiprocessing for `repo status -j<num>` instead of threading
This change increases the speed of the command with parallelization with processes. The parallelization with threads doesn't work well, and increasing the number of jobs to many (8 threads ~) didn't increase the speed. Possibly, the global interpreter lock of Python affects. Bug: https://crbug.com/gerrit/12389 Change-Id: Icbe5df8ba037dd91422b96f4e43708068d7be924 Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/279936 Tested-by: Kimiyuki Onaka <kimiyuki@google.com> Reviewed-by: Mike Frysinger <vapier@google.com>
-rw-r--r--project.py7
-rw-r--r--subcmds/status.py48
2 files changed, 22 insertions, 33 deletions
diff --git a/project.py b/project.py
index 972cfa5f..fdbf9e4a 100644
--- a/project.py
+++ b/project.py
@@ -3208,6 +3208,13 @@ class Project(object):
3208 self._bare = bare 3208 self._bare = bare
3209 self._gitdir = gitdir 3209 self._gitdir = gitdir
3210 3210
3211 # __getstate__ and __setstate__ are required for pickling because __getattr__ exists.
3212 def __getstate__(self):
3213 return (self._project, self._bare, self._gitdir)
3214
3215 def __setstate__(self, state):
3216 self._project, self._bare, self._gitdir = state
3217
3211 def LsOthers(self): 3218 def LsOthers(self):
3212 p = GitCommand(self._project, 3219 p = GitCommand(self._project,
3213 ['ls-files', 3220 ['ls-files',
diff --git a/subcmds/status.py b/subcmds/status.py
index 8537e6c5..c380dba3 100644
--- a/subcmds/status.py
+++ b/subcmds/status.py
@@ -16,17 +16,13 @@
16 16
17from __future__ import print_function 17from __future__ import print_function
18 18
19import functools
19import glob 20import glob
20import itertools 21import multiprocessing
21import os 22import os
22 23
23from command import PagedCommand 24from command import PagedCommand
24 25
25try:
26 import threading as _threading
27except ImportError:
28 import dummy_threading as _threading
29
30from color import Coloring 26from color import Coloring
31import platform_utils 27import platform_utils
32 28
@@ -95,25 +91,20 @@ the following meanings:
95 p.add_option('-q', '--quiet', action='store_true', 91 p.add_option('-q', '--quiet', action='store_true',
96 help="only print the name of modified projects") 92 help="only print the name of modified projects")
97 93
98 def _StatusHelper(self, project, clean_counter, sem, quiet): 94 def _StatusHelper(self, quiet, project):
99 """Obtains the status for a specific project. 95 """Obtains the status for a specific project.
100 96
101 Obtains the status for a project, redirecting the output to 97 Obtains the status for a project, redirecting the output to
102 the specified object. It will release the semaphore 98 the specified object.
103 when done.
104 99
105 Args: 100 Args:
101 quiet: Where to output the status.
106 project: Project to get status of. 102 project: Project to get status of.
107 clean_counter: Counter for clean projects. 103
108 sem: Semaphore, will call release() when complete. 104 Returns:
109 output: Where to output the status. 105 The status of the project.
110 """ 106 """
111 try: 107 return project.PrintWorkTreeStatus(quiet=quiet)
112 state = project.PrintWorkTreeStatus(quiet=quiet)
113 if state == 'CLEAN':
114 next(clean_counter)
115 finally:
116 sem.release()
117 108
118 def _FindOrphans(self, dirs, proj_dirs, proj_dirs_parents, outstring): 109 def _FindOrphans(self, dirs, proj_dirs, proj_dirs_parents, outstring):
119 """find 'dirs' that are present in 'proj_dirs_parents' but not in 'proj_dirs'""" 110 """find 'dirs' that are present in 'proj_dirs_parents' but not in 'proj_dirs'"""
@@ -133,27 +124,18 @@ the following meanings:
133 124
134 def Execute(self, opt, args): 125 def Execute(self, opt, args):
135 all_projects = self.GetProjects(args) 126 all_projects = self.GetProjects(args)
136 counter = itertools.count() 127 counter = 0
137 128
138 if opt.jobs == 1: 129 if opt.jobs == 1:
139 for project in all_projects: 130 for project in all_projects:
140 state = project.PrintWorkTreeStatus(quiet=opt.quiet) 131 state = project.PrintWorkTreeStatus(quiet=opt.quiet)
141 if state == 'CLEAN': 132 if state == 'CLEAN':
142 next(counter) 133 counter += 1
143 else: 134 else:
144 sem = _threading.Semaphore(opt.jobs) 135 with multiprocessing.Pool(opt.jobs) as pool:
145 threads = [] 136 states = pool.map(functools.partial(self._StatusHelper, opt.quiet), all_projects)
146 for project in all_projects: 137 counter += states.count('CLEAN')
147 sem.acquire() 138 if not opt.quiet and len(all_projects) == counter:
148
149 t = _threading.Thread(target=self._StatusHelper,
150 args=(project, counter, sem, opt.quiet))
151 threads.append(t)
152 t.daemon = True
153 t.start()
154 for t in threads:
155 t.join()
156 if not opt.quiet and len(all_projects) == next(counter):
157 print('nothing to commit (working directory clean)') 139 print('nothing to commit (working directory clean)')
158 140
159 if opt.orphans: 141 if opt.orphans: