[pypy-svn] r51684 - pypy/dist/pypy/rpython/memory/gctransform

arigo at codespeak.net arigo at codespeak.net
Wed Feb 20 12:42:14 CET 2008


Author: arigo
Date: Wed Feb 20 12:42:14 2008
New Revision: 51684

Modified:
   pypy/dist/pypy/rpython/memory/gctransform/asmgcroot.py
Log:
Replace the naive sorting algorithm with a call to qsort() from the
libc, but only called lazily if the binary search fails.

Best-of-both-worlds result: in non-gcc-profiled builds, the table is
already sorted, so binary search will always succeed; in gcc-profiled
builds, sorting is needed anyway, and qsort() should be much better than
the previous algorithm.



Modified: pypy/dist/pypy/rpython/memory/gctransform/asmgcroot.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform/asmgcroot.py	(original)
+++ pypy/dist/pypy/rpython/memory/gctransform/asmgcroot.py	Wed Feb 20 12:42:14 2008
@@ -52,17 +52,6 @@
         self._asm_callback = _asm_callback
         self._shape_decompressor = ShapeDecompressor()
 
-    def setup_root_walker(self):
-        # The gcmap table is a list of entries, two machine words each:
-        #     void *SafePointAddress;
-        #     int Shape;
-        # Here, i.e. when the program starts, we sort it
-        # in-place on the SafePointAddress to allow for more
-        # efficient searches.
-        gcmapstart = llop.llvm_gcmapstart(llmemory.Address)
-        gcmapend   = llop.llvm_gcmapend(llmemory.Address)
-        insertion_sort(gcmapstart, gcmapend)
-
     def walk_stack_roots(self, collect_stack_root):
         gcdata = self.gcdata
         gcdata._gc_collect_stack_root = collect_stack_root
@@ -147,13 +136,13 @@
         #
         gcmapstart = llop.llvm_gcmapstart(llmemory.Address)
         gcmapend   = llop.llvm_gcmapend(llmemory.Address)
-        item = binary_search(gcmapstart, gcmapend, retaddr)
-        if item.address[0] != retaddr:
-            # 'retaddr' not exactly found.  Check that 'item' the start of a
-            # compressed range containing 'retaddr'.
-            if retaddr > item.address[0] and item.signed[1] < 0:
-                pass   # ok
-            else:
+        item = search_in_gcmap(gcmapstart, gcmapend, retaddr)
+        if not item:
+            # the item may have been not found because the array was
+            # not sorted.  Sort it and try again.
+            sort_gcmap(gcmapstart, gcmapend)
+            item = search_in_gcmap(gcmapstart, gcmapend, retaddr)
+            if not item:
                 llop.debug_fatalerror(lltype.Void, "cannot find gc roots!")
                 return False
         #
@@ -243,30 +232,33 @@
             count -= middleindex
     return start
 
-def insertion_sort(start, end):
-    """Sort an array of pairs of addresses.
-
-    This is an insertion sort, so it's slowish unless the array is mostly
-    sorted already (which is what I expect, but XXX check this).
-    """
-    # XXX this should check that it's not changing the relative order
-    # of entry and the following entry in case it's a compressed "range"
-    # entry, i.e. "entry.signed[1] < 0".
-    next = start
-    while next < end:
-        # assuming the interval from start (included) to next (excluded)
-        # to be already sorted, move the next element back into the array
-        # until it reaches its proper place.
-        addr1 = next.address[0]
-        addr2 = next.address[1]
-        scan = next
-        while scan > start and addr1 < scan.address[-2]:
-            scan.address[0] = scan.address[-2]
-            scan.address[1] = scan.address[-1]
-            scan -= arrayitemsize
-        scan.address[0] = addr1
-        scan.address[1] = addr2
-        next += arrayitemsize
+def search_in_gcmap(gcmapstart, gcmapend, retaddr):
+    item = binary_search(gcmapstart, gcmapend, retaddr)
+    if item.address[0] == retaddr:
+        return item     # found
+    # 'retaddr' not exactly found.  Check that 'item' is the start of a
+    # compressed range that includes 'retaddr'.
+    if retaddr > item.address[0] and item.signed[1] < 0:
+        return item     # ok
+    else:
+        return llmemory.NULL    # failed
+
+def sort_gcmap(gcmapstart, gcmapend):
+    count = (gcmapend - gcmapstart) // arrayitemsize
+    qsort(gcmapstart,
+          rffi.cast(rffi.SIZE_T, count),
+          rffi.cast(rffi.SIZE_T, arrayitemsize),
+          llhelper(QSORT_CALLBACK_PTR, _compare_gcmap_entries))
+
+def _compare_gcmap_entries(addr1, addr2):
+    key1 = addr1.address[0]
+    key2 = addr2.address[0]
+    if key1 < key2:
+        return -1
+    elif key1 == key2:
+        return 0
+    else:
+        return 1
 
 # ____________________________________________________________
 
@@ -336,3 +328,14 @@
                                   sandboxsafe=True,
                                   _nowrapper=True)
 c_asm_gcroot = Constant(pypy_asm_gcroot, lltype.typeOf(pypy_asm_gcroot))
+
+QSORT_CALLBACK_PTR = lltype.Ptr(lltype.FuncType([llmemory.Address,
+                                                 llmemory.Address], rffi.INT))
+qsort = rffi.llexternal('qsort',
+                        [llmemory.Address,
+                         rffi.SIZE_T,
+                         rffi.SIZE_T,
+                         QSORT_CALLBACK_PTR],
+                        lltype.Void,
+                        sandboxsafe=True,
+                        _nowrapper=True)



More information about the Pypy-commit mailing list