[pypy-svn] r43477 - in pypy/branch/prolog-jit-experiments/pypy/lang/prolog: builtin interpreter interpreter/test

cfbolz at codespeak.net cfbolz at codespeak.net
Fri May 18 14:35:13 CEST 2007


Author: cfbolz
Date: Fri May 18 14:35:12 2007
New Revision: 43477

Modified:
   pypy/branch/prolog-jit-experiments/pypy/lang/prolog/builtin/__init__.py
   pypy/branch/prolog-jit-experiments/pypy/lang/prolog/builtin/register.py
   pypy/branch/prolog-jit-experiments/pypy/lang/prolog/interpreter/engine.py
   pypy/branch/prolog-jit-experiments/pypy/lang/prolog/interpreter/portal.py
   pypy/branch/prolog-jit-experiments/pypy/lang/prolog/interpreter/term.py
   pypy/branch/prolog-jit-experiments/pypy/lang/prolog/interpreter/test/test_jit.py
Log:
assorted hints and hacks to make pyrolog-jit better. gives a speedup of around
2.


Modified: pypy/branch/prolog-jit-experiments/pypy/lang/prolog/builtin/__init__.py
==============================================================================
--- pypy/branch/prolog-jit-experiments/pypy/lang/prolog/builtin/__init__.py	(original)
+++ pypy/branch/prolog-jit-experiments/pypy/lang/prolog/builtin/__init__.py	Fri May 18 14:35:12 2007
@@ -1,5 +1,6 @@
 # all builtins
 builtins = {}
+builtins_list = []
 
 # imports to register builtins
 import pypy.lang.prolog.builtin.allsolution

Modified: pypy/branch/prolog-jit-experiments/pypy/lang/prolog/builtin/register.py
==============================================================================
--- pypy/branch/prolog-jit-experiments/pypy/lang/prolog/builtin/register.py	(original)
+++ pypy/branch/prolog-jit-experiments/pypy/lang/prolog/builtin/register.py	Fri May 18 14:35:12 2007
@@ -2,17 +2,20 @@
 from pypy.lang.prolog.interpreter import arithmetic
 from pypy.lang.prolog.interpreter.parsing import parse_file, TermBuilder
 from pypy.lang.prolog.interpreter import engine, helper, term, error
-from pypy.lang.prolog.builtin import builtins
+from pypy.lang.prolog.builtin import builtins, builtins_list
 
 from pypy.rlib.objectmodel import we_are_translated
 
 class Builtin(object):
+    _immutable_ = True
     def __init__(self, function):
         self.function = function
 
     def call(self, engine, query, continuation):
         return self.function(engine, query, continuation)
         
+    def _freeze_(self):
+        return True
 
 def expose_builtin(func, name, unwrap_spec=None, handles_continuation=False,
                    translatable=True):
@@ -80,5 +83,6 @@
     exec py.code.Source("\n".join(code)).compile() in miniglobals
     for name in expose_as:
         signature = "%s/%s" % (name, len(unwrap_spec))
-        builtins[signature] = Builtin(miniglobals[funcname])
-
+        b = Builtin(miniglobals[funcname])
+        builtins[signature] = b
+        builtins_list.append((signature, b))

Modified: pypy/branch/prolog-jit-experiments/pypy/lang/prolog/interpreter/engine.py
==============================================================================
--- pypy/branch/prolog-jit-experiments/pypy/lang/prolog/interpreter/engine.py	(original)
+++ pypy/branch/prolog-jit-experiments/pypy/lang/prolog/interpreter/engine.py	Fri May 18 14:35:12 2007
@@ -3,7 +3,8 @@
 from pypy.lang.prolog.interpreter.error import UnificationFailed, FunctionNotFound, \
     CutException
 from pypy.lang.prolog.interpreter import error
-from pypy.rlib.objectmodel import hint, specialize
+from pypy.rlib.objectmodel import hint, specialize, _is_early_constant
+from pypy.rlib.unroll import unrolling_iterable
 
 DEBUG = False
 
@@ -95,6 +96,7 @@
         return result
 
 class LinkedRules(object):
+    _immutable_ = True
     def __init__(self, rule, next=None):
         self.rule = rule
         self.next = next
@@ -114,13 +116,19 @@
         #import pdb;pdb.set_trace()
         while self:
             uh = self.rule.unify_hash
-            for j in range(len(uh)):
+            hint(uh, concrete=True)
+            uh = hint(uh, deepfreeze=True)
+            j = 0
+            while j < len(uh):
+                hint(j, concrete=True)
                 hash1 = uh[j]
                 hash2 = query.unify_hash_of_child(j)
                 if hash1 != 0 and hash2 != 0 and hash1 != hash2:
                     break
