[pypy-commit] pypy default: Made the graphanalzyer code faster.

alex_gaynor noreply at buildbot.pypy.org
Sun Dec 16 20:13:56 CET 2012


Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch: 
Changeset: r59463:a8e0bae2f603
Date: 2012-12-16 10:51 -0800
http://bitbucket.org/pypy/pypy/changeset/a8e0bae2f603/

Log:	Made the graphanalzyer code faster.

	It now requires less copying, and bails out sooner upon realizing
	that a result includes everything.

diff --git a/pypy/translator/backendopt/graphanalyze.py b/pypy/translator/backendopt/graphanalyze.py
--- a/pypy/translator/backendopt/graphanalyze.py
+++ b/pypy/translator/backendopt/graphanalyze.py
@@ -12,10 +12,6 @@
     # method overridden by subclasses
 
     @staticmethod
-    def join_two_results(result1, result2):
-        raise NotImplementedError("abstract base class")
-
-    @staticmethod
     def bottom_result():
         raise NotImplementedError("abstract base class")
 
@@ -28,6 +24,22 @@
         # only an optimization, safe to always return False
         return False
 
+    @staticmethod
+    def result_builder():
+        raise NotImplementedError("abstract base class")
+
+    @staticmethod
+    def add_to_result(result, other):
+        raise NotImplementedError("abstract base class")
+
+    @staticmethod
+    def finalize_builder(result):
+        raise NotImplementedError("abstract base class")
+
+    @staticmethod
+    def join_two_results(result1, result2):
+        raise NotImplementedError("abstract base class")
+
     def analyze_simple_operation(self, op, graphinfo=None):
         raise NotImplementedError("abstract base class")
 
@@ -59,12 +71,6 @@
 
     # general methods
 
-    def join_results(self, results):
-        result = self.bottom_result()
-        for sub in results:
-            result = self.join_two_results(result, sub)
-        return result
-
     def compute_graph_info(self, graph):
         return None
 
@@ -108,31 +114,51 @@
             seen = DependencyTracker(self)
         if not seen.enter(graph):
             return seen.get_cached_result(graph)
-        result = self.bottom_result()
+        result = self.result_builder()
         graphinfo = self.compute_graph_info(graph)
         for block in graph.iterblocks():
             if block is graph.startblock:
-                result = self.join_two_results(
-                        result, self.analyze_startblock(block, seen))
+                result = self.add_to_result(
+                    result,
+                    self.analyze_startblock(block, seen)
+                )
             elif block is graph.exceptblock:
-                result = self.join_two_results(
-                        result, self.analyze_exceptblock(block, seen))
-            for op in block.operations:
-                result = self.join_two_results(
-                        result, self.analyze(op, seen, graphinfo))
-            for exit in block.exits:
-                result = self.join_two_results(
-                        result, self.analyze_link(exit, seen))
+                result = self.add_to_result(
+                    result,
+                    self.analyze_exceptblock(block, seen)
+                )
+            if not self.is_top_result(result):
+                for op in block.operations:
+                    result = self.add_to_result(
+                        result,
+                        self.analyze(op, seen, graphinfo)
+                    )
+                    if self.is_top_result(result):
+                        break
+            if not self.is_top_result(result):
+                for exit in block.exits:
+                    result = self.add_to_result(
+                        result,
+                        self.analyze_link(exit, seen)
+                    )
+                    if self.is_top_result(result):
+                        break
             if self.is_top_result(result):
                 break
+        result = self.finalize_builder(result)
         seen.leave_with(result)
         return result
 
     def analyze_indirect_call(self, graphs, seen=None):
-        results = []
+        result = self.result_builder()
         for graph in graphs:
-            results.append(self.analyze_direct_call(graph, seen))
-        return self.join_results(results)
+            result = self.add_to_result(
+                result,
+                self.analyze_direct_call(graph, seen)
+            )
+            if self.is_top_result(result):
+                break
+        return self.finalize_builder(result)
 
     def analyze_oosend(self, TYPE, name, seen=None):
         graphs = TYPE._lookup_graphs(name)
@@ -210,18 +236,23 @@
     """generic way to analyze graphs: recursively follow it until the first
     operation is found on which self.analyze_simple_operation returns True"""
 
-    @staticmethod
-    def join_two_results(result1, result2):
-        return result1 or result2
+    def bottom_result(self):
+        return False
 
-    @staticmethod
-    def is_top_result(result):
+    def top_result(self):
+        return True
+
+    def is_top_result(self, result):
         return result
 
-    @staticmethod
-    def bottom_result():
+    def result_builder(self):
         return False
 
-    @staticmethod
-    def top_result():
-        return True
+    def add_to_result(self, result, other):
+        return self.join_two_results(result, other)
+
+    def finalize_builder(self, result):
+        return result
+
+    def join_two_results(self, result1, result2):
+        return result1 or result2
diff --git a/pypy/translator/backendopt/writeanalyze.py b/pypy/translator/backendopt/writeanalyze.py
--- a/pypy/translator/backendopt/writeanalyze.py
+++ b/pypy/translator/backendopt/writeanalyze.py
@@ -5,37 +5,36 @@
 top_set = object()
 empty_set = frozenset()
 
+
 class WriteAnalyzer(graphanalyze.GraphAnalyzer):
+    def bottom_result(self):
+        return empty_set
 
-    @staticmethod
-    def join_two_results(result1, result2):
-        if result1 is top_set:
+    def top_result(self):
+        return top_set
+
+    def is_top_result(self, result):
+        return result is top_set
+
+    def result_builder(self):
+        return set()
+
+    def add_to_result(self, result, other):
+        if other is top_set:
             return top_set
-        if result2 is top_set:
+        result.update(other)
+        return result
+
+    def finalize_builder(self, result):
+        if result is top_set:
+            return result
+        return frozenset(result)
+
+    def join_two_results(self, result1, result2):
+        if result1 is top_set or result2 is top_set:
             return top_set
         return result1.union(result2)
 
-    @staticmethod
-    def join_results(results):
-        result = set()
-        for res in results:
-            if res is top_set:
-                return top_set
-            result |= res
-        return frozenset(result)
-
-    @staticmethod
-    def bottom_result():
-        return empty_set
-
-    @staticmethod
-    def top_result():
-        return top_set
-
-    @staticmethod
-    def is_top_result(result):
-        return result is top_set
-
     def analyze_simple_operation(self, op, graphinfo):
         if op.opname in ("setfield", "oosetfield"):
             if graphinfo is None or not graphinfo.is_fresh_malloc(op.args[0]):


More information about the pypy-commit mailing list