[PATCH 5 of 6] dirs: reuse private ints in _incdir
Bryan O'Sullivan
bos at serpentine.com
Thu Mar 28 20:22:47 CDT 2013
# HG changeset patch
# User Bryan O'Sullivan <bryano at fb.com>
# Date 1364520157 25200
# Thu Mar 28 18:22:37 2013 -0700
# Node ID 96da5c8a645016dc0b68855ff26293ceb1188cf2
# Parent 492566bf24e94dcbb87bdfcfb10c102742c90ab5
dirs: reuse private ints in _incdir
We do not publicly expose our refcounts, so it is safe to violate Python's
assumption that ints are immutable.
Mutating the refcounts directly saves a ton of work.
perfdirs performance in a working dir with 170,000 files:
previously 248 msec
now 194
diff --git a/mercurial/dirs.c b/mercurial/dirs.c
--- a/mercurial/dirs.c
+++ b/mercurial/dirs.c
@@ -11,6 +11,12 @@
#include <Python.h>
#include "util.h"
+/*
+ * We violate the Python rule that integers are immutable. Said
+ * integers are used only for internal refcounting by this code, and
+ * are not (and must not be) used by Python code.
+ */
+
static inline Py_ssize_t _finddir(PyObject *path, Py_ssize_t pos)
{
const char *s = PyString_AS_STRING(path);
@@ -32,7 +38,6 @@ static int _incdirs(PyObject *dirs, PyOb
while ((pos = _finddir(path, pos - 1)) != -1) {
PyObject *val;
- long v = 0;
key = PyString_FromStringAndSize(PyString_AS_STRING(path), pos);
@@ -40,20 +45,30 @@ static int _incdirs(PyObject *dirs, PyOb
goto bail;
val = PyDict_GetItem(dirs, key);
+ /* Avoid allocating and deallocating an int every time
+ we revisit a directory that we have seen already,
+ by directly incrementing our internal refcount.
+ (This mutation is why Python code must not look at
+ our refcounts.) */
if (val != NULL) {
if (!PyInt_Check(val)) {
PyErr_SetString(PyExc_TypeError,
"expected int value");
goto bail;
}
- v = PyInt_AS_LONG(val);
+ PyInt_AS_LONG(val) += 1;
+ Py_CLEAR(key);
+ continue;
}
- newval = PyInt_FromLong(v + 1);
+ /* Force Python to not reuse a value from its shared
+ pool of small ints. */
+ newval = PyInt_FromLong(0x1eadbeef);
if (newval == NULL)
goto bail;
+ PyInt_AS_LONG(newval) = 1;
ret = PyDict_SetItem(dirs, key, newval);
if (ret == -1)
goto bail;
More information about the Mercurial-devel
mailing list