+                j += 1
             else:
-                return self
+                #XXX otherwise the result is green which seems wrong
+                return hint(self, variable=True)
             self = self.next
         return None
 
@@ -128,14 +136,19 @@
         return "LinkedRules(%r, %r)" % (self.rule, self.next)
 
 
+
 class Function(object):
-    def __init__(self, firstrule):
-        self.rulechain = LinkedRules(firstrule)
-        self.last = self.rulechain
+    def __init__(self, firstrule=None):
+        if firstrule is None:
+            self.rulechain = self.last = None
+        else:
+            self.rulechain = LinkedRules(firstrule)
+            self.last = self.rulechain
 
     def add_rule(self, rule, end):
-        #import pdb; pdb.set_trace()
-        if end:
+        if self.rulechain is None:
+            self.rulechain = self.last = LinkedRules(rule)
+        elif end:
             self.rulechain, last = self.rulechain.copy()
             self.last = LinkedRules(rule)
             last.next = self.last
@@ -146,13 +159,17 @@
         self.rulechain, last = self.rulechain.copy(rulechain)
         last.next = rulechain.next
 
+
 class Engine(object):
     def __init__(self):
         self.heap = Heap()
         self.signature2function = {}
         self.parser = None
         self.operations = None
-    
+        #XXX circular imports hack
+        from pypy.lang.prolog.builtin import builtins_list
+        globals()['unrolling_builtins'] = unrolling_iterable(builtins_list) 
+
     def add_rule(self, rule, end=True):
         from pypy.lang.prolog import builtin
         if DEBUG:
@@ -204,29 +221,57 @@
 
     def call(self, query, continuation=DONOTHING):
         assert isinstance(query, Callable)
-        from pypy.lang.prolog.builtin import builtins
         if DEBUG:
             debug_print("calling", query)
         signature = query.signature
         # check for builtins
-        builtins = hint(builtins, deepfreeze=True)
+        if _is_early_constant(signature):
+            for bsig, builtin in unrolling_builtins:
+                if signature == bsig:
+                    #XXX should be:
+                    #return builtin.call(self, query, continuation)
+                    # but then the JIT explodes sometimes for funny reasons
+                    return builtin.function(self, query, continuation)
+            # do a real call
+            return self.user_call(query, continuation)
+        else:
+            return self._opaque_call(signature, query, continuation)
+
+    def _opaque_call(self, signature, query, continuation):
+        from pypy.lang.prolog.builtin import builtins
+        #builtins = hint(builtins, deepfreeze=True)
         builtin = builtins.get(signature, None)
         if builtin is not None:
-            return builtin.call(self, query, continuation)
+            #XXX should be:
+            #return builtin.call(self, query, continuation)
+            # but then the JIT explodes sometimes for funny reasons
+            return builtin.function(self, query, continuation)
         # do a real call
         return self.user_call(query, continuation)
 
+    def _jit_lookup(self, signature):
+        signature2function = self.signature2function
+        function = signature2function.get(signature, None)
+        if function is None:
+            signature2function[signature] = function = Function()
+        return function
+    _jit_lookup._pure_function_ = True
+
     def user_call(self, query, continuation):
         #import pdb; pdb.set_trace()
-        signature = query.signature
-        function = self.signature2function.get(signature, None)
-        if function is None:
+        signature = hint(query.signature, promote=True)
+        function = self._jit_lookup(signature)
+        startrulechain = function.rulechain
+        startrulechain = hint(startrulechain, promote=True)
+        if startrulechain is None:
             error.throw_existence_error(
                 "procedure", query.get_prolog_signature())
-        rulechain = function.rulechain.find_applicable_rule(query)
+
+        rulechain = startrulechain.find_applicable_rule(query)
         if rulechain is None:
             # none of the rules apply
             raise UnificationFailed()
+        rulechain = hint(rulechain, promote=True)
         rule = rulechain.rule
         rulechain = rulechain.next
         oldstate = self.heap.branch()
@@ -235,6 +280,8 @@
             if rulechain is None:
                 self.heap.discard(oldstate)
                 break
+            rulechain = hint(rulechain, promote=True)
+            hint(rule, concrete=True)
             if rule.contains_cut:
                 continuation = LimitedScopeContinuation(continuation)
                 try:
@@ -257,6 +304,7 @@
                     self.heap.revert(oldstate)
             rule = rulechain.rule
             rulechain = rulechain.next
