Commit Graph

30530 Commits

Author SHA1 Message Date
FUJIWARA Katsunori
fc0b0c4b06 perf: make perftags clear tags cache correctly
Before this patch, "hg perftags" command doesn't measure performance
of "repo.tags()" correctly, because it doesn't clear tags cache
correctly.

a043ed82a5cd replaced repo._tags with repo._tagscache, but didn't
change the code path to clear tags cache in perftags() at that time.
BTW, full history of "tags cache" is:

  - b8d757d45f24 (or 0.6) introduced repo.tagscache as the first "tags cache"
  - 4cbf51c74e8c (or 1.4) replaced repo.tagscache with repo._tags
  - a043ed82a5cd (or 2.0) replaced repo._tags with repo._tagscache
  - 04c204f1ed65 (or 2.5) made repo._tagscache filteredpropertycache

To make perftags clear tags cache correctly, and to increase
"historical portability" of perftags, this patch examines existence of
attributes in repo object, and guess appropriate procedure to clear
tags cache.

To avoid examining existence of attributes at each repetition, this
patch makes repocleartagscachefunc() return the function, which
actually clears tags cache.

mozilla-central repo (85 tags on 308365 revs) with each Mercurial
version between before and after this patch.

  ==== ========= =========
  ver  before    after
  ==== ========= =========
  1.9  0.476062  0.466464
       ------- *1 -------
  2.0  0.346309  0.458327
  2.1  0.343106  0.454489
       ------- *2 -------
  2.2  0.069790  0.071263
  2.3  0.067829  0.069340
  2.4  0.068075  0.069573
       ------- *3 -------
  2.5  0.021896  0.022406
  2.6  0.021900  0.022374
  2.7  0.021883  0.022379
  2.8  0.021949  0.022327
  2.9  0.021877  0.022330
  3.0  0.021860  0.022314
  3.1  0.021869  0.022669
  3.2  0.021831  0.022668
  3.3  0.021809  0.022691
  3.4  0.021861  0.022916
  3.5  0.019335  0.020749
  3.6  0.019319  0.020866
  3.7  0.018781  0.020251
       ------- *4 -------
  3.8  0.068262  0.072558
  3.9  0.069682  0.073773
  ==== ========= =========

(*1) repo._tags was replaced with repo._tagscache at this point

     "repo._tags = None" in perftags "before" this patch doesn't clear
     tags cache for Mercurial 2.0 or later. This causes significant
     gap of "before" between 1.9 and 2.0 .

(*2) I'm not sure about significant gap at this point, but release
     note of 2.2 described "a number of significant performance
     improvements for large repositories"

(*3) filtered changelog was cached in repoview as repoview.changelog
     at this point (by 131b01a4654d)

     This avoids calculation of filtered changelog at each repetition
     of t().

(*4) calculation of filtered changelog was included into wall time at
     this point (by adf01efe43a5), again

     See below for detail about this significant gap:

     https://www.mercurial-scm.org/pipermail/mercurial-devel/2016-April/083410.html
2016-10-09 01:03:20 +09:00
FUJIWARA Katsunori
37e273ea35 perf: replace ui.configint() by getint() for Mercurial earlier than 1.9
Before this patch, using ui.configint() prevents perf.py from
measuring performance with Mercurial earlier than 1.9 (or
12e7e9fbf243), because ui.configint() isn't available in such
Mercurial, even though there are some code paths for Mercurial earlier
than 1.9 in perf.py.

For example, setting "_prereadsize" attribute in perfindex() and
perfnodelookup() is effective only with hg earlier than 1.8 (or
1299f0c14572).

This patch replaces ui.configint() invocations by newly introduced
getint().

This patch also adds check-perf-code.py an extra check entry to detect
direct usage of ui.configint() in perf.py.

BTW, this patch doesn't choose adding configint() method at runtime by
replacing ui.__class__ like below, even though this is the recommended
way to modern Mercurial extensions.

    def uisetup(ui):
        if not util.safehasattr(ui, 'configint'):
            class uiwrap(ui.__class__):
                def configint(self, section, name, ....):
                    ....
            ui.__class__ = uiwrap

Because changes to ui.__class__ by uisetup() of loaded extension have
been propagated since 1.6.1 (or 07a6e7bd0cc1), the recommended way
above doesn't work as expected with Mercurial earlier than it.
2016-10-09 01:03:19 +09:00
FUJIWARA Katsunori
87f398d18d perf: omit copying from ui.ferr to ui.fout for Mercurial earlier than 1.9
Before this patch, referring ui.ferr prevents perf.py from measuring
performance with Mercurial earlier than 1.9 (or bac01d164cc1), because
ui.ferr isn't available in such Mercurial, even though there are some
code paths for Mercurial earlier than 1.9 in perf.py.

