Author: Remi Meier <remi.me...@gmail.com> Branch: stmgc-c4 Changeset: r66405:27b6cc609d16 Date: 2013-08-28 17:55 +0200 http://bitbucket.org/pypy/pypy/changeset/27b6cc609d16/
Log: move rgc.no_release_gil to backendopt diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py --- a/rpython/memory/gctransform/framework.py +++ b/rpython/memory/gctransform/framework.py @@ -46,34 +46,6 @@ return (op.opname in LL_OPERATIONS and LL_OPERATIONS[op.opname].canmallocgc) -class GilAnalyzer(graphanalyze.BoolGraphAnalyzer): - - def analyze_direct_call(self, graph, seen=None): - try: - func = graph.func - except AttributeError: - pass - else: - if getattr(func, '_gctransformer_hint_close_stack_', False): - return True - if getattr(func, '_transaction_break_', False): - return True - - return graphanalyze.BoolGraphAnalyzer.analyze_direct_call( - self, graph, seen) - - def analyze_external_call(self, op, seen=None): - funcobj = op.args[0].value._obj - if getattr(funcobj, 'transactionsafe', False): - return False - else: - return False - - def analyze_instantiate_call(self, seen=None): - return False - - def analyze_simple_operation(self, op, graphinfo): - return False def find_initializing_stores(collect_analyzer, graph): @@ -281,9 +253,6 @@ self.collect_analyzer = CollectAnalyzer(self.translator) self.collect_analyzer.analyze_all() - self.gil_analyzer = GilAnalyzer(self.translator) - self.gil_analyzer.analyze_all() - s_gc = self.translator.annotator.bookkeeper.valueoftype(GCClass) r_gc = self.translator.rtyper.getrepr(s_gc) self.c_const_gc = rmodel.inputconst(r_gc, self.gcdata.gc) @@ -673,27 +642,6 @@ raise Exception("'no_collect' function can trigger collection:" " %s\n%s" % (func, err.getvalue())) - if func and getattr(func, '_no_release_gil_', False): - if self.gil_analyzer.analyze_direct_call(graph): - # 'no_release_gil' function can release the gil - import cStringIO - err = cStringIO.StringIO() - import sys - prev = sys.stdout - try: - sys.stdout = err - ca = GilAnalyzer(self.translator) - ca.verbose = True - ca.analyze_direct_call(graph) # print the "traceback" here - sys.stdout = prev - except: - sys.stdout = prev - # ^^^ for the dump of which operation in which graph actually - # causes it to return True - raise Exception("'no_release_gil' function can release the GIL:" - " %s\n%s" % (func, err.getvalue())) - - if self.write_barrier_ptr: self.clean_sets = ( find_initializing_stores(self.collect_analyzer, graph)) diff --git a/rpython/memory/gctransform/test/test_framework.py b/rpython/memory/gctransform/test/test_framework.py --- a/rpython/memory/gctransform/test/test_framework.py +++ b/rpython/memory/gctransform/test/test_framework.py @@ -5,7 +5,7 @@ from rpython.rtyper.lltypesystem.lloperation import llop from rpython.memory.gc.semispace import SemiSpaceGC from rpython.memory.gctransform.framework import (CollectAnalyzer, - find_initializing_stores, find_clean_setarrayitems, GilAnalyzer) + find_initializing_stores, find_clean_setarrayitems) from rpython.memory.gctransform.shadowstack import ( ShadowStackFrameworkGCTransformer) from rpython.memory.gctransform.test.test_transform import rtype @@ -99,36 +99,6 @@ t = rtype(g, []) gg = graphof(t, g) assert CollectAnalyzer(t).analyze_direct_call(gg) - -def test_canrelease_external(): - for ths in ['auto', True, False]: - for sbxs in [True, False]: - fext = rffi.llexternal('fext2', [], lltype.Void, - threadsafe=ths, sandboxsafe=sbxs) - def g(): - fext() - t = rtype(g, []) - gg = graphof(t, g) - - releases = (ths == 'auto' and not sbxs) or ths is True - assert releases == GilAnalyzer(t).analyze_direct_call(gg) - -def test_canrelease_instantiate(): - class O: - pass - class A(O): - pass - class B(O): - pass - - classes = [A, B] - def g(i): - classes[i]() - - t = rtype(g, [int]) - gg = graphof(t, g) - assert not GilAnalyzer(t).analyze_direct_call(gg) - def test_no_collect(gc="minimark"): from rpython.rlib import rgc @@ -155,60 +125,6 @@ def test_no_collect_stm(): test_no_collect("stmgc") -def test_no_release_gil(gc="minimark"): - from rpython.rlib import rgc - from rpython.translator.c.genc import CStandaloneBuilder - - @rgc.no_release_gil - def g(): - return 1 - - assert g._dont_inline_ - assert g._no_release_gil_ - - def entrypoint(argv): - return g() + 2 - - t = rtype(entrypoint, [s_list_of_strings]) - if gc == "stmgc": - t.config.translation.stm = True - t.config.translation.gc = gc - cbuild = CStandaloneBuilder(t, entrypoint, t.config, - gcpolicy=FrameworkGcPolicy2) - db = cbuild.generate_graphs_for_llinterp() - -def test_no_release_gil_stm(): - test_no_release_gil("stmgc") - -def test_no_release_gil_detect(gc="minimark"): - from rpython.rlib import rgc - from rpython.translator.c.genc import CStandaloneBuilder - - fext1 = rffi.llexternal('fext1', [], lltype.Void, threadsafe=True) - @rgc.no_release_gil - def g(): - fext1() - return 1 - - assert g._dont_inline_ - assert g._no_release_gil_ - - def entrypoint(argv): - return g() + 2 - - t = rtype(entrypoint, [s_list_of_strings]) - if gc == "stmgc": - t.config.translation.stm = True - t.config.translation.gc = gc - cbuild = CStandaloneBuilder(t, entrypoint, t.config, - gcpolicy=FrameworkGcPolicy2) - f = py.test.raises(Exception, cbuild.generate_graphs_for_llinterp) - expected = "'no_release_gil' function can release the GIL: <function g at " - assert str(f.value).startswith(expected) - -def test_no_release_gil_detect_stm(): - test_no_release_gil_detect("stmgc") - def test_no_collect_detection(gc="minimark"): from rpython.rlib import rgc from rpython.translator.c.genc import CStandaloneBuilder diff --git a/rpython/translator/backendopt/all.py b/rpython/translator/backendopt/all.py --- a/rpython/translator/backendopt/all.py +++ b/rpython/translator/backendopt/all.py @@ -11,6 +11,7 @@ from rpython.translator.backendopt.support import log from rpython.translator.backendopt.checkvirtual import check_virtual_methods from rpython.translator.backendopt.storesink import storesink_graph +from rpython.translator.backendopt import gilanalysis from rpython.flowspace.model import checkgraph INLINE_THRESHOLD_FOR_TEST = 33 @@ -142,6 +143,9 @@ for graph in graphs: checkgraph(graph) + gilanalysis.analyze(graphs, translator) + + def constfold(config, graphs): if config.constfold: for graph in graphs: diff --git a/rpython/translator/backendopt/gilanalysis.py b/rpython/translator/backendopt/gilanalysis.py new file mode 100644 --- /dev/null +++ b/rpython/translator/backendopt/gilanalysis.py @@ -0,0 +1,56 @@ +from rpython.translator.backendopt import graphanalyze + +class GilAnalyzer(graphanalyze.BoolGraphAnalyzer): + + def analyze_direct_call(self, graph, seen=None): + try: + func = graph.func + except AttributeError: + pass + else: + if getattr(func, '_gctransformer_hint_close_stack_', False): + return True + if getattr(func, '_transaction_break_', False): + return True + + return graphanalyze.BoolGraphAnalyzer.analyze_direct_call( + self, graph, seen) + + def analyze_external_call(self, op, seen=None): + funcobj = op.args[0].value._obj + if getattr(funcobj, 'transactionsafe', False): + return False + else: + return False + + def analyze_instantiate_call(self, seen=None): + return False + + def analyze_simple_operation(self, op, graphinfo): + return False + +def analyze(graphs, translator): + gilanalyzer = GilAnalyzer(translator) + for graph in graphs: + func = getattr(graph, 'func', None) + if func and getattr(func, '_no_release_gil_', False): + if gilanalyzer.analyze_direct_call(graph): + # 'no_release_gil' function can release the gil + import cStringIO + err = cStringIO.StringIO() + import sys + prev = sys.stdout + try: + sys.stdout = err + ca = GilAnalyzer(translator) + ca.verbose = True + ca.analyze_direct_call(graph) # print the "traceback" here + sys.stdout = prev + except: + sys.stdout = prev + # ^^^ for the dump of which operation in which graph actually + # causes it to return True + raise Exception("'no_release_gil' function can release the GIL:" + " %s\n%s" % (func, err.getvalue())) + + diff --git a/rpython/translator/backendopt/test/test_gilanalysis.py b/rpython/translator/backendopt/test/test_gilanalysis.py new file mode 100644 --- /dev/null +++ b/rpython/translator/backendopt/test/test_gilanalysis.py @@ -0,0 +1,80 @@ +import py + +from rpython.annotator.listdef import s_list_of_strings +from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.translator.backendopt import gilanalysis +from rpython.memory.gctransform.test.test_transform import rtype +from rpython.translator.translator import graphof + +def test_canrelease_external(): + for ths in ['auto', True, False]: + for sbxs in [True, False]: + fext = rffi.llexternal('fext2', [], lltype.Void, + threadsafe=ths, sandboxsafe=sbxs) + def g(): + fext() + t = rtype(g, []) + gg = graphof(t, g) + + releases = (ths == 'auto' and not sbxs) or ths is True + assert releases == gilanalysis.GilAnalyzer(t).analyze_direct_call(gg) + +def test_canrelease_instantiate(): + class O: + pass + class A(O): + pass + class B(O): + pass + + classes = [A, B] + def g(i): + classes[i]() + + t = rtype(g, [int]) + gg = graphof(t, g) + assert not gilanalysis.GilAnalyzer(t).analyze_direct_call(gg) + + + +def test_no_release_gil(): + from rpython.rlib import rgc + + @rgc.no_release_gil + def g(): + return 1 + + assert g._dont_inline_ + assert g._no_release_gil_ + + def entrypoint(argv): + return g() + 2 + + t = rtype(entrypoint, [s_list_of_strings]) + gilanalysis.analyze(t.graphs, t) + + + +def test_no_release_gil_detect(gc="minimark"): + from rpython.rlib import rgc + + fext1 = rffi.llexternal('fext1', [], lltype.Void, threadsafe=True) + @rgc.no_release_gil + def g(): + fext1() + return 1 + + assert g._dont_inline_ + assert g._no_release_gil_ + + def entrypoint(argv): + return g() + 2 + + t = rtype(entrypoint, [s_list_of_strings]) + f = py.test.raises(Exception, gilanalysis.analyze, t.graphs, t) + expected = "'no_release_gil' function can release the GIL: <function g at " + assert str(f.value).startswith(expected) + + + + _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit