[pypy-svn] r27360 - in pypy/dist/pypy: rpython rpython/memory rpython/memory/test translator/backendopt

arigo at codespeak.net arigo at codespeak.net
Wed May 17 14:43:28 CEST 2006


Author: arigo
Date: Wed May 17 14:43:26 2006
New Revision: 27360

Modified:
   pypy/dist/pypy/rpython/annlowlevel.py
   pypy/dist/pypy/rpython/memory/gc.py
   pypy/dist/pypy/rpython/memory/gctransform.py
   pypy/dist/pypy/rpython/memory/gcwrapper.py
   pypy/dist/pypy/rpython/memory/support.py
   pypy/dist/pypy/rpython/memory/test/test_support.py
   pypy/dist/pypy/translator/backendopt/all.py
   pypy/dist/pypy/translator/backendopt/inline.py
Log:
(pedronis, arigo)

Start optimizing the GCs in general.  Next thing is to rewrite the
MarkSweepGC to avoid these AddressLinkedLists.


Modified: pypy/dist/pypy/rpython/annlowlevel.py
==============================================================================
--- pypy/dist/pypy/rpython/annlowlevel.py	(original)
+++ pypy/dist/pypy/rpython/annlowlevel.py	Wed May 17 14:43:26 2006
@@ -120,6 +120,7 @@
         self.delayedreprs = []
         self.delayedconsts = []
         self.delayedfuncs = []
+        self.original_graph_count = len(rtyper.annotator.translator.graphs)
 
     def getgraph(self, ll_function, args_s, s_result):
         # get the graph of the mix-level helper ll_function and prepare it for
@@ -212,3 +213,10 @@
         del self.pending[:]
         del self.delayedreprs[:]
         del self.delayedconsts[:]
+
+    def backend_optimize(self, **flags):
+        # only optimize the newly created graphs
+        from pypy.translator.backendopt.all import backend_optimizations
+        translator = self.rtyper.annotator.translator
+        newgraphs = translator.graphs[self.original_graph_count:]
+        backend_optimizations(translator, newgraphs, **flags)

Modified: pypy/dist/pypy/rpython/memory/gc.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gc.py	(original)
+++ pypy/dist/pypy/rpython/memory/gc.py	Wed May 17 14:43:26 2006
@@ -191,11 +191,9 @@
         # from this point onwards, no more mallocs should be possible
         old_malloced = self.bytes_malloced
         self.bytes_malloced = 0
-        while 1:  #mark
+        while objects.non_empty():  #mark
             curr = objects.pop()
 ##             print "object: ", curr
-            if curr == NULL:
-                break
             gc_info = curr - size_gc_header
             hdr = llmemory.cast_adr_to_ptr(gc_info, self.HDRPTR)
             if hdr.typeid & 1:
@@ -227,10 +225,9 @@
         newmo = self.AddressLinkedList()
         curr_heap_size = 0
         freed_size = 0
-        while 1:  #sweep
-            curr = self.malloced_objects.pop()
-            if curr == NULL:
-                break
+        malloced_objects = self.malloced_objects
+        while malloced_objects.non_empty():  #sweep
+            curr = malloced_objects.pop()
             hdr = llmemory.cast_adr_to_ptr(curr, self.HDRPTR)
             typeid = hdr.typeid >> 1
             size = self.fixed_size(typeid)
@@ -245,7 +242,7 @@
             else:
                 freed_size += estimate
                 raw_free(curr)
-        self.malloced_objects.delete()
+        malloced_objects.delete()
         self.malloced_objects = newmo
         if curr_heap_size > self.bytes_malloced_threshold:
             self.bytes_malloced_threshold = curr_heap_size
@@ -467,27 +464,21 @@
         roots = roots_copy
         dealloc_list = self.AddressLinkedList()
         self.length_zero_ref_counts = 0
-        while 1:
+        while self.zero_ref_counts.non_empty():
             candidate = self.zero_ref_counts.pop()
-            if candidate == NULL:
-                break
             refcount = self.refcount(candidate)
             typeid = (candidate - self.size_gc_header()).signed[1]
             if (refcount == 0 and typeid >= 0):
                 (candidate - self.size_gc_header()).signed[1] = -typeid - 1
                 dealloc_list.append(candidate)
-        while 1:
+        while dealloc_list.non_empty():
             deallocate = dealloc_list.pop()
-            if deallocate == NULL:
-                break
             typeid = (deallocate - self.size_gc_header()).signed[1]
             (deallocate - self.size_gc_header()).signed[1] = -typeid - 1
             self.deallocate(deallocate)
         dealloc_list.delete()
-        while 1:
+        while roots.non_empty():
             root = roots.pop()
-            if root == NULL:
-                break
             self.decref(root.address[0])
         self.collecting = False
 

Modified: pypy/dist/pypy/rpython/memory/gctransform.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform.py	(original)
+++ pypy/dist/pypy/rpython/memory/gctransform.py	Wed May 17 14:43:26 2006
@@ -909,6 +909,7 @@
                                     [s_gcdata], annmodel.SomeTuple(statics_s))
                                    
         annhelper.finish()   # at this point, annotate all mix-level helpers
