[PATCH 1 of 2 obs-speedup] obsolete: add C implementation of _addsuccessors

Augie Fackler raf at durin42.com
Mon Aug 24 18:25:55 UTC 2015


# HG changeset patch
# User Augie Fackler <augie at google.com>
# Date 1440439282 14400
#      Mon Aug 24 14:01:22 2015 -0400
# Node ID 3aecfdbfe3ca54134cdb0e98944e8fca53bd46f1
# Parent  207e95720308518aa40c2a91ce20fdf52dfa8550
obsolete: add C implementation of _addsuccessors

Before, best of 10 runs:
hg sl > /dev/null  0.75s user 0.07s system 99% cpu 0.828 total

After, best of 10 runs:
./hg sl > /dev/null  0.65s user 0.09s system 99% cpu 0.744 total

where
alias.sl=log -Gr smart -Tsl
revsetalias.smart=(parents(not public()) or not public() or . or head()) and (not obsolete() or unstable()^)

It's a straight-line port to C code, but still a 10% win on walltime
for the command. I can live with that.

diff --git a/mercurial/obsolete.py b/mercurial/obsolete.py
--- a/mercurial/obsolete.py
+++ b/mercurial/obsolete.py
@@ -470,10 +470,16 @@ class marker(object):
         return self._data[2]
 
 @util.nogc
-def _addsuccessors(successors, markers):
+def _addsuccessors_pure(successors, markers):
     for mark in markers:
         successors.setdefault(mark[0], set()).add(mark)
 
+def _addsuccessors(successors, markers):
+    global _addsuccessors
+    fn = getattr(parsers, 'addsuccessors', _addsuccessors_pure)
+    _addsuccessors = fn
+    return fn(successors, markers)
+
 @util.nogc
 def _addprecursors(precursors, markers):
     for mark in markers:
diff --git a/mercurial/parsers.c b/mercurial/parsers.c
--- a/mercurial/parsers.c
+++ b/mercurial/parsers.c
@@ -2700,6 +2700,46 @@ bail:
 	return NULL;
 }
 
+static PyObject *addsuccessors(PyObject *self, PyObject *args) {
+	Py_ssize_t i, len;
+	PyObject *succs = NULL, *marks = NULL;
+
+	if (!PyArg_ParseTuple(args, "O!O!", &PyDict_Type, &succs,
+			      &PyList_Type, &marks)) {
+		return NULL;
+	}
+	len = PyList_Size(marks);
+	for (i = 0; i < len; i++) {
+		PyObject *mark, *key, *dest;
+		mark = PyList_GetItem(marks, i);
+		if (!mark) {
+			return NULL;
+		}
+		key = PyTuple_GetItem(mark, 0);
+		if (!key) {
+			return NULL;
+		}
+		if (PyDict_Contains(succs, key)) {
+			dest = PyDict_GetItem(succs, key);
+		} else {
+			int r;
+			dest = PySet_New(NULL);
+			if (!dest)
+				return NULL;
+			r = PyDict_SetItem(succs, key, dest);
+			Py_DECREF(dest);
+			if (r)
+				return NULL;
+		}
+		if (!dest)
+			return NULL;
+		if (PySet_Add(dest, mark))
+			return NULL;
+	}
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
 static char parsers_doc[] = "Efficient content parsing.";
 
 PyObject *encodedir(PyObject *self, PyObject *args);
@@ -2722,6 +2762,8 @@ static PyMethodDef methods[] = {
 	{"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
 	{"fm1readmarkers", fm1readmarkers, METH_VARARGS,
 			"parse v1 obsolete markers\n"},
+	{"addsuccessors", addsuccessors, METH_VARARGS,
+	 "add successors to a dict\n"},
 	{NULL, NULL}
 };
 
diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -2945,6 +2945,7 @@ class abstractsmartset(object):
 
         This is part of the mandatory API for smartset."""
         c = other.__contains__
+        # this is slow?
         return self.filter(lambda r: not c(r), cache=False)
 
     def filter(self, condition, cache=True):


More information about the Mercurial-devel mailing list