+        hint(rule, concrete=True)
         if rule.contains_cut:
             continuation = LimitedScopeContinuation(continuation)
             try:
@@ -268,9 +316,12 @@
         return self.try_rule(rule, query, continuation)
 
     def try_rule(self, rule, query, continuation=DONOTHING):
+        return self._portal_try_rule(rule, query, continuation)
+
+    def _portal_try_rule(self, rule, query, continuation=DONOTHING):
         hint(None, global_merge_point=True)
-        rule = hint(rule, promote=True)
         rule = hint(rule, deepfreeze=True)
+        hint(self, concrete=True)
         if DEBUG:
             debug_print("trying rule", rule, query, self.heap.vars[:self.heap.needed_vars])
         # standardizing apart
@@ -284,7 +335,6 @@
             continuation.call(self)
             return "yes"
 
-
     def continue_after_cut(self, continuation, lsc=None):
         while 1:
             try:
@@ -306,3 +356,7 @@
         if self.operations is None:
             return default_operations
         return self.operations
+
+
+
+

Modified: pypy/branch/prolog-jit-experiments/pypy/lang/prolog/interpreter/portal.py
==============================================================================
--- pypy/branch/prolog-jit-experiments/pypy/lang/prolog/interpreter/portal.py	(original)
+++ pypy/branch/prolog-jit-experiments/pypy/lang/prolog/interpreter/portal.py	Fri May 18 14:35:12 2007
@@ -11,7 +11,7 @@
                 'pypy.lang.prolog.builtin.register': True
                }
 
-PORTAL = engine.Engine.try_rule
+PORTAL = engine.Engine._portal_try_rule.im_func
 
 class PyrologHintAnnotatorPolicy(HintAnnotatorPolicy):
     novirtualcontainer = True
@@ -126,13 +126,21 @@
         seegraph(cls.copy)
         seegraph(cls.__init__)
         seegraph(cls.copy_and_unify)
+        seegraph(cls.unify_hash_of_child)
     for cls in [term.Term, term.Number, term.Atom]:
         seegraph(cls.copy_and_basic_unify)
+        seegraph(cls.dereference)
         seegraph(cls.copy_and_basic_unify)
+    for cls in [term.Var, term.Term, term.Number, term.Atom]:
+        seegraph(cls.get_unify_hash)
+    for cls in [term.Callable, term.Atom, term.Term]:
+        seegraph(cls.get_prolog_signature)
+    seegraph(PORTAL)
     seegraph(pypy.lang.prolog.interpreter.engine.Heap.newvar)
-    seegraph(pypy.lang.prolog.interpreter.engine.Engine.try_rule)
     seegraph(pypy.lang.prolog.interpreter.term.Rule.clone_and_unify_head)
     seegraph(pypy.lang.prolog.interpreter.engine.Engine.call)
+    seegraph(pypy.lang.prolog.interpreter.engine.Engine.user_call)
+    seegraph(pypy.lang.prolog.interpreter.engine.LinkedRules.find_applicable_rule)
     return result_graphs
 
 def get_portal(drv):

Modified: pypy/branch/prolog-jit-experiments/pypy/lang/prolog/interpreter/term.py
==============================================================================
--- pypy/branch/prolog-jit-experiments/pypy/lang/prolog/interpreter/term.py	(original)
+++ pypy/branch/prolog-jit-experiments/pypy/lang/prolog/interpreter/term.py	Fri May 18 14:35:12 2007
@@ -18,6 +18,10 @@
     if DEBUG and not we_are_translated():
         print " ".join([str(a) for a in args])
 
+def pure_hash_function(s):
+    return h(s)
+pure_hash_function._pure_function_ = True
+
 class PrologObject(object):
     __slots__ = ()
     _immutable_ = True
@@ -49,7 +53,7 @@
         # they must not be unifiable
         raise NotImplementedError("abstract base class")
 
-    def unify_hash_of_child(self, i, heap=None):
+    def unify_hash_of_child(self, i):
         raise KeyError
 
     @specialize.arg(3)
@@ -79,6 +83,7 @@
 
     __slots__ = ('index', )
     cache = {}
+    _immutable_ = True
 
     def __init__(self, index):
         self.index = index
@@ -223,6 +228,7 @@
     STANDARD_ORDER = 1
 
     cache = {}
+    _immutable_ = True
 
     def __init__(self, name):
         self.name = name
@@ -253,10 +259,11 @@
             raise UnificationFailed
 
     def get_unify_hash(self):