+        annhelper.backend_optimize()
 
         self.collect_analyzer = CollectAnalyzer(self.translator)
         self.collect_analyzer.analyze_all()

Modified: pypy/dist/pypy/rpython/memory/gcwrapper.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gcwrapper.py	(original)
+++ pypy/dist/pypy/rpython/memory/gcwrapper.py	Wed May 17 14:43:26 2006
@@ -175,7 +175,7 @@
 class GcWrapper(object):
     def __init__(self, llinterp, flowgraphs, gc_class):
         self.query_types = QueryTypes()
-        self.AddressLinkedList = get_address_linked_list(3)
+        self.AddressLinkedList = get_address_linked_list(3, hackishpop=True)
         # XXX there might me GCs that have headers that depend on the type
         # therefore we have to change the query functions to annotatable ones
         # later

Modified: pypy/dist/pypy/rpython/memory/support.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/support.py	(original)
+++ pypy/dist/pypy/rpython/memory/support.py	Wed May 17 14:43:26 2006
@@ -6,7 +6,7 @@
 
 DEFAULT_CHUNK_SIZE = 1019
 
-def get_address_linked_list(chunk_size=DEFAULT_CHUNK_SIZE):
+def get_address_linked_list(chunk_size=DEFAULT_CHUNK_SIZE, hackishpop=False):
 
     CHUNK = lltype.ForwardReference()
     CHUNK.become(lltype.Struct('AddressLinkedListChunk',
@@ -43,31 +43,44 @@
             self.chunk.previous = null_chunk
             self.chunk.length = 0
 
+        def enlarge(self):
+            new = unused_chunks.get()
+            new.previous = self.chunk
+            new.length = 0
+            self.chunk = new
+            return new
+        enlarge.dont_inline = True
+
+        def shrink(self):
+            old = self.chunk
+            self.chunk = old.previous
+            unused_chunks.put(old)
+            return self.chunk
+        shrink.dont_inline = True
+
         def append(self, addr):
             if addr == llmemory.NULL:
                 return
-            if self.chunk.length == chunk_size:
-                new = unused_chunks.get()
-                new.previous = self.chunk
-                new.length = 0
-                self.chunk = new
-            used_chunks = self.chunk.length
-            self.chunk.length += 1
-            self.chunk.items[used_chunks] = addr
-            
+            chunk = self.chunk
+            if chunk.length == chunk_size:
+                chunk = self.enlarge()
+            used_chunks = chunk.length
+            chunk.length = used_chunks + 1
+            chunk.items[used_chunks] = addr
+
+        def non_empty(self):
+            chunk = self.chunk
+            return chunk.length != 0 or bool(chunk.previous)
+
         def pop(self):
-            used_chunks = self.chunk.length
-            if used_chunks == 0:
-                old = self.chunk
-                previous = old.previous
-                if not previous:
-                    return llmemory.NULL
-                self.chunk = previous
-                unused_chunks.put(old)
-                used_chunks = self.chunk.length
-            result = self.chunk.items[used_chunks - 1]
-            #self.chunk.items[used_chunks - 1] = llmemory.NULL
-            self.chunk.length = used_chunks - 1
+            if hackishpop and not self.non_empty():
+                return llmemory.NULL
+            chunk = self.chunk
+            if chunk.length == 0:
+                chunk = self.shrink()
+            used_chunks = self.chunk.length - 1
+            result = chunk.items[used_chunks]
+            chunk.length = used_chunks
             return result
 
         def delete(self):

Modified: pypy/dist/pypy/rpython/memory/test/test_support.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/test/test_support.py	(original)
+++ pypy/dist/pypy/rpython/memory/test/test_support.py	Wed May 17 14:43:26 2006
@@ -13,14 +13,16 @@
         ll.append(addr)
         ll.append(addr + 1)
         ll.append(addr + 2)
+        assert ll.non_empty()
         a = ll.pop()
         assert a - addr == 2
+        assert ll.non_empty()
         a = ll.pop()
         assert a - addr == 1
+        assert ll.non_empty()
         a = ll.pop()
         assert a == addr
-        assert ll.pop() == NULL
-        assert ll.pop() == NULL
+        assert not ll.non_empty()
         ll.append(addr)
         ll.delete()
         ll = AddressLinkedList()
@@ -63,10 +65,10 @@
         res = (a - INT_SIZE*2 == addr)
         a = ll.pop()
         res = res and (a - INT_SIZE*1 == addr)
+        res = res and ll.non_empty()
         a = ll.pop()
         res = res and a == addr
-        res = res and (ll.pop() == NULL)
-        res = res and (ll.pop() == NULL)
+        res = res and not ll.non_empty()
         ll.append(addr)
         for i in range(300):
             ll.append(addr + INT_SIZE*i)

Modified: pypy/dist/pypy/translator/backendopt/all.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/all.py	(original)
+++ pypy/dist/pypy/translator/backendopt/all.py	Wed May 17 14:43:26 2006
@@ -1,6 +1,6 @@
 from pypy.translator.backendopt.raisingop2direct_call import raisingop2direct_call
 from pypy.translator.backendopt import removenoops
-from pypy.translator.backendopt.inline import auto_inlining
+from pypy.translator.backendopt import inline
 from pypy.translator.backendopt.malloc import remove_simple_mallocs
 from pypy.translator.backendopt.propagate import propagate_all
 from pypy.translator.backendopt.stat import print_statistics
@@ -9,10 +9,12 @@
 from pypy.translator.backendopt.escape import malloc_to_stack
 from pypy.translator.backendopt.mallocprediction import clever_inlining_and_malloc_removal
 from pypy.translator.backendopt.support import log
+from pypy.objspace.flow.model import checkgraph
 
 PRINT_STATISTICS = False
 
-def backend_optimizations(translator, raisingop2direct_call_all=False,
+def backend_optimizations(translator, graphs=None,
+                                      raisingop2direct_call_all=False,
                                       inline_threshold=1,
                                       mallocs=True,
                                       merge_if_blocks_to_switch=True,
@@ -20,15 +22,19 @@
                                       heap2stack=False,
                                       clever_malloc_removal=False):
 
+    if graphs is None:
+        graphs = translator.graphs
+
     if PRINT_STATISTICS:
         print "before optimizations:"
         print_statistics(translator.graphs[0], translator, "per-graph.txt")
 
     if raisingop2direct_call_all:
+        assert graphs is translator.graphs  # XXX for now
         raisingop2direct_call(translator)
 
     # remove obvious no-ops
-    for graph in translator.graphs:
+    for graph in graphs:
         removenoops.remove_same_as(graph)
         simplify.eliminate_empty_blocks(graph)
         simplify.transform_dead_op_vars(graph, translator)
@@ -40,13 +46,16 @@
 
     # ...
     if propagate:
+        assert graphs is translator.graphs  # XXX for now
         propagate_all(translator)
 
     if not clever_malloc_removal:
         # inline functions in each other
         if inline_threshold:
-            auto_inlining(translator, inline_threshold)
-            for graph in translator.graphs:
+            callgraph = inline.inlinable_static_callers(graphs)
+            inline.auto_inlining(translator, inline_threshold,
+                                 callgraph=callgraph)
+            for graph in graphs:
                 removenoops.remove_superfluous_keep_alive(graph)
                 removenoops.remove_duplicate_casts(graph, translator)
 
@@ -57,7 +66,7 @@
         # vaporize mallocs
         if mallocs:
             tot = 0
-            for graph in translator.graphs:
+            for graph in graphs:
                 count = remove_simple_mallocs(graph)
                 if count:
                     # remove typical leftovers from malloc removal
@@ -71,6 +80,7 @@
             print "after malloc removal:"
             print_statistics(translator.graphs[0], translator)
     else:
+        assert graphs is translator.graphs  # XXX for now
         clever_inlining_and_malloc_removal(translator)
 
         if PRINT_STATISTICS:
@@ -78,17 +88,20 @@
             print_statistics(translator.graphs[0], translator)
 
     if propagate:
+        assert graphs is translator.graphs  # XXX for now
         propagate_all(translator)
 
     if heap2stack:
+        assert graphs is translator.graphs  # XXX for now
         malloc_to_stack(translator)
 
     if merge_if_blocks_to_switch:
-        for graph in translator.graphs:
+        for graph in graphs:
             merge_if_blocks(graph)
 
     if PRINT_STATISTICS:
         print "after if-to-switch:"
         print_statistics(translator.graphs[0], translator)
 
-    translator.checkgraphs()
+    for graph in graphs:
+        checkgraph(graph)

Modified: pypy/dist/pypy/translator/backendopt/inline.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/inline.py	(original)
+++ pypy/dist/pypy/translator/backendopt/inline.py	Wed May 17 14:43:26 2006
@@ -496,11 +496,11 @@
             static_instruction_count(graph))
 
 
-def inlinable_static_callers(translator):
+def inlinable_static_callers(graphs):
     result = []
-    def build_call_graph(node):
-        if isinstance(node, Block):
-            for op in node.operations:
+    for parentgraph in graphs:
+        for block in parentgraph.iterblocks():
+            for op in block.operations:
                 if op.opname == "direct_call":
                     funcobj = op.args[0].value._obj
                     graph = getattr(funcobj, 'graph', None)
@@ -512,8 +512,6 @@
                                    'dont_inline', False):
                             continue
                         result.append((parentgraph, graph))
-    for parentgraph in translator.graphs:
-        traverse(build_call_graph, parentgraph)
     return result
 
 
@@ -524,7 +522,7 @@
     callers = {}     # {graph: {graphs-that-call-it}}
     callees = {}     # {graph: {graphs-that-it-calls}}
     if callgraph is None:
-        callgraph = inlinable_static_callers(translator)
+        callgraph = inlinable_static_callers(translator.graphs)
     for graph1, graph2 in callgraph:
         callers.setdefault(graph2, {})[graph1] = True
         callees.setdefault(graph1, {})[graph2] = True



More information about the Pypy-commit mailing list