For example, setting "_prereadsize" attribute in perfindex() and
perfnodelookup() is effective only with hg earlier than 1.8 (or
1299f0c14572).
2016-10-09 01:03:19 +09:00
FUJIWARA Katsunori
31be956823 perf: define formatter locally for Mercurial earlier than 2.2
Before this patch, using ui.formatter() prevents perf.py from
measuring performance with Mercurial earlier than 2.2 (or
045c8375c770), because ui.formatter() isn't available in such
Mercurial, even though there are some code paths for Mercurial earlier
than 2.2 in perf.py.

For example, setting "_prereadsize" attribute in perfindex() and
perfnodelookup() is effective only with hg earlier than 1.8 (or
1299f0c14572).

This patch defines formatter class locally, and use it instead of the
value returned by ui.formatter(), if perf.py is used with Mercurial
earlier than 2.2.

In this case, we don't need to think about -T/--template option for
formatter, because previous patch made -T/--template disabled for
perf.py with Mercurial earlier than 3.2 (or 44a82ed65df7).
2016-10-09 01:03:18 +09:00
FUJIWARA Katsunori
dd96bd471b perf: add functions to get vfs-like object for Mercurial earlier than 2.3
Before this patch, using svfs prevents perf.py from measuring
performance of Mercurial earlier than 2.3 (or 12df7401e8cd), because
svfs isn't available in such Mercurial, even though there are some
code paths for Mercurial earlier than 2.3 in perf.py.

For example, setting "_prereadsize" attribute in perfindex() and
perfnodelookup() is effective only with hg earlier than 1.8 (or
1299f0c14572).

To get appropriate vfs-like object to access files under .hg/store,
this patch adds getsvfs() (and also getvfs(), for future use).

To avoid examining existence of attribute at each repetition while
measuring performance, getsvfs() is invoked outside the function to be
called repeatedly.

This patch also adds check-perf-code.py an extra check entry to detect
direct usage of repo.(vfs|svfs|opener|sopener) in perf.py.
2016-10-09 01:03:18 +09:00
FUJIWARA Katsunori
956b59a347 perf: avoid actual writing branch cache out correctly
Mercurial 2.5 (or 0eb7dcc721cb) introduced "perfbranchmap" command,
and tried to avoid actual writing branch cache out by replacing
write() of branchcache class in branchmap.py with no-op function
(probably, for elimination of noisy and heavy file I/O factor).

But its implementation isn't correct, because 0eb7dcc721cb replaced
not branchmap.branchcache.write() but branchmap.write(). The latter
doesn't exist, even at that change.

To avoid actual writing branch cache out correctly, this patch
replaces branchmap.branchcache.write() with no-op function.

To detect mistake of replacement or change of API in the future
quickly, this patch uses safeattrsetter() instead of direct attribute
assignment. For similarity between replacements, this patch also
changes replacement of branchmap.read().

In this patch, replacement of read()/write() can run safely outside
"try" block, because two safeattrsetter() invocations ensure that
replacement doesn't cause exception.

FYI, the table below compares "base" filter wall time of perfbranchmap
on recent mozilla-central repo with each Mercurial version between
before and after this patch.

  ==== ========= =========
  ver  before    after
  ==== ========= =========
  2.5  18.492334 18.232455
  2.6  18.733858 18.156702
  2.7  18.245598 18.349210
  2.8  18.289070 18.528422
  2.9  17.572742 16.989655
  3.0  17.406953 17.615012
  3.1  17.228419 17.689805
  3.2  17.862961 17.718367
  3.3   2.632110  2.707960
  3.4   3.285683  3.272060
  3.5   3.370141  3.352176
  3.6   3.366939  3.242455
  3.7   3.300778  3.367328
  3.8   3.300132  3.267298
  3.9   3.418996  3.370265
  ==== ========= =========

IMHO, there is no serious overlooking performance regression.
2016-10-09 01:03:17 +09:00
FUJIWARA Katsunori
9d79ac8dbc perf: get subsettable from appropriate module for Mercurial earlier than 2.9
Before this patch, using branchmap.subsettable prevents perfbranchmap
from measuring performance of Mercurial earlier than 2.9 (or
aad678a92970), because aad678a92970 moved subsettable from repoview.py
to branchmap.py, even though there are some code paths for Mercurial
earlier than 2.9 in perf.py.

For example, setting "_prereadsize" attribute in perfindex() and
perfnodelookup() is effective only with hg earlier than 1.8 (or
1299f0c14572).