-        return intmask(hash(self.name) << TAGBITS | self.TAG)
+        name = hint(self.name, promote=True)
+        return intmask(pure_hash_function(name) << TAGBITS | self.TAG)
 
     def get_prolog_signature(self):
-        return Term("/", [self, Number(0)])
+        return Term("/", [self, NUMBER_0])
 
     def newatom(name):
         result = Atom.cache.get(name, None)
@@ -270,6 +277,7 @@
 class Number(NonVar):
     TAG = tag()
     STANDARD_ORDER = 2
+    _immutable_ = True
     def __init__(self, num):
         self.num = num
 
@@ -298,10 +306,12 @@
     def get_unify_hash(self):
         return intmask(self.num << TAGBITS | self.TAG)
 
+NUMBER_0 = Number(0)
 
 class Float(NonVar):
     TAG = tag()
     STANDARD_ORDER = 2
+    _immutable_ = True
     def __init__(self, num):
         self.num = num
 
@@ -374,6 +384,7 @@
 class Term(Callable):
     TAG = tag()
     STANDARD_ORDER = 3
+    _immutable_ = True
     def __init__(self, name, args, signature=None):
         self.name = name
         self.args = args
@@ -453,7 +464,8 @@
             return self
 
     def get_unify_hash(self):
-        return intmask(hash(self.signature) << TAGBITS | self.TAG)
+        signature = hint(self.signature, promote=True)
+        return intmask(pure_hash_function(signature) << TAGBITS | self.TAG)
 
     def unify_hash_of_child(self, i):
         return self.args[i].get_unify_hash()
@@ -506,6 +518,7 @@
     def clone_and_unify_head(self, heap, head):
         memo = {}
         h2 = self.head
+        hint(h2, concrete=True)
         if isinstance(h2, Term):
             assert isinstance(head, Term)
             i = 0
@@ -516,6 +529,7 @@
                 arg2.copy_and_unify(arg1, heap, memo)
                 i += 1
         body = self.body
+        hint(body, concrete=True)
         if body is None:
             return None
         return body.copy(heap, memo)

Modified: pypy/branch/prolog-jit-experiments/pypy/lang/prolog/interpreter/test/test_jit.py
==============================================================================
--- pypy/branch/prolog-jit-experiments/pypy/lang/prolog/interpreter/test/test_jit.py	(original)
+++ pypy/branch/prolog-jit-experiments/pypy/lang/prolog/interpreter/test/test_jit.py	Fri May 18 14:35:12 2007
@@ -1,5 +1,5 @@
 import py
-from pypy.jit.timeshifter.test.test_portal import PortalTest
+from pypy.jit.timeshifter.test.test_portal import PortalTest, P_NOVIRTUAL
 from pypy.lang.prolog.interpreter import portal
 from pypy.lang.prolog.interpreter import engine, term
 from pypy.lang.prolog.interpreter.parsing import parse_query_term, get_engine
@@ -37,11 +37,59 @@
         assert res == True
 
 
-        res = self.timeshift_from_portal(main, engine.Engine.try_rule.im_func,
+        res = self.timeshift_from_portal(main, portal.PORTAL,
                                          [1], policy=POLICY)
         assert res == True
         
-        res = self.timeshift_from_portal(main, engine.Engine.try_rule.im_func,
+        res = self.timeshift_from_portal(main, portal.PORTAL,
+                                         [0], policy=POLICY)
+        assert res == True
+
+    def test_and(self):
+        e = get_engine("""
+            b(a).
+            a(a).
+            f(X) :- b(X), a(X).
+        """)
+        X = e.heap.newvar()
+
+        def main(n):
+            e.heap.reset()
+            if n == 0:
+                e.call(term.Term("f", [X]))
+                return isinstance(X.dereference(e.heap), term.Atom)
+            else:
+                return False
+
+        res = main(0)
+        assert res == True
+
+        res = self.timeshift_from_portal(main, portal.PORTAL,
+                                         [0], policy=POLICY)
+        assert res == True
+
+    def test_user_call(self):
+        e = get_engine("""
+            h(X) :- f(X, b).
+            f(a, a).
+            f(X, b) :- g(X).
+            g(b).
+        """)
+        X = e.heap.newvar()
+
+        def main(n):
+            e.heap.reset()
+            if n == 0:
+                e.call(term.Term("h", [X]))
+                return isinstance(X.dereference(e.heap), term.Atom)
+            else:
+                return False
+
+        res = main(0)
+        assert res == True
+
+
+        res = self.timeshift_from_portal(main, portal.PORTAL,
                                          [0], policy=POLICY)
         assert res == True
 



More information about the Pypy-commit mailing list