Patchwork [8,of,8,faster-obsmarkers] _fm1readmarkers: generate list in C

login
register
mail settings
Submitter Augie Fackler
Date Feb. 2, 2015, 4:01 p.m.
Message ID <d04f0cdf9c5b3396bf5e.1422892889@arthedain.pit.corp.google.com>
Download mbox | patch
Permalink /patch/7601/
State Superseded
Headers show

Comments

Augie Fackler - Feb. 2, 2015, 4:01 p.m.
# HG changeset patch
# User Martin von Zweigbergk <martinvonz@google.com>
# Date 1422368579 18000
#      Tue Jan 27 09:22:59 2015 -0500
# Branch stable
# Node ID d04f0cdf9c5b3396bf5e83ca71bc504832bf075d
# Parent  6969fa0e9ab6ae8c4642ea1f90e9374e4e5a9b28
_fm1readmarkers: generate list in C

This moves perfloadmarkers from
! result: 63866
! wall 0.239217 comb 0.250000 user 0.240000 sys 0.010000 (best of 42)

to

! result: 63866
! wall 0.218795 comb 0.210000 user 0.210000 sys 0.000000 (best of 46)

Patch

diff --git a/mercurial/obsolete.py b/mercurial/obsolete.py
--- a/mercurial/obsolete.py
+++ b/mercurial/obsolete.py
@@ -285,7 +285,7 @@  def _fm0decodemeta(data):
 _fm1metapair = 'BB'
 _fm1metapairsize = _calcsize('BB')
 
-def _fm1readmarkers(data, off):
+def _fm1purereadmarkers(data, off):
     # make some global constants local for performance
     noneflag = _fm1parentnone
     sha2flag = usingsha256
@@ -302,14 +302,6 @@  def _fm1readmarkers(data, off):
     stop = len(data) - _fm1fsize
     ufixed = util.unpacker(_fm1fixed)
 
-    fast = getattr(parsers, 'fm1readmarker', None)
-    if fast is not None:
-        while off <= stop:
-            ret = fast(data, off)
-            yield ret[1:]
-            off += ret[0]
-        return
-
     while off <= stop:
         # read fixed part
         o1 = off + fsize
@@ -404,6 +396,13 @@  def _fm1encodeonemarker(marker):
         data.append(value)
     return ''.join(data)
 
+def _fm1readmarkers(data, off):
+    native = getattr(parsers, 'fm1readmarkers', None)
+    if not native:
+        return _fm1purereadmarkers(data, off)
+    stop = len(data) - _fm1fsize
+    return native(data, off, stop)
+
 # mapping to read/write various marker formats
 # <version> -> (decoder, encoder)
 formats = {_fm0version: (_fm0readmarkers, _fm0encodeonemarker),
diff --git a/mercurial/parsers.c b/mercurial/parsers.c
--- a/mercurial/parsers.c
+++ b/mercurial/parsers.c
@@ -2253,13 +2253,10 @@  static PyObject *readshas(
 	return list;
 }
 
-static PyObject *fm1readmarker(PyObject *self, PyObject *args)
+static PyObject *fm1readmarker(const char *data, uint32_t *msize)
 {
-	const char *data;
 	const char *meta;
-	Py_ssize_t datalen, offset;
 
-	uint32_t msize;
 	double mtime;
 	int16_t tz;
 	uint16_t flags;
@@ -2270,12 +2267,7 @@  static PyObject *fm1readmarker(PyObject 
 	PyObject *metadata = NULL, *ret = NULL;
 	int i;
 
-	if (!PyArg_ParseTuple(args, "s#n", &data, &datalen, &offset)) {
-		return NULL;
-	}
-	data += offset;
-
-	msize = getbe32(data);
+	*msize = getbe32(data);
 	data += 4;
 	mtime = getbefloat64(data);
 	data += 8;
@@ -2340,7 +2332,7 @@  static PyObject *fm1readmarker(PyObject 
 		}
 		PyTuple_SetItem(metadata, i, tmp);
 	}
-	ret = Py_BuildValue("(nOOHO(di)O)", msize, prec, succs, flags,
+	ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags,
 			    metadata, mtime, (int)tz * 60, parents);
 bail:
 	Py_XDECREF(prec);
@@ -2351,6 +2343,41 @@  bail:
 	return ret;
 }
 
+
+static PyObject *fm1readmarkers(PyObject *self, PyObject *args) {
+	const char *data;
+	Py_ssize_t datalen, offset, stop;
+	PyObject *markers = NULL;
+
+	if (!PyArg_ParseTuple(args, "s#nn", &data, &datalen, &offset, &stop)) {
+		return NULL;
+	}
+	data += offset;
+	markers = PyList_New(0);
+	if (!markers) {
+		return NULL;
+	}
+	while (offset < stop) {
+		uint32_t msize;
+		int error;
+		PyObject *record = fm1readmarker(data, &msize);
+		if (!record) {
+			goto bail;
+		}
+		error = PyList_Append(markers, record);
+		Py_DECREF(record);
+		if (error) {
+			goto bail;
+		}
+		data += msize;
+		offset += msize;
+	}
+	return markers;
+bail:
+	Py_DECREF(markers);
+	return NULL;
+}
+
 static char parsers_doc[] = "Efficient content parsing.";
 
 PyObject *encodedir(PyObject *self, PyObject *args);
@@ -2366,7 +2393,8 @@  static PyMethodDef methods[] = {
 	{"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
 	{"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
 	{"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
-	{"fm1readmarker", fm1readmarker, METH_VARARGS, "parse v1 obsolete marker\n"},
+	{"fm1readmarkers", fm1readmarkers, METH_VARARGS,
+			"parse v1 obsolete markers\n"},
 	{NULL, NULL}
 };