comparison mercurial/util.py @ 34358:c41444a39de2

config: use copy-on-write to improve copy performance Previously, chg's `verify` call could take 30+ms loading and checking new config files. With one socket redirection, that adds up to around 70ms, which is a lot for fast commands (ex. `bookmark --hidden`). When investigating closer, A lot of time was spent on actually spent on ui copying, which is mainly about `config.config` and `dict` copying. This patch makes that 20x faster by adopting copy-on-write. The copy-on-write is performed at config section level. Before: In [1]: %timeit ui.copy() 100 loops, best of 3: 2.32 ms per loop After: In [1]: %timeit ui.copy() 10000 loops, best of 3: 128 us per loop 2ms may look not that bad, but it adds up pretty quickly with multiple calls. A typical chg run may call it 4 times, which is about 10ms. Differential Revision: https://phab.mercurial-scm.org/D808
author Jun Wu <quark@fb.com>
date Wed, 27 Sep 2017 18:07:48 -0700
parents 3bb2a9f25fe9
children f435097d13c9
comparison
equal deleted inserted replaced
34357:f975cb7c4dbe 34358:c41444a39de2
586 cache[args] = func(*args) 586 cache[args] = func(*args)
587 return cache[args] 587 return cache[args]
588 588
589 return f 589 return f
590 590
591 class cow(object):
592 """helper class to make copy-on-write easier
593
594 Call preparewrite before doing any writes.
595 """
596
597 def preparewrite(self):
598 """call this before writes, return self or a copied new object"""
599 if getattr(self, '_copied', 0):
600 self._copied -= 1
601 return self.__class__(self)
602 return self
603
604 def copy(self):
605 """always do a cheap copy"""
606 self._copied = getattr(self, '_copied', 0) + 1
607 return self
608
591 class sortdict(collections.OrderedDict): 609 class sortdict(collections.OrderedDict):
592 '''a simple sorted dictionary 610 '''a simple sorted dictionary
593 611
594 >>> d1 = sortdict([(b'a', 0), (b'b', 1)]) 612 >>> d1 = sortdict([(b'a', 0), (b'b', 1)])
595 >>> d2 = d1.copy() 613 >>> d2 = d1.copy()
610 def update(self, src): 628 def update(self, src):
611 if isinstance(src, dict): 629 if isinstance(src, dict):
612 src = src.iteritems() 630 src = src.iteritems()
613 for k, v in src: 631 for k, v in src:
614 self[k] = v 632 self[k] = v
633
634 class cowdict(cow, dict):
635 """copy-on-write dict
636
637 Be sure to call d = d.preparewrite() before writing to d.
638
639 >>> a = cowdict()
640 >>> a is a.preparewrite()
641 True
642 >>> b = a.copy()
643 >>> b is a
644 True
645 >>> c = b.copy()
646 >>> c is a
647 True
648 >>> a = a.preparewrite()
649 >>> b is a
650 False
651 >>> a is a.preparewrite()
652 True
653 >>> c = c.preparewrite()
654 >>> b is c
655 False
656 >>> b is b.preparewrite()
657 True
658 """
659
660 class cowsortdict(cow, sortdict):
661 """copy-on-write sortdict
662
663 Be sure to call d = d.preparewrite() before writing to d.
664 """
615 665
616 class transactional(object): 666 class transactional(object):
617 """Base class for making a transactional type into a context manager.""" 667 """Base class for making a transactional type into a context manager."""
618 __metaclass__ = abc.ABCMeta 668 __metaclass__ = abc.ABCMeta
619 669