To get subsettable from appropriate module, this patch examines
existence of subsettable in branchmap and repoview.

This patch also adds check-perf-code.py an extra check entry to detect
direct usage of subsettable attribute in perf.py.
2016-10-09 01:03:17 +09:00
FUJIWARA Katsunori
0f1711011f perf: introduce safeattrsetter to replace direct attribute assignment
Referring not-existing attribute immediately causes failure, but
assigning a value to such attribute doesn't.

For example, perf.py has code paths below, which assign a value to
not-existing attribute. This causes incorrect performance measurement,
but these code paths are executed successfully.

  - "repo._tags = None" in perftags()
    recent Mercurial has tags cache information in repo._tagscache

  - "branchmap.write = lambda repo: None" in perfbranchmap()
    branchmap cache is written out by branchcache.write() in branchmap.py

"util.safehasattr() before assignment" can avoid this issue, but might
increase mistake at "copy & paste" attribute name or so.

To centralize (1) examining existence of, (2) assigning a value to,
and (3) restoring an old value to the attribute, this patch introduces
safeattrsetter(). This is used to replace direct attribute assignment
in subsequent patches.

Encapsulation of restoring is needed to completely remove direct
attribute assignment from perf.py, even though restoring isn't needed
so often.
2016-10-09 01:03:16 +09:00
Mads Kiilerich
7afa73604d largefiles: use context for file closing
Make the code slightly smaller and safer (and more deeply indented).
2016-10-08 00:59:41 +02:00
Mads Kiilerich
73724460ec largefiles: when setting/clearing x bit on largefiles, don't change other bits
It is only the X bit that it matters to copy from the standin to the largefile
in the working directory. While it generally doesn't do any harm to copy the
whole mode, it is also "wrong" to copy more than the X bit we care about. It
can make a difference if someone should try to handle largefiles differently,
such as marking them read-only.

Thus, do similar to what utils.setflags does and set the X bit where there are
R bits and obey umask.
2016-10-08 00:59:40 +02:00
Mads Kiilerich
cb6727b739 eol: on update, only re-check files if filtering changed
Before, update would mark all files as 'normallookup' in dirstate if .hgeol
changed so all files would get the new filtering applied. That takes some time
... and is pointless if the filtering for that file didn't change.

Instead, keep track of the old filtering and only check files where the
filtering is changed.

To keep the old filtering, change to write the applied .hgeol content to
.hg/eol.cache instead of just touching it. That change is backwards/forwards
compatible.

