Mercurial > hg
changeset 31015:1076f7eba964
smartset: convert set to list lazily
If the caller only wants to construct a baseset via a set, and then do
"__contains__" tests. It's unnecessary to initialize the list.
Testing on my unfiltered hg-committed repo where len(draft()) is 2600, this
patch shows about 6% improvement on set intensive queries:
Before:
$ for i in `seq 5`; hg perfrevset 'draft() & draft() & draft() & draft()'
! wall 0.001196 comb 0.000000 user 0.000000 sys 0.000000 (best of 2011)
! wall 0.001191 comb 0.000000 user 0.000000 sys 0.000000 (best of 2099)
! wall 0.001186 comb 0.010000 user 0.010000 sys 0.000000 (best of 1953)
! wall 0.001182 comb 0.000000 user 0.000000 sys 0.000000 (best of 2135)
! wall 0.001193 comb 0.000000 user 0.000000 sys 0.000000 (best of 2177)
After:
$ for i in `seq 5`; hg perfrevset 'draft() & draft() & draft() & draft()'
! wall 0.001128 comb 0.000000 user 0.000000 sys 0.000000 (best of 2247)
! wall 0.001119 comb 0.000000 user 0.000000 sys 0.000000 (best of 2317)
! wall 0.001115 comb 0.000000 user 0.000000 sys 0.000000 (best of 2244)
! wall 0.001131 comb 0.000000 user 0.000000 sys 0.000000 (best of 2093)
! wall 0.001124 comb 0.000000 user 0.000000 sys 0.000000 (best of 2134)
It could have bigger impact on larger sets in theory.
author | Jun Wu <quark@fb.com> |
---|---|
date | Fri, 17 Feb 2017 20:59:29 -0800 |
parents | 219629d42786 |
children | bf81d3b7b2ba |
files | mercurial/smartset.py |
diffstat | 1 files changed, 17 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/smartset.py Thu Feb 16 11:34:50 2017 -0500 +++ b/mercurial/smartset.py Fri Feb 17 20:59:29 2017 -0800 @@ -171,8 +171,12 @@ self._set = data # set has no order we pick one for stability purpose self._ascending = True - data = list(data) - self._list = data + # converting set to list has a cost, do it lazily + data = None + else: + data = list(data) + if data is not None: + self._list = data self._datarepr = datarepr @util.propertycache @@ -185,6 +189,12 @@ asclist.sort() return asclist + @util.propertycache + def _list(self): + # _list is only lazily constructed if we have _set + assert '_set' in self.__dict__ + return list(self._set) + def __iter__(self): if self._ascending is None: return iter(self._list) @@ -204,7 +214,7 @@ return self._set.__contains__ def __nonzero__(self): - return bool(self._list) + return bool(len(self)) def sort(self, reverse=False): self._ascending = not bool(reverse) @@ -218,7 +228,10 @@ self._istopo = False def __len__(self): - return len(self._list) + if '_list' in self.__dict__: + return len(self._list) + else: + return len(self._set) def isascending(self): """Returns True if the collection is ascending order, False if not.