comparison mercurial/manifest.py @ 39668:24870f1be088

narrow: when writing treemanifests, skip inspecting directories outside narrow This provides significant speed benefits when narrow and treemanifests are in use, see the timing numbers below. Note that like previously, differences of <5% are considered noise. The below timing numbers are in the same style as previously (example: ee7ee0c516ca). 'before' is 9db85644, and does not include that example commit's improvements. diff --git: repo | N | T | before (mean +- stdev) | after (mean +- stdev) | % of before ------+---+---+------------------------+-----------------------+------------ m-u | | | 1.327 s +- 0.051 s | 1.296 s +- 0.009 s | 97.7% m-u | | x | 1.310 s +- 0.020 s | 1.295 s +- 0.015 s | 98.9% m-u | x | | 1.295 s +- 0.018 s | 1.296 s +- 0.007 s | 100.1% m-u | x | x | 83.5 ms +- 0.8 ms | 84.1 ms +- 0.8 ms | 100.7% l-d-r | | | 205.1 ms +- 3.5 ms | 205.0 ms +- 3.8 ms | 100.0% l-d-r | | x | 194.2 ms +- 5.6 ms | 192.3 ms +- 4.3 ms | 99.0% l-d-r | x | | 99.1 ms +- 2.2 ms | 97.8 ms +- 0.9 ms | 98.7% l-d-r | x | x | 66.2 ms +- 1.0 ms | 67.2 ms +- 2.7 ms | 101.5% diff -c . --git: repo | N | T | before (mean +- stdev) | after (mean +- stdev) | % of before ------+---+---+------------------------+-----------------------+------------ m-u | | | 233.9 ms +- 1.9 ms | 235.6 ms +- 5.1 ms | 100.7% m-u | | x | 151.4 ms +- 1.2 ms | 152.2 ms +- 2.0 ms | 100.5% m-u | x | | 234.8 ms +- 2.7 ms | 235.0 ms +- 2.7 ms | 100.1% m-u | x | x | 127.8 ms +- 2.1 ms | 126.0 ms +- 1.1 ms | 98.6% l-d-r | | | 82.5 ms +- 1.6 ms | 82.3 ms +- 2.0 ms | 99.8% l-d-r | | x | 3.742 s +- 0.017 s | 3.819 s +- 0.208 s | 102.1% l-d-r | x | | 84.4 ms +- 1.5 ms | 83.2 ms +- 1.0 ms | 98.6% l-d-r | x | x | 751.2 ms +- 5.0 ms | 755.8 ms +- 12.9 ms | 100.6% rebase -r . --keep -d .^^: repo | N | T | before (mean +- stdev) | after (mean +- stdev) | % of before ------+---+---+------------------------+-----------------------+------------ m-u | | | 5.519 s +- 0.038 s | 5.526 s +- 0.057 s | 100.1% m-u | | x | 5.588 s +- 0.048 s | 5.607 s +- 0.061 s | 100.3% m-u | x | | 5.520 s +- 0.044 s | 5.546 s +- 0.059 s | 100.5% m-u | x | x | 586.6 ms +- 12.8 ms | 554.9 ms +- 21.2 ms | 94.6% <-- l-d-r | | | 629.8 ms +- 5.5 ms | 627.4 ms +- 6.6 ms | 99.6% l-d-r | | x | 6.165 s +- 0.058 s | 6.255 s +- 0.303 s | 101.5% l-d-r | x | | 270.2 ms +- 2.3 ms | 271.4 ms +- 2.7 ms | 100.4% l-d-r | x | x | 4.700 s +- 0.025 s | 1.651 s +- 0.016 s | 35.1% <-- status --change . --copies: repo | N | T | before (mean +- stdev) | after (mean +- stdev) | % of before ------+---+---+------------------------+-----------------------+------------ m-u | | | 215.4 ms +- 2.3 ms | 216.5 ms +- 4.2 ms | 100.5% m-u | | x | 132.9 ms +- 1.2 ms | 132.0 ms +- 1.4 ms | 99.3% m-u | x | | 217.0 ms +- 1.9 ms | 215.4 ms +- 1.9 ms | 99.3% m-u | x | x | 108.6 ms +- 1.0 ms | 108.2 ms +- 1.5 ms | 99.6% l-d-r | | | 80.0 ms +- 1.3 ms | 80.5 ms +- 1.1 ms | 100.6% l-d-r | | x | 3.916 s +- 0.187 s | 3.966 s +- 0.236 s | 101.3% l-d-r | x | | 84.4 ms +- 3.1 ms | 83.9 ms +- 1.1 ms | 99.4% l-d-r | x | x | 758.0 ms +- 8.2 ms | 753.5 ms +- 5.0 ms | 99.4% status --copies: repo | N | T | before (mean +- stdev) | after (mean +- stdev) | % of before ------+---+---+------------------------+-----------------------+------------ m-u | | | 1.905 s +- 0.025 s | 1.910 s +- 0.044 s | 100.3% m-u | | x | 1.892 s +- 0.009 s | 1.895 s +- 0.012 s | 100.2% m-u | x | | 1.891 s +- 0.012 s | 1.902 s +- 0.018 s | 100.6% m-u | x | x | 93.3 ms +- 0.9 ms | 93.4 ms +- 0.8 ms | 100.1% l-d-r | | | 570.7 ms +- 7.8 ms | 571.9 ms +- 18.5 ms | 100.2% l-d-r | | x | 561.5 ms +- 5.2 ms | 562.9 ms +- 6.1 ms | 100.2% l-d-r | x | | 171.7 ms +- 2.6 ms | 171.9 ms +- 1.2 ms | 100.1% l-d-r | x | x | 142.7 ms +- 2.0 ms | 140.3 ms +- 1.0 ms | 98.3% update $rev^; ~/src/hg/hg{hg}/hg update $rev: repo | N | T | before (mean +- stdev) | after (mean +- stdev) | % of before ------+---+---+------------------------+-----------------------+------------ m-u | | | 3.126 s +- 0.016 s | 3.128 s +- 0.015 s | 100.1% m-u | | x | 3.014 s +- 0.068 s | 3.008 s +- 0.031 s | 99.8% m-u | x | | 3.143 s +- 0.037 s | 3.184 s +- 0.086 s | 101.3% m-u | x | x | 308.0 ms +- 1.8 ms | 308.1 ms +- 5.7 ms | 100.0% l-d-r | | | 430.8 ms +- 4.5 ms | 436.4 ms +- 8.7 ms | 101.3% l-d-r | | x | 9.676 s +- 0.127 s | 9.945 s +- 0.272 s | 102.8% l-d-r | x | | 254.2 ms +- 3.3 ms | 255.7 ms +- 3.1 ms | 100.6% l-d-r | x | x | 1.571 s +- 0.030 s | 1.555 s +- 0.014 s | 99.0% Differential Revision: https://phab.mercurial-scm.org/D4606
author spectral <spectral@google.com>
date Fri, 14 Sep 2018 16:29:51 -0700
parents 3ba9ef0fb693
children 5ccd791344f3
comparison
equal deleted inserted replaced
39667:0b7594ada0db 39668:24870f1be088
1201 def _load_for_read(s): 1201 def _load_for_read(s):
1202 s.parse(gettext(), readsubtree) 1202 s.parse(gettext(), readsubtree)
1203 s._dirty = False 1203 s._dirty = False
1204 self._loadfunc = _load_for_read 1204 self._loadfunc = _load_for_read
1205 1205
1206 def writesubtrees(self, m1, m2, writesubtree): 1206 def writesubtrees(self, m1, m2, writesubtree, match):
1207 self._load() # for consistency; should never have any effect here 1207 self._load() # for consistency; should never have any effect here
1208 m1._load() 1208 m1._load()
1209 m2._load() 1209 m2._load()
1210 emptytree = treemanifest() 1210 emptytree = treemanifest()
1211 def getnode(m, d): 1211 def getnode(m, d):
1212 ld = m._lazydirs.get(d) 1212 ld = m._lazydirs.get(d)
1213 if ld: 1213 if ld:
1214 return ld[1] 1214 return ld[1]
1215 return m._dirs.get(d, emptytree)._node 1215 return m._dirs.get(d, emptytree)._node
1216 1216
1217 # we should have always loaded everything by the time we get here for
1218 # `self`, but possibly not in `m1` or `m2`.
1219 assert not self._lazydirs
1220 # let's skip investigating things that `match` says we do not need.
1221 visit = match.visitchildrenset(self._dir[:-1] or '.')
1222 if visit == 'this' or visit == 'all':
1223 visit = None
1217 for d, subm in self._dirs.iteritems(): 1224 for d, subm in self._dirs.iteritems():
1225 if visit and d[:-1] not in visit:
1226 continue
1218 subp1 = getnode(m1, d) 1227 subp1 = getnode(m1, d)
1219 subp2 = getnode(m2, d) 1228 subp2 = getnode(m2, d)
1220 if subp1 == nullid: 1229 if subp1 == nullid:
1221 subp1, subp2 = subp2, subp1 1230 subp1, subp2 = subp2, subp1
1222 writesubtree(subm, subp1, subp2) 1231 writesubtree(subm, subp1, subp2, match)
1223 1232
1224 def walksubtrees(self, matcher=None): 1233 def walksubtrees(self, matcher=None):
1225 """Returns an iterator of the subtrees of this manifest, including this 1234 """Returns an iterator of the subtrees of this manifest, including this
1226 manifest itself. 1235 manifest itself.
1227 1236
1443 self._dirlogcache, 1452 self._dirlogcache,
1444 treemanifest=self._treeondisk) 1453 treemanifest=self._treeondisk)
1445 self._dirlogcache[d] = mfrevlog 1454 self._dirlogcache[d] = mfrevlog
1446 return self._dirlogcache[d] 1455 return self._dirlogcache[d]
1447 1456
1448 def add(self, m, transaction, link, p1, p2, added, removed, readtree=None): 1457 def add(self, m, transaction, link, p1, p2, added, removed, readtree=None,
1458 match=None):
1449 if p1 in self.fulltextcache and util.safehasattr(m, 'fastdelta'): 1459 if p1 in self.fulltextcache and util.safehasattr(m, 'fastdelta'):
1450 # If our first parent is in the manifest cache, we can 1460 # If our first parent is in the manifest cache, we can
1451 # compute a delta here using properties we know about the 1461 # compute a delta here using properties we know about the
1452 # manifest up-front, which may save time later for the 1462 # manifest up-front, which may save time later for the
1453 # revlog layer. 1463 # revlog layer.
1467 # just encode a fulltext of the manifest and pass that 1477 # just encode a fulltext of the manifest and pass that
1468 # through to the revlog layer, and let it handle the delta 1478 # through to the revlog layer, and let it handle the delta
1469 # process. 1479 # process.
1470 if self._treeondisk: 1480 if self._treeondisk:
1471 assert readtree, "readtree must be set for treemanifest writes" 1481 assert readtree, "readtree must be set for treemanifest writes"
1482 assert match, "match must be specified for treemanifest writes"
1472 m1 = readtree(self.tree, p1) 1483 m1 = readtree(self.tree, p1)
1473 m2 = readtree(self.tree, p2) 1484 m2 = readtree(self.tree, p2)
1474 n = self._addtree(m, transaction, link, m1, m2, readtree) 1485 n = self._addtree(m, transaction, link, m1, m2, readtree,
1486 match=match)
1475 arraytext = None 1487 arraytext = None
1476 else: 1488 else:
1477 text = m.text() 1489 text = m.text()
1478 n = self._revlog.addrevision(text, transaction, link, p1, p2) 1490 n = self._revlog.addrevision(text, transaction, link, p1, p2)
1479 arraytext = bytearray(text) 1491 arraytext = bytearray(text)
1481 if arraytext is not None: 1493 if arraytext is not None:
1482 self.fulltextcache[n] = arraytext 1494 self.fulltextcache[n] = arraytext
1483 1495
1484 return n 1496 return n
1485 1497
1486 def _addtree(self, m, transaction, link, m1, m2, readtree): 1498 def _addtree(self, m, transaction, link, m1, m2, readtree, match):
1487 # If the manifest is unchanged compared to one parent, 1499 # If the manifest is unchanged compared to one parent,
1488 # don't write a new revision 1500 # don't write a new revision
1489 if self.tree != '' and (m.unmodifiedsince(m1) or m.unmodifiedsince( 1501 if self.tree != '' and (m.unmodifiedsince(m1) or m.unmodifiedsince(
1490 m2)): 1502 m2)):
1491 return m.node() 1503 return m.node()
1492 def writesubtree(subm, subp1, subp2): 1504 def writesubtree(subm, subp1, subp2, match):
1493 sublog = self.dirlog(subm.dir()) 1505 sublog = self.dirlog(subm.dir())
1494 sublog.add(subm, transaction, link, subp1, subp2, None, None, 1506 sublog.add(subm, transaction, link, subp1, subp2, None, None,
1495 readtree=readtree) 1507 readtree=readtree, match=match)
1496 m.writesubtrees(m1, m2, writesubtree) 1508 m.writesubtrees(m1, m2, writesubtree, match)
1497 text = m.dirtext() 1509 text = m.dirtext()
1498 n = None 1510 n = None
1499 if self.tree != '': 1511 if self.tree != '':
1500 # Double-check whether contents are unchanged to one parent 1512 # Double-check whether contents are unchanged to one parent
1501 if text == m1.dirtext(): 1513 if text == m1.dirtext():
1695 return memmf 1707 return memmf
1696 1708
1697 def read(self): 1709 def read(self):
1698 return self._manifestdict 1710 return self._manifestdict
1699 1711
1700 def write(self, transaction, link, p1, p2, added, removed): 1712 def write(self, transaction, link, p1, p2, added, removed, match=None):
1701 return self._storage().add(self._manifestdict, transaction, link, 1713 return self._storage().add(self._manifestdict, transaction, link,
1702 p1, p2, added, removed) 1714 p1, p2, added, removed, match=match)
1703 1715
1704 @interfaceutil.implementer(repository.imanifestrevisionstored) 1716 @interfaceutil.implementer(repository.imanifestrevisionstored)
1705 class manifestctx(object): 1717 class manifestctx(object):
1706 """A class representing a single revision of a manifest, including its 1718 """A class representing a single revision of a manifest, including its
1707 contents, its parent revs, and its linkrev. 1719 contents, its parent revs, and its linkrev.
1800 return memmf 1812 return memmf
1801 1813
1802 def read(self): 1814 def read(self):
1803 return self._treemanifest 1815 return self._treemanifest
1804 1816
1805 def write(self, transaction, link, p1, p2, added, removed): 1817 def write(self, transaction, link, p1, p2, added, removed, match=None):
1806 def readtree(dir, node): 1818 def readtree(dir, node):
1807 return self._manifestlog.get(dir, node).read() 1819 return self._manifestlog.get(dir, node).read()
1808 return self._storage().add(self._treemanifest, transaction, link, 1820 return self._storage().add(self._treemanifest, transaction, link,
1809 p1, p2, added, removed, readtree=readtree) 1821 p1, p2, added, removed, readtree=readtree,
1822 match=match)
1810 1823
1811 @interfaceutil.implementer(repository.imanifestrevisionstored) 1824 @interfaceutil.implementer(repository.imanifestrevisionstored)
1812 class treemanifestctx(object): 1825 class treemanifestctx(object):
1813 def __init__(self, manifestlog, dir, node): 1826 def __init__(self, manifestlog, dir, node):
1814 self._manifestlog = manifestlog 1827 self._manifestlog = manifestlog