In a real world test, this takes an update that is changing .hgeol and 30000
files from 12s to 4s - where the remaining eol overhead is 1-2s.
2016-10-09 15:54:49 +02:00
Gregory Szorc
48ea4c11ea dirs: add comment about _PyBytes_Resize
So readers have a canonical function to compare this code to.
2016-10-13 10:59:29 +02:00
Pierre-Yves David
163070ae3d checkcopies: extract the '_related' closure
There is not need for it to be a closure.
2016-10-11 01:29:08 +02:00
Pierre-Yves David
2d670597fe checkcopies: add an inline comment about the '_related' call
This helps understanding the flow of the function.
2016-10-08 23:00:55 +02:00
Pierre-Yves David
71b0c4ef9c checkcopies: minor change to comment
This helped me understand the refactoring so this must be helpful.
2016-10-08 19:03:16 +02:00
Pierre-Yves David
1f966aa892 checkcopies: rename 'ca' to 'base'
This variable was named after the common ancestor. It is actually the merge
base that might differ from the common ancestor in the graft case. We rename the
variable before a larger refactoring to clarify the situation.
2016-10-08 18:38:42 +02:00
Pierre-Yves David
023c7518b5 bisect: extra a small initialisation outside of a loop
Having initialisation done during the first iteration is cute, but can be
avoided.
2016-08-24 05:09:46 +02:00
Martijn Pieters
6c2c90ea4c pycompat: only accept a bytestring filepath in Python 2 2016-10-10 23:11:15 +01:00
Mateusz Kwapich
f97c61b781 py3: use raw strings in line continuation (convert ext)
Our py2 to py3 string translations marks those as bytestrings.
2016-10-10 05:31:31 -07:00
Mateusz Kwapich
41dd071f2f py3: namedtuple takes unicode (journal ext)
namedtuple usage consistent with changelog.py:141
2016-10-10 05:30:14 -07:00
Augie Fackler
88491409f0 debuginstall: use %d instead of %s for formatting an int
% formatting on bytes on Python 3 is pickier about which % character
we specify.
2016-10-09 09:42:46 -04:00
Pulkit Goyal
65a2376373 py3: test to check which commands run
This test helps us to keep track on the commands which runs to Python 3.
The full traceback is hidden. Thanks to Augie and Martijn to wrap it up
in four lines.
2016-10-09 13:59:20 +02:00
Pierre-Yves David
a3ad6827e4 bisect: build a displayer only once
There is multiple spot using this, building it early will help to extract more
of the logic into the bisect module.
2016-08-24 05:06:21 +02:00
Pierre-Yves David
440aae6fd1 bisect: factor commonly update sequence
For now, This remains a closure in the module to avoid circular import with used
module.
2016-08-24 05:04:46 +02:00
Pierre-Yves David
7afebe8fb3 bisect: move check_state into the bisect module
Now that the function is simpler, we resume our quest to move the logic into the
bisect module. In the process, we add basic documentation.
2016-08-24 04:25:20 +02:00
Pierre-Yves David
1864a91d18 bisect: simplify conditional in 'check_state'
Now that extra code about "updating" flag have been removed, we can simplify the
condition flow and remove a level.
2016-08-24 04:23:13 +02:00
Pierre-Yves David
d737fb6fef bisect: remove code about "update-flag" in check_state
Now that the flag dedicated to updating the flag are handled earlier, we do not
need to handle them in the 'check_state' function.
2016-08-24 04:22:40 +02:00
Pierre-Yves David
c0f3c6bafe bisect: rename 'check_code' to match our naming scheme
We need to do it early, otherwise 'check-commit' will complain every time we
touch it.
2016-10-09 03:50:55 +02:00
Pierre-Yves David
e6d1c84c27 bisect: minor movement of code handle flag updating state
The code flag handling is quite complicated, we are moving code around to
prepare further simplification.
2016-08-24 04:48:17 +02:00
Augie Fackler
5b9434e546 test-clone: discard lock-related messages
We can't predict where those will show up and they're not
super-important for the contents of this particular test, so just drop
them. Further reduces the flakiness of the test to zero.
2016-10-09 04:37:02 -04:00
Augie Fackler
8d7ad91965 test-clone: fix some instability in pooled clone race condition test
Healthy output (one log file mentioning "existing pooled" and one
mentioning "new pooled") will now print in a stable order, but
unhealthy output will print some sort of error.

This reduces the flakiness of the test from 55% to 38%. My next patch
makes it completely stable.
2016-10-09 04:25:22 -04:00
Martijn Pieters
74d3bea9ae py3: add an os.fsencode backport to ease path handling 2016-10-09 17:44:23 +02:00
Martijn Pieters
e20d571ccf py3: a second argument to open can't be bytes
This fixes open(filename, 'r'), open(filename, 'w'), etc. calls. In Python
3, that second argument *must* be a string, you can't use bytes.

The fix is the same as used with getattr() (where the second argument must
also always be a string); in the tokenizer, where we detect calls, if there
is something that looks like a call to open (and is not an attribute, so
the previous token is not a "." dot) then make sure that that second
argument is not converted to a `bytes` object instead.

There is some remaining issue where the current transformer will also rewrite

  open(f('foo')).

However this also affect function for which we perform similar rewrite
('getattr', 'setattr', 'hasattr', 'safehasattr') and will be dealt with in a
follow up.
2016-10-09 14:10:01 +02:00
Yuya Nishihara
52fe1cc6d6 py3: make check-py3-compat.py import importlib only if necessary
importlib isn't available on Python 2.6, and it isn't necessary for Py2
checks.
2016-10-09 17:02:34 +02:00
Simon Farnsworth
d1e0848d7f templater: handle division by zero in arithmetic
For now, just turn it to an abort.
2016-10-09 08:09:20 -07:00
Simon Farnsworth
d5bf3ea399 templater: provide arithmetic operations on integers
The termwidth template keyword is of limited use without some way to ensure
that margins are respected.

