Author: Carl Friedrich Bolz <cfb...@gmx.de> Branch: Changeset: r86909:aab338e52409 Date: 2016-09-06 16:50 +0200 http://bitbucket.org/pypy/pypy/changeset/aab338e52409/
Log: improve the trace of import statements to not contain calls (needed slightly awkward code) diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -259,10 +259,8 @@ raise oefmt(space.w_ValueError, "Empty module name") w = space.wrap - if w_fromlist is not None and space.is_true(w_fromlist): - fromlist_w = space.fixedview(w_fromlist) - else: - fromlist_w = None + if w_fromlist is not None and not space.is_true(w_fromlist): + w_fromlist = None rel_modulename = None if (level != 0 and w_globals is not None and @@ -284,19 +282,19 @@ w_mod = None else: w_mod = absolute_import(space, rel_modulename, rel_level, - fromlist_w, tentative=True) + w_fromlist, tentative=True) else: w_mod = absolute_import(space, rel_modulename, rel_level, - fromlist_w, tentative=False) + w_fromlist, tentative=False) if w_mod is not None: return w_mod - w_mod = absolute_import(space, modulename, 0, fromlist_w, tentative=0) + w_mod = absolute_import(space, modulename, 0, w_fromlist, tentative=0) if rel_modulename is not None: space.setitem(space.sys.get('modules'), w(rel_modulename), space.w_None) return w_mod -def absolute_import(space, modulename, baselevel, fromlist_w, tentative): +def absolute_import(space, modulename, baselevel, w_fromlist, tentative): # Short path: check in sys.modules, but only if there is no conflict # on the import lock. In the situation of 'import' statements # inside tight loops, this should be true, and absolute_import_try() @@ -304,25 +302,25 @@ # if the import lock is currently held by another thread, then we # have to wait, and so shouldn't use the fast path. if not getimportlock(space).lock_held_by_someone_else(): - w_mod = absolute_import_try(space, modulename, baselevel, fromlist_w) + w_mod = absolute_import_try(space, modulename, baselevel, w_fromlist) if w_mod is not None and not space.is_w(w_mod, space.w_None): return w_mod return absolute_import_with_lock(space, modulename, baselevel, - fromlist_w, tentative) + w_fromlist, tentative) @jit.dont_look_inside def absolute_import_with_lock(space, modulename, baselevel, - fromlist_w, tentative): + w_fromlist, tentative): lock = getimportlock(space) lock.acquire_lock() try: return _absolute_import(space, modulename, baselevel, - fromlist_w, tentative) + w_fromlist, tentative) finally: lock.release_lock(silent_after_fork=True) @jit.unroll_safe -def absolute_import_try(space, modulename, baselevel, fromlist_w): +def absolute_import_try(space, modulename, baselevel, w_fromlist): """ Only look up sys.modules, not actually try to load anything """ w_path = None @@ -330,7 +328,7 @@ if '.' not in modulename: w_mod = check_sys_modules_w(space, modulename) first = w_mod - if fromlist_w is not None and w_mod is not None: + if w_fromlist is not None and w_mod is not None: w_path = try_getattr(space, w_mod, space.wrap('__path__')) else: level = 0 @@ -345,28 +343,36 @@ return None if level == baselevel: first = w_mod - if fromlist_w is not None: + if w_fromlist is not None: w_path = try_getattr(space, w_mod, space.wrap('__path__')) level += 1 - if fromlist_w is not None: + if w_fromlist is not None: + # bit artificial code but important to not just unwrap w_fromlist + # to get a better trace. if it is unwrapped, the immutability of the + # tuple is lost if w_path is not None: - if len(fromlist_w) == 1 and space.eq_w(fromlist_w[0], - space.wrap('*')): + length = space.len_w(w_fromlist) + if length == 1 and space.eq_w( + space.getitem(w_fromlist, space.wrap(0)), + space.wrap('*')): w_all = try_getattr(space, w_mod, space.wrap('__all__')) if w_all is not None: - fromlist_w = space.fixedview(w_all) + w_fromlist = w_all else: - fromlist_w = [] + w_fromlist = None # "from x import *" with x already imported and no x.__all__ # always succeeds without doing more imports. It will # just copy everything from x.__dict__ as it is now. - for w_name in fromlist_w: - if try_getattr(space, w_mod, w_name) is None: - return None + + if w_fromlist is not None: + for i in range(length): + w_name = space.getitem(w_fromlist, space.wrap(i)) + if try_getattr(space, w_mod, w_name) is None: + return None return w_mod return first -def _absolute_import(space, modulename, baselevel, fromlist_w, tentative): +def _absolute_import(space, modulename, baselevel, w_fromlist, tentative): w = space.wrap if '/' in modulename or '\\' in modulename: @@ -394,18 +400,23 @@ w_path = try_getattr(space, w_mod, w('__path__')) level += 1 - if fromlist_w is not None: + if w_fromlist is not None: if w_path is not None: - if len(fromlist_w) == 1 and space.eq_w(fromlist_w[0],w('*')): + length = space.len_w(w_fromlist) + if length == 1 and space.eq_w( + space.getitem(w_fromlist, space.wrap(0)), + space.wrap('*')): w_all = try_getattr(space, w_mod, w('__all__')) if w_all is not None: - fromlist_w = space.fixedview(w_all) + w_fromlist = w_all else: - fromlist_w = [] - for w_name in fromlist_w: - if try_getattr(space, w_mod, w_name) is None: - load_part(space, w_path, prefix, space.str0_w(w_name), - w_mod, tentative=1) + w_fromlist = None + if w_fromlist is not None: + for i in range(length): + w_name = space.getitem(w_fromlist, space.wrap(i)) + if try_getattr(space, w_mod, w_name) is None: + load_part(space, w_path, prefix, space.str0_w(w_name), + w_mod, tentative=1) return w_mod else: return first diff --git a/pypy/module/pypyjit/test_pypy_c/test_import.py b/pypy/module/pypyjit/test_pypy_c/test_import.py --- a/pypy/module/pypyjit/test_pypy_c/test_import.py +++ b/pypy/module/pypyjit/test_pypy_c/test_import.py @@ -38,3 +38,27 @@ # call_may_force(absolute_import_with_lock). for opname in log.opnames(loop.allops(opcode="IMPORT_NAME")): assert 'call' not in opname # no call-like opcode + + def test_import_fast_path(self, tmpdir): + print tmpdir + pkg = tmpdir.join('mypkg').ensure(dir=True) + subdir = pkg.join("sub").ensure(dir=True) + pkg.join('__init__.py').write("") + subdir.join('__init__.py').write("") + subdir.join('mod.py').write(str(py.code.Source(""" + def do_the_import(): + import sys + """))) + def main(path, n): + def do_the_import(): + from mypkg.sub import mod + import sys + sys.path.append(path) + for i in range(n): + do_the_import() + # + log = self.run(main, [str(tmpdir), 300]) + loop, = log.loops_by_filename(self.filepath) + # check that no string compares and other calls are there + for opname in log.opnames(loop.allops(opcode="IMPORT_NAME")): + assert 'call' not in opname # no call-like opcode diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -64,6 +64,8 @@ def setitem_str(self, w_dict, key, w_value): cell = self.getdictvalue_no_unwrapping(w_dict, key) + #if (key == '__package__' or key == "__path__") and cell is not None and w_value is not cell: + # print "WARNING", key, w_value, cell, self return self._setitem_str_cell_known(cell, w_dict, key, w_value) def _setitem_str_cell_known(self, cell, w_dict, key, w_value): _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit