Commit Graph

19 Commits

Author SHA1 Message Date
Gregory Szorc
b5f731482f dirs: use PyVarObject_HEAD_INIT
This makes a compiler warning go away on Python 3.
2016-10-13 13:14:14 +02:00
Gregory Szorc
a17dfc705a dirs: document Py_SIZE weirdness
Assigning to what looks like a function is clown shoes. Document that
it is a macro referring to a struct member.
2016-10-08 17:07:43 +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
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
Martin von Zweigbergk
832b375a47 dirs.c: pass C string, not Python string, to _finddir()
The callers already have the C string, and although the
PyString_AS_STRING() macro is probably free, this simplifies the code.
2015-05-08 14:13:12 -07:00
Martin von Zweigbergk
fc6f3d0ec4 dirs.c: extract 'cpath' variable in _delpath() to match _addpath()
The PyString_AS_STRING() macro is probably free, but this makes
_delpath() more similar to _addpath() and simplifies the next patch.
2015-05-08 14:11:00 -07:00
Martin von Zweigbergk
d189c54016 dirs: speed up by storing number of direct children per dir
The Python version of the dirs type stores only the number of direct
children associated with each directory. That means that while adding
a directory, it only has to walk backwards until it runs into a
directory that is already in its map. The C version walks all the way
to the top-most directory. By copying the Python version's clever
trick to the C code, we can speed it up quite a bit.

On the Firefox repo, perfdirs now runs in 0.031390, from 0.056518
before the undoing Sid's optimization in the previous change, and
0.061835 before previous his optimization. More practically, it speeds
up 'hg status nonexistent' on the Firefox repo from 0.176s to 0.155s.

It's unclear why the C version did not have the same cleverness
implemented from the start, especially given that they were both
written by the same person (Bryan O'Sullivan) very close in time:

  36b515ad5d16 (scmutil: add a dirs class, 2013-04-10)
  1b2603494a5d (scmutil: rewrite dirs in C, use if available, 2013-04-10)
2015-05-08 15:04:14 -07:00
Martin von Zweigbergk
f89a1f3022 dirs: back out forward-searching in finddirs()
This backs out the changes below. The next patch will implement a
faster algorithm based on backward-walking in finddirs().

  88c2b37a1220 (dirs._addpath: reinstate use of Py_CLEAR, 2015-04-07)
  4f6b7d37d06a (dirs._addpath: don't mutate Python strings after exposing them (issue4589), 2015-04-06)
  3f1ebc88eb7b (dirs.addpath: rework algorithm to search forward, 2015-03-27)
2015-05-08 15:09:28 -07:00
Siddharth Agarwal
d2eef4cb42 dirs._addpath: reinstate use of Py_CLEAR
I changed this to an explicit Py_DECREF + set to null in 4f6b7d37d06a. This was
a silly misunderstanding on my part -- for some reason I thought Py_CLEAR set
its argument to null only if its refcount reached 0. Turns out that's not
actually the case -- Py_CLEAR is just Py_DECREF + set to null with some
additional precautions around destructors that aren't relevant here.

The real bug that 4f6b7d37d06a fixed was the fact that we were mutating the
string after setting it in the Python dictionary.
2015-04-07 20:43:04 -07:00
Siddharth Agarwal
1312e430db dirs._addpath: don't mutate Python strings after exposing them (issue4589)
One of the rules of Python strings is that they're immutable. dirs._addpath
breaks this assumption for performance, which is fine as long as it is done
safely -- once a string is no longer internal-only it shouldn't be mutated.
Unfortunately, we weren't being safe here -- we were mutating 'key' even after
adding it to a dictionary.

This only really affects other C code that reads strings, so it's somewhat hard
to write a test for this without poking into the internal representation of the
string via ctypes or similar. There is currently no C code that reads the
output of the string, but there will likely be some soon as the bug indicates.

There's no significant difference in performance.
2015-04-06 10:46:44 -07:00
Siddharth Agarwal
0a19443756 dirs.addpath: rework algorithm to search forward
This improves performance because it uses strchr rather than a loop.

For LLVM/clang version "Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM
3.5svn)" on OS X, for a repo with over 200,000 files, this improves perfdirs
from 0.248 seconds to 0.230 (7.3%)

For gcc 4.4.6 on Linux, for a test repo with over 500,000 files, this improves
perfdirs from 0.704 seconds to 0.658 (6.5%).
2015-03-27 01:03:06 -07:00
Augie Fackler
9ac34109bd dirs: fix leak of iterator in dirs_fromiter
Spotted with cpychecker.
2015-01-27 10:10:04 -05:00
Siddharth Agarwal
f40a94a790 parsers: inline fields of dirstate values in C version
Previously, while unpacking the dirstate we'd create 3-4 new CPython objects
for most dirstate values:

- the state is a single character string, which is pooled by CPython
- the mode is a new object if it isn't 0 due to being in the lookup set
- the size is a new object if it is greater than 255
- the mtime is a new object if it isn't -1 due to being in the lookup set
- the tuple to contain them all

In some cases such as regular hg status, we actually look at all the objects.
In other cases like hg add, hg status for a subdirectory, or hg status with the
third-party hgwatchman enabled, we look at almost none of the objects.

This patch eliminates most object creation in these cases by defining a custom
C struct that is exposed to Python with an interface similar to a tuple. Only
when tuple elements are actually requested are the respective objects created.

The gains, where they're expected, are significant. The following tests are run
against a working copy with over 270,000 files.

parse_dirstate becomes significantly faster:

$ hg perfdirstate
before: wall 0.186437 comb 0.180000 user 0.160000 sys 0.020000 (best of 35)
after:  wall 0.093158 comb 0.100000 user 0.090000 sys 0.010000 (best of 95)

and as a result, several commands benefit:

$ time hg status  # with hgwatchman enabled
before: 0.42s user 0.14s system 99% cpu 0.563 total
after:  0.34s user 0.12s system 99% cpu 0.471 total

$ time hg add new-file
before: 0.85s user 0.18s system 99% cpu 1.033 total
after:  0.76s user 0.17s system 99% cpu 0.931 total

There is a slight regression in regular status performance, but this is fixed
in an upcoming patch.
2014-05-27 14:27:41 -07:00
Bryan O'Sullivan
562cfc4b72 dirs: use mutable strings internally
perfdirs results for a working dir with 170,000 files:
  Python     638 msec
  C          244
  C+int      192
  C+int+str  168

In the large repo above, the nearly 0.5 second time improvement is
visible in commands like "hg add" and "hg update".

hg add
  Python    1100 msec
  C+int+str  600

hg update (with nothing to do)
  Python    2800 msec
  C+int+str 2240
2013-04-10 15:08:28 -07:00
Bryan O'Sullivan
601384a79a dirs: use mutable integers internally
These integers are not visible to Python code, so this is safe.

perfdirs results for a working dir with 170,000 files:
  Python     638 msec
  C          244
  C+int      192
2013-04-10 15:08:27 -07:00
Bryan O'Sullivan
8f78d582d5 scmutil: rewrite dirs in C, use if available
This is over twice as fast as the Python dirs code. Upcoming changes
will nearly double its speed again.

perfdirs results for a working dir with 170,000 files:
  Python     638 msec
  C          244
2013-04-10 15:08:27 -07:00