Provide a full set of arithmetic operators (four basic operations plus the
mod function, defined to match Python's // for division), so that you can
create termwidth based layouts that match the user's terminal size
2016-10-09 05:51:04 -07:00
Mads Kiilerich
7fc89d4630 eol: store and reuse pattern matchers instead of creating in tight loop
More "right" and more efficient.
2016-10-09 15:54:42 +02:00
Mads Kiilerich
e84c500b99 eol: fix variable naming - call it _eolmatch instead of _eolfile
It is not the file but a match object based on it.
2016-10-09 15:42:42 +02:00
Gregory Szorc
d61a5b6632 parsers: move PyInt aliasing out of util.h
The PyInt aliasing is only used by parsers.c. Since we don't want to
encourage the use of PyInt parsing, move the aliasing to parsers.c.
2016-10-09 13:50:53 +02:00
Gregory Szorc
ac2a04b10d osutil: use PyLongObject on Python 3 for listdir_slot
This code looks performance sensitive. So let's retain PyIntObject on
Python 2 and use PyLongObject explicitly on Python 3.
2016-10-09 13:47:46 +02:00
Gregory Szorc
809ce99930 osutil: use PyLongObject in recvfds
PyIntObject doesn't exist in Python 3. While PyIntObject is preferred
on Python 2 because it is a fixed capacity and faster, the difference
between PyIntObject and PyLongObject for scenarios where performance
isn't critical or the caller isn't performing type checking shouldn't
be relevant.

So change recvfds to return a list of longs instead of ints on Python
2.
2016-10-09 13:41:18 +02:00
Pulkit Goyal
f139198734 py3: use encoding.environ instead of os.environ
This complains while running hg version on Python 3.5
2016-10-09 12:37:10 +02:00
Martijn Pieters
25a79def1c store: py26 compat, don't use a dict comprehension 2016-10-09 12:58:22 +02:00
Gregory Szorc
d30141b4f3 dirs: document performance reasons for bypassing Python C API
So someone isn't tempted to change it.
2016-10-08 16:51:18 +02:00
Gregory Szorc
c066170094 dirs: port PyInt code to work on Python 3
PyIntObject no longer exists in Python 3. Instead, there is
PyLongObject.

Furthermore, PyInt_AS_LONG is a macro referencing a struct member.
PyInt_AS_LONG doesn't exist in Python 3 and PyLong_AS_LONG is a
#define for PyLong_AsLong, which is a function. So assigning to the
return value of PyLong_AS_LONG doesn't work.

This patch introduces a macro for obtaining the value of an
integer-like type that works on Python 2 and Python 3. On
Python 3, we access the struct field of the underlying
PyLongObjet directly, without overflow checking. This is
essentially the same as what Python 2 was doing except using a
PyLong instead of a PyInt.
2016-10-08 16:20:21 +02:00
Gregory Szorc
17698cdbdb dirs: convert PyString to PyBytes
PyStringObject was renamed to PyBytes in Python 3 along with the
corresponding PyString* functions and macros. PyString* doesn't
exist in Python 3. But PyBytes* is an alias to PyString in Python 2.
So rewrite PyString* to PyBytes* for Python 2/3 dual compatibility.
2016-10-08 14:31:59 +02:00
Gregory Szorc
e7e3331fdd dirs: inline string macros
The old code happened to work because of how the macro was defined.
This no longer works in Python 3. Furthermore, assigning to a macro
just feels weird. So just inline the macro.
2016-10-08 16:02:51 +02:00
Gregory Szorc
216178bf54 parsers: use PyVarObject_HEAD_INIT
The macro changed slightly in Python 3, introducing curly brackets
that somehow confuse Clang into issuing a ton of compiler warnings.
Using PyVarObject_HEAD_INIT makes these go away.

It's worth noting that the code is identical: the 2nd argument to
PyVarObject_HEAD_INIT is assigned to the ob_size field and is
inserted immediately after "PyObject_HEAD_INIT(type)" is generated.
Compilers are weird.
2016-10-08 22:44:02 +02:00
Gregory Szorc
c76037ee62 pathencode: use Py_SIZE directly
On Python 2, PyBytes_GET_SIZE is the same as PyString_GET_SIZE which
is the same as Py_SIZE which resolves to a struct member.

On Python 3, PyBytes_GET_SIZE is
"(assert(PyBytes_Check(op)),Py_SIZE(op))". The compiler barfs when
assigning to this version.

This patch simply changes PyBytes_GET_SIZE to Py_SIZE. On Python 2,
there is no effective change in behavior. On Python 3, we drop the
PyBytes_Check(). However, in all cases we have explicitly created
a PyBytesObject in the same function, so the PyBytes_Check() is
guaranteed to be true. Despite this, code changes over time, so
I've added added assert() in all callers so we can catch this in
debug builds.

With this patch, all mercurial.* C extensions now compile on Python 3
on my OS X machine. There are several compiler warnings and I'm sure
there are incompatibilities with Python 3, including possibly
segfaults. But it is a milestone.
2016-10-08 22:21:22 +02:00
Gregory Szorc
83437de093 util: remove PyString* aliases on Python 3
We no longer have any users of the legacy PyString* functions. We no
longer need these redefinitions.

After this change, the only reference to "PyString" in the repo is in
watchman's C extension. That isn't our code and porting Mercurial
extensions to Python 3 is not a high priority at the moment. watchman's
C extension will be dealt with later.
2016-10-08 22:04:56 +02:00