Mercurial > hg
comparison mercurial/copies.py @ 40057:25b2868206e2
copies: add a devel debug mode to trace what copy tracing does
Mercurial can spend a lot of time finding renames between two commits. Having
more information about that process help to understand what makes it slow in
an individual instance. (eg: many files vs 1 file, etc...)
author | Boris Feld <boris.feld@octobus.net> |
---|---|
date | Fri, 07 Sep 2018 11:16:06 -0400 |
parents | 707c3804e607 |
children | cf01616f8d96 |
comparison
equal
deleted
inserted
replaced
40056:324b4b10351e | 40057:25b2868206e2 |
---|---|
161 | 161 |
162 def _committedforwardcopies(a, b, match): | 162 def _committedforwardcopies(a, b, match): |
163 """Like _forwardcopies(), but b.rev() cannot be None (working copy)""" | 163 """Like _forwardcopies(), but b.rev() cannot be None (working copy)""" |
164 # files might have to be traced back to the fctx parent of the last | 164 # files might have to be traced back to the fctx parent of the last |
165 # one-side-only changeset, but not further back than that | 165 # one-side-only changeset, but not further back than that |
166 limit = _findlimit(a._repo, a.rev(), b.rev()) | 166 repo = a._repo |
167 debug = repo.ui.debugflag and repo.ui.configbool('devel', 'debug.copies') | |
168 dbg = repo.ui.debug | |
169 if debug: | |
170 dbg('debug.copies: looking into rename from %s to %s\n' | |
171 % (a, b)) | |
172 limit = _findlimit(repo, a.rev(), b.rev()) | |
167 if limit is None: | 173 if limit is None: |
168 limit = -1 | 174 limit = -1 |
175 if debug: | |
176 dbg('debug.copies: search limit: %d\n' % limit) | |
169 am = a.manifest() | 177 am = a.manifest() |
170 | 178 |
171 # find where new files came from | 179 # find where new files came from |
172 # we currently don't try to find where old files went, too expensive | 180 # we currently don't try to find where old files went, too expensive |
173 # this means we can miss a case like 'hg rm b; hg cp a b' | 181 # this means we can miss a case like 'hg rm b; hg cp a b' |
184 filesmatcher = scmutil.matchfiles(a._repo, b.files()) | 192 filesmatcher = scmutil.matchfiles(a._repo, b.files()) |
185 forwardmissingmatch = matchmod.intersectmatchers(match, filesmatcher) | 193 forwardmissingmatch = matchmod.intersectmatchers(match, filesmatcher) |
186 missing = _computeforwardmissing(a, b, match=forwardmissingmatch) | 194 missing = _computeforwardmissing(a, b, match=forwardmissingmatch) |
187 | 195 |
188 ancestrycontext = a._repo.changelog.ancestors([b.rev()], inclusive=True) | 196 ancestrycontext = a._repo.changelog.ancestors([b.rev()], inclusive=True) |
197 | |
198 if debug: | |
199 dbg('debug.copies: missing file to search: %d\n' % len(missing)) | |
200 | |
189 for f in missing: | 201 for f in missing: |
202 if debug: | |
203 dbg('debug.copies: tracing file: %s\n' % f) | |
190 fctx = b[f] | 204 fctx = b[f] |
191 fctx._ancestrycontext = ancestrycontext | 205 fctx._ancestrycontext = ancestrycontext |
206 | |
192 ofctx = _tracefile(fctx, am, limit) | 207 ofctx = _tracefile(fctx, am, limit) |
193 if ofctx: | 208 if ofctx: |
209 if debug: | |
210 dbg('debug.copies: rename of: %s\n' % ofctx._path) | |
194 cm[f] = ofctx.path() | 211 cm[f] = ofctx.path() |
195 return cm | 212 return cm |
196 | 213 |
197 def _forwardcopies(a, b, match=None): | 214 def _forwardcopies(a, b, match=None): |
198 """find {dst@b: src@a} copy mapping where a is an ancestor of b""" | 215 """find {dst@b: src@a} copy mapping where a is an ancestor of b""" |
224 r[v] = k | 241 r[v] = k |
225 return r | 242 return r |
226 | 243 |
227 def pathcopies(x, y, match=None): | 244 def pathcopies(x, y, match=None): |
228 """find {dst@y: src@x} copy mapping for directed compare""" | 245 """find {dst@y: src@x} copy mapping for directed compare""" |
246 repo = x._repo | |
247 debug = repo.ui.debugflag and repo.ui.configbool('devel', 'debug.copies') | |
248 if debug: | |
249 repo.ui.debug('debug.copies: searching copies from %s to %s\n' | |
250 % (x, y)) | |
229 if x == y or not x or not y: | 251 if x == y or not x or not y: |
230 return {} | 252 return {} |
231 a = y.ancestor(x) | 253 a = y.ancestor(x) |
232 if a == x: | 254 if a == x: |
255 if debug: | |
256 repo.ui.debug('debug.copies: search mode: forward\n') | |
233 return _forwardcopies(x, y, match=match) | 257 return _forwardcopies(x, y, match=match) |
234 if a == y: | 258 if a == y: |
259 if debug: | |
260 repo.ui.debug('debug.copies: search mode: backward\n') | |
235 return _backwardrenames(x, y) | 261 return _backwardrenames(x, y) |
262 if debug: | |
263 repo.ui.debug('debug.copies: search mode: combined\n') | |
236 return _chain(x, y, _backwardrenames(x, a), | 264 return _chain(x, y, _backwardrenames(x, a), |
237 _forwardcopies(a, y, match=match)) | 265 _forwardcopies(a, y, match=match)) |
238 | 266 |
239 def _computenonoverlap(repo, c1, c2, addedinm1, addedinm2, baselabel=''): | 267 def _computenonoverlap(repo, c1, c2, addedinm1, addedinm2, baselabel=''): |
240 """Computes, based on addedinm1 and addedinm2, the files exclusive to c1 | 268 """Computes, based on addedinm1 and addedinm2, the files exclusive to c1 |