Commit Graph

5 Commits

Author SHA1 Message Date
Pierre-Yves David
9c4de6ba91 revset: improves time complexity of 'roots(xxx)'
The canonical way of doing 'roots(X)' is 'X - children(X)'. This is what the
implementation used to be. However, computing children is expensive because it
is unbounded. Any changesets in the repository may be a children of '0' so you
have to look at all changesets in the repository to compute children(0).
Moreover the current revsets implementation for children is not lazy, leading to
bad performance when fetching the first result.


There is a more restricted algorithm to compute roots:

    roots(X) = [r for r in X if not parents(r) & X]

This achieve the same result while only looking for parent/children relation in
the X set itself, making the algorithm 'O(len(X))' membership operation.
Another advantages is that it turns the check into a simple filter, preserving
all laziness property of the underlying revsets.

The speed is very significant and some laziness is restored.

-) revset without 'roots(...)' to compare to base line
0) before this change
1) after this change

revset #0: roots((tip~100::) - (tip~100::tip))
   plain         min           last
-) 0.001082      0.000993      0.000790
0) 0.001366      0.001385      0.001339
1) 0.001257  92% 0.001028  74% 0.000821  61%

revset #1: roots((0::) - (0::tip))
   plain         min           last
-) 0.134551      0.144682      0.068453
0) 0.161822      0.171786      0.157683
1) 0.137583  85% 0.146204  85% 0.070012  44%

revset #2: roots(tip~100:)
   plain         min           first         last
-) 0.000219      0.000225      0.000231      0.000229
0) 0.000513      0.000529      0.000507      0.000539
1) 0.000463  90% 0.000269  50% 0.000267  52% 0.000463  85%

revset #3: roots(:42)
   plain         min           first         last
-) 0.000119      0.000146      0.000146      0.000146
0) 0.000231      0.000254      0.000253      0.000260
1) 0.000216  93% 0.000186  73% 0.000184  72% 0.000244  93%

revset #4: roots(not public())
   plain         min           first
-) 0.000478      0.000502      0.000504
0) 0.000611      0.000639      0.000634
1) 0.000604      0.000560  87% 0.000558

revset #5: roots((0:tip)::)
   plain         min           max           first         last
-) 0.057795      0.004905      0.058260      0.004908      0.038812
0) 0.132845      0.118931      0.130306      0.114280      0.127742
1) 0.111659  84% 0.005023   4% 0.111658  85% 0.005022   4% 0.092490  72%

revset #6: roots(0::tip)
   plain         min           max           first         last
-) 0.032971      0.033947      0.033460      0.032350      0.033125
0) 0.083671      0.081953      0.084074      0.080364      0.086069
1) 0.074720  89% 0.035547  43% 0.077025  91% 0.033729  41% 0.083197

revset #7: 42:68 and roots(42:tip)
   plain         min           max           first         last
-) 0.006827      0.000251      0.006830      0.000254      0.006771
0) 0.000337      0.000353      0.000366      0.000350      0.000366
1) 0.000318  94% 0.000297  84% 0.000353      0.000293  83% 0.000351

revset #8: roots(0:tip)
   plain         min           max           first         last
-) 0.002119      0.000145      0.000147      0.000147      0.000147
0) 0.047441      0.040660      0.045662      0.040284      0.043435
1) 0.038057  80% 0.000187   0% 0.034919  76% 0.000186   0% 0.035097  80%

revset #0: roots(:42 + tip~42:)
   plain         min           max           first         last          sort
-) 0.000321      0.000317      0.000319      0.000308      0.000369      0.000343
0) 0.000772      0.000751      0.000811      0.000750      0.000802      0.000783
1) 0.000632  81% 0.000369  49% 0.000617  76% 0.000358  47% 0.000601  74% 0.000642  81%
2015-06-22 10:19:12 -07:00
Pierre-Yves David
da0f39bd8a revset: make use of natively-computed set for 'draft()' and 'secret()'
If the computation of a set for each phase (done in C) is available,
we use it directly instead of applying a simple filter. This give a
massive speed-up in the vast majority of cases.

On my mercurial repo with about 15000 out of 40000 draft changesets:

revset: draft()
   plain         min           first         last
0) 0.011201      0.019950      0.009844      0.000074
1) 0.000284   2% 0.000312   1% 0.000314   3% 0.000315 x4.3

Bad performance for "last" come from the handling of the 15000 elements set
(memory allocation, filtering hidden changesets (99% of it) etc. compared to
applying the filter only on a handfuld of revisions (the first draft changesets
being close of tip).

This is not seen as an issue since:

* Timing is still pretty good and in line with all the other one,
* Current user of Vanilla Mercurial will not have 1/3 of their repo draft,

This bad effect disappears when phase's set is smaller. (about 200 secrets):

revset: secret()
   plain         min           first         last
0) 0.011181      0.022228      0.010851      0.000452
1) 0.000058   0% 0.000084   0% 0.000087   0% 0.000087  19%
2015-06-10 19:18:51 -07:00
Pierre-Yves David
7dc4b61365 revset: translate node directly with changelog in 'head'
Using 'repo[X]' is much slower because it creates a 'changectx' object and goes
though multiple layers of code to do so. It is also error prone if there is
tags, bookmarks, branch or other names that could map to a node hash and take
precedence (user are wicked).

This provides a significant performance boost on repository with a lot of
heads.  Benchmark result for a repo with 1181 heads.

revset: head()
   plain         min           last          reverse
0) 0.014853      0.014371      0.014350      0.015161
1) 0.001402   9% 0.000975   6% 0.000874   6% 0.001415   9%

revset: head() - public()
   plain         min           last          reverse
0) 0.015121      0.014420      0.014560      0.015028
1) 0.001674  11% 0.001109   7% 0.000980   6% 0.001693  11%

revset: draft() and head()
   plain         min           last          reverse
0) 0.015976      0.014490      0.014214      0.015892
1) 0.002335  14% 0.001018   7% 0.000887   6% 0.002340  14%

The speed up is visible even when other more costly revset are in use

revset: head() and author("mpm")
   plain         min           last          reverse
0) 0.105419      0.090046      0.017169      0.108180
1) 0.090721  86% 0.077602  86% 0.003556  20% 0.093324  86%
2015-06-16 19:47:46 -07:00
Pierre-Yves David
9b78f27d7c contrib: clean up all-revsets.txt file
I forgot to cleanup a handful of them when I originally created the file.
2015-06-17 16:29:46 -07:00
Pierre-Yves David
916b1666b3 contrib: introduce an all-revsets.txt file
This file should gather all revsets ever thought interesting by
anyone. That way one can check the impact of a change when touching
something revset-ish. See inline comments for details.

This file have been refilled with all the entry I could automatically
find from changeset descriptions. I assume we missed some not using
'revsetbenchmarks.py' output.
2015-06-16 22:15:30 -07:00