Mercurial > public > mercurial-scm > hg-stable
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 |