Rev 4763: Remove 2 more mallocs per line by using a fixed-width StaticTuple for reflists. in http://bazaar.launchpad.net/~jameinel/bzr/2.1-static-tuple

John Arbash Meinel john at arbash-meinel.com
Wed Oct 7 22:18:03 BST 2009


At http://bazaar.launchpad.net/~jameinel/bzr/2.1-static-tuple

------------------------------------------------------------
revno: 4763
revision-id: john at arbash-meinel.com-20091007211747-tlgi6myzn54wdyxa
parent: john at arbash-meinel.com-20091007193509-ncpv7t7amrrnk5ti
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: 2.1-static-tuple
timestamp: Wed 2009-10-07 16:17:47 -0500
message:
  Remove 2 more mallocs per line by using a fixed-width StaticTuple for reflists.
  
  Note that 'ref_list' is arbitrary width (think parent pointers), so we can't pre-allocate that.
  I suppose we *could* count the occurences of the separator in the memory buffer, though.
  That may be more efficient...
-------------- next part --------------
=== modified file 'bzrlib/_btree_serializer_pyx.pyx'
--- a/bzrlib/_btree_serializer_pyx.pyx	2009-10-07 15:57:25 +0000
+++ b/bzrlib/_btree_serializer_pyx.pyx	2009-10-07 21:17:47 +0000
@@ -236,7 +236,7 @@
             # shrink the references end point
             last = temp_ptr
         if self.ref_list_length:
-            ref_lists = []
+            ref_lists = StaticTuple_New(self.ref_list_length)
             loop_counter = 0
             while loop_counter < self.ref_list_length:
                 ref_list = []
@@ -268,12 +268,13 @@
                     if temp_ptr == NULL:
                         # key runs to the end
                         temp_ptr = ref_ptr
+                                        
                     PyList_Append(ref_list, self.extract_key(temp_ptr))
                 ref_list = StaticTuple_Intern(StaticTuple(*ref_list))
-                PyList_Append(ref_lists, ref_list)
+                Py_INCREF(ref_list)
+                StaticTuple_SET_ITEM(ref_lists, loop_counter - 1, ref_list)
                 # prepare for the next reference list
                 self._start = next_start
-            ref_lists = StaticTuple(*ref_lists)
             node_value = StaticTuple(value, ref_lists)
         else:
             if last != self._start:

=== modified file 'bzrlib/_simple_set_pyx.pyx'
--- a/bzrlib/_simple_set_pyx.pyx	2009-10-07 19:31:39 +0000
+++ b/bzrlib/_simple_set_pyx.pyx	2009-10-07 21:17:47 +0000
@@ -20,6 +20,8 @@
     ctypedef unsigned long size_t
     ctypedef long (*hashfunc)(PyObject*)
     ctypedef PyObject *(*richcmpfunc)(PyObject *, PyObject *, int)
+    ctypedef int (*visitproc)(PyObject *, void *)
+    ctypedef int (*traverseproc)(PyObject *, visitproc, void *)
     int Py_EQ
     PyObject *Py_True
     PyObject *Py_NotImplemented
@@ -28,6 +30,7 @@
     ctypedef struct PyTypeObject:
         hashfunc tp_hash
         richcmpfunc tp_richcompare
+        traverseproc tp_traverse
 
     PyTypeObject *Py_TYPE(PyObject *)
         
@@ -112,6 +115,10 @@
         def __get__(self):
             return self._mask
 
+    def _memory_size(self):
+        """Return the number of bytes of memory consumed by this class."""
+        return sizeof(self) + (sizeof(PyObject*)*(self._mask + 1))
+
     def __len__(self):
         return self._used
 
@@ -451,8 +458,7 @@
     raise AssertionError('should never get here')
 
 
-cdef api PyObject **_SimpleSet_Lookup(object self,
-                                                object key) except NULL:
+cdef api PyObject **_SimpleSet_Lookup(object self, object key) except NULL:
     """Find the slot where 'key' would fit.
 
     This is the same as a dicts 'lookup' function. This is a private
@@ -515,8 +521,7 @@
 
 
 # TODO: this should probably have direct tests, since it isn't used by __iter__
-cdef api int SimpleSet_Next(object self, Py_ssize_t *pos,
-                                      PyObject **key):
+cdef api int SimpleSet_Next(object self, Py_ssize_t *pos, PyObject **key):
     """Walk over items in a SimpleSet.
 
     :param pos: should be initialized to 0 by the caller, and will be updated
@@ -542,3 +547,26 @@
         key[0] = table[i]
     return 1
 
+
+cdef int SimpleSet_traverse(SimpleSet self, visitproc visit, void *arg):
+    """This is an implementation of 'tp_traverse' that hits the whole table.
+
+    Cython/Pyrex don't seem to let you define a tp_traverse, and they only
+    define one for you if you have an 'object' attribute. Since they don't
+    support C arrays of objects, we access the PyObject * directly.
+    """
+    cdef Py_ssize_t pos
+    cdef PyObject *next_key
+    cdef int ret
+
+    pos = 0
+    while SimpleSet_Next(self, &pos, &next_key):
+        ret = visit(next_key, arg)
+        if ret:
+            return ret
+
+    return 0;
+
+# It is a little bit ugly to do this, but it works, and means that Meliae can
+# dump the total memory consumed by all child objects.
+(<PyTypeObject *>SimpleSet).tp_traverse = <traverseproc>SimpleSet_traverse



More information about the bazaar-commits mailing list