Author: Manuel Jacob <[email protected]>
Branch: py3.3
Changeset: r79011:58654aa3cd80
Date: 2015-08-17 02:41 +0200
http://bitbucket.org/pypy/pypy/changeset/58654aa3cd80/
Log: hg merge py3k
diff too long, truncating to 2000 out of 5812 lines
diff --git a/_pytest/assertion/rewrite.py b/_pytest/assertion/rewrite.py
--- a/_pytest/assertion/rewrite.py
+++ b/_pytest/assertion/rewrite.py
@@ -308,7 +308,10 @@
if (len(data) != 8 or data[:4] != imp.get_magic() or
struct.unpack("<l", data[4:])[0] != mtime):
return None
- co = marshal.load(fp)
+ try:
+ co = marshal.load(fp)
+ except ValueError:
+ return None # e.g. bad marshal data because of pypy/cpython mix
if not isinstance(co, types.CodeType):
# That's interesting....
return None
diff --git a/pypy/doc/embedding.rst b/pypy/doc/embedding.rst
--- a/pypy/doc/embedding.rst
+++ b/pypy/doc/embedding.rst
@@ -46,7 +46,11 @@
source. It'll acquire the GIL.
Note: this is meant to be called *only once* or a few times at most. See
- the `more complete example`_ below.
+ the `more complete example`_ below. In PyPy <= 2.6.0, the globals
+ dictionary is *reused* across multiple calls, giving potentially
+ strange results (e.g. objects dying too early). In PyPy >= 2.6.1,
+ you get a new globals dictionary for every call (but then, all globals
+ dictionaries are all kept alive forever, in ``sys._pypy_execute_source``).
.. function:: int pypy_execute_source_ptr(char* source, void* ptr);
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -55,3 +55,15 @@
.. branch: nditer-revisited
Implement nditer 'buffered' flag and fix some edge cases
+
+.. branch: ufunc-reduce
+
+Allow multiple axes in ufunc.reduce()
+
+.. branch: fix-tinylang-goals
+
+Update tinylang goals to match current rpython
+
+.. branch: vmprof-review
+
+Clean up of vmprof, notably to handle correctly multiple threads
diff --git a/pypy/goal/targetpypystandalone.py
b/pypy/goal/targetpypystandalone.py
--- a/pypy/goal/targetpypystandalone.py
+++ b/pypy/goal/targetpypystandalone.py
@@ -135,13 +135,7 @@
@entrypoint('main', [rffi.CCHARP], c_name='pypy_execute_source')
def pypy_execute_source(ll_source):
- after = rffi.aroundstate.after
- if after: after()
- source = rffi.charp2str(ll_source)
- res = _pypy_execute_source(source)
- before = rffi.aroundstate.before
- if before: before()
- return rffi.cast(rffi.INT, res)
+ return pypy_execute_source_ptr(ll_source, 0)
@entrypoint('main', [rffi.CCHARP, lltype.Signed],
c_name='pypy_execute_source_ptr')
@@ -149,9 +143,7 @@
after = rffi.aroundstate.after
if after: after()
source = rffi.charp2str(ll_source)
- space.setitem(w_globals, space.wrap('c_argument'),
- space.wrap(ll_ptr))
- res = _pypy_execute_source(source)
+ res = _pypy_execute_source(source, ll_ptr)
before = rffi.aroundstate.before
if before: before()
return rffi.cast(rffi.INT, res)
@@ -176,15 +168,21 @@
before = rffi.aroundstate.before
if before: before()
- w_globals = space.newdict()
- space.setitem(w_globals, space.wrap('__builtins__'),
- space.builtin_modules['builtins'])
-
- def _pypy_execute_source(source):
+ def _pypy_execute_source(source, c_argument):
try:
- compiler = space.createcompiler()
- stmt = compiler.compile(source, 'c callback', 'exec', 0)
- stmt.exec_code(space, w_globals, w_globals)
+ w_globals = space.newdict(module=True)
+ space.setitem(w_globals, space.wrap('__builtins__'),
+ space.builtin_modules['__builtin__'])
+ space.setitem(w_globals, space.wrap('c_argument'),
+ space.wrap(c_argument))
+ space.appexec([space.wrap(source), w_globals], """(src, glob):
+ import sys
+ stmt = compile(src, 'c callback', 'exec')
+ if not hasattr(sys, '_pypy_execute_source'):
+ sys._pypy_execute_source = []
+ sys._pypy_execute_source.append(glob)
+ exec stmt in glob
+ """)
except OperationError, e:
debug("OperationError:")
debug(" operror-type: " + e.w_type.getname(space).encode('utf-8'))
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -12,7 +12,7 @@
INT_MIN, INT_MAX, UINT_MAX, USHRT_MAX
from pypy.interpreter.executioncontext import (ExecutionContext, ActionFlag,
- UserDelAction, CodeUniqueIds)
+ UserDelAction)
from pypy.interpreter.error import OperationError, new_exception_class, oefmt
from pypy.interpreter.argument import Arguments
from pypy.interpreter.miscutils import ThreadLocals, make_weak_value_dictionary
@@ -398,7 +398,6 @@
self.actionflag = ActionFlag() # changed by the signal module
self.check_signal_action = None # changed by the signal module
self.user_del_action = UserDelAction(self)
- self.code_unique_ids = CodeUniqueIds()
self._code_of_sys_exc_info = None
# can be overridden to a subclass
@@ -690,16 +689,6 @@
assert ec is not None
return ec
- def register_code_callback(self, callback):
- cui = self.code_unique_ids
- cui.code_callback = callback
-
- def register_code_object(self, pycode):
- cui = self.code_unique_ids
- if cui.code_callback is None:
- return
- cui.code_callback(self, pycode)
-
def _freeze_(self):
return True
diff --git a/pypy/interpreter/executioncontext.py
b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -589,11 +589,3 @@
# there is no list of length n: if n is large, then the GC
# will run several times while walking the list, but it will
# see lower and lower memory usage, with no lower bound of n.
-
-class CodeUniqueIds(object):
- def __init__(self):
- if sys.maxint == 2147483647:
- self.code_unique_id = 0 # XXX this is wrong, it won't work on 32bit
- else:
- self.code_unique_id = 0x7000000000000000
- self.code_callback = None
diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py
--- a/pypy/interpreter/pycode.py
+++ b/pypy/interpreter/pycode.py
@@ -109,7 +109,7 @@
self.magic = magic
self._signature = cpython_code_signature(self)
self._initialize()
- space.register_code_object(self)
+ self._init_ready()
def _initialize(self):
if self.co_cellvars:
@@ -152,14 +152,8 @@
from pypy.objspace.std.mapdict import init_mapdict_cache
init_mapdict_cache(self)
- cui = self.space.code_unique_ids
- self._unique_id = cui.code_unique_id
- cui.code_unique_id += 4 # so we have two bits that we can mark stuff
- # with
-
- def _get_full_name(self):
- return "py:%s:%d:%s" % (self.co_name, self.co_firstlineno,
- self.co_filename)
+ def _init_ready(self):
+ "This is a hook for the vmprof module, which overrides this method."
def _cleanup_(self):
if (self.magic == cpython_magic and
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -62,6 +62,7 @@
}
interpleveldefs = {
+ 'attach_gdb' : 'interp_magic.attach_gdb',
'internal_repr' : 'interp_magic.internal_repr',
'bytebuffer' : 'bytebuffer.bytebuffer',
'identity_dict' : 'interp_identitydict.W_IdentityDict',
@@ -98,8 +99,6 @@
def setup_after_space_initialization(self):
"""NOT_RPYTHON"""
- if not self.space.config.translating:
- self.extra_interpdef('interp_pdb', 'interp_magic.interp_pdb')
if self.space.config.objspace.std.withmethodcachecounter:
self.extra_interpdef('method_cache_counter',
'interp_magic.method_cache_counter')
diff --git a/pypy/module/__pypy__/interp_magic.py
b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -15,12 +15,10 @@
return space.wrap('%r' % (w_object,))
-def interp_pdb(space):
- """Run an interp-level pdb.
- This is not available in translated versions of PyPy."""
- assert not we_are_translated()
- import pdb
- pdb.set_trace()
+def attach_gdb(space):
+ """Run an interp-level gdb (or pdb when untranslated)"""
+ from rpython.rlib.debug import attach_gdb
+ attach_gdb()
@unwrap_spec(name=str)
diff --git a/pypy/module/_file/readinto.py b/pypy/module/_file/readinto.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_file/readinto.py
@@ -0,0 +1,81 @@
+import sys, errno
+from rpython.rlib import rposix
+from rpython.rlib.objectmodel import keepalive_until_here
+from rpython.rtyper.lltypesystem import lltype, rffi
+from pypy.module._file.interp_file import is_wouldblock_error, signal_checker
+
+_WIN32 = sys.platform.startswith('win')
+UNDERSCORE_ON_WIN32 = '_' if _WIN32 else ''
+
+os_read = rffi.llexternal(UNDERSCORE_ON_WIN32 + 'read',
+ [rffi.INT, rffi.CCHARP, rffi.SIZE_T],
+ rffi.SIZE_T, save_err=rffi.RFFI_SAVE_ERRNO)
+
+
+def direct_readinto(self, w_rwbuffer):
+ rwbuffer = self.space.writebuf_w(w_rwbuffer)
+ stream = self.getstream()
+ size = rwbuffer.getlength()
+ target_address = lltype.nullptr(rffi.CCHARP.TO)
+ fd = -1
+ target_pos = 0
+
+ if size > 64:
+ try:
+ target_address = rwbuffer.get_raw_address()
+ except ValueError:
+ pass
+ else:
+ fd = stream.try_to_find_file_descriptor()
+
+ if fd < 0 or not target_address:
+ # fall-back
+ MAX_PART = 1024 * 1024 # 1 MB
+ while size > MAX_PART:
+ data = self.direct_read(MAX_PART)
+ rwbuffer.setslice(target_pos, data)
+ target_pos += len(data)
+ size -= len(data)
+ if len(data) != MAX_PART:
+ break
+ else:
+ data = self.direct_read(size)
+ rwbuffer.setslice(target_pos, data)
+ target_pos += len(data)
+
+ else:
+ # optimized case: reading more than 64 bytes into a rwbuffer
+ # with a valid raw address
+ self.check_readable()
+
+ # first "read" the part that is already sitting in buffers, if any
+ initial_size = min(size, stream.count_buffered_bytes())
+ if initial_size > 0:
+ data = stream.read(initial_size)
+ rwbuffer.setslice(target_pos, data)
+ target_pos += len(data)
+ size -= len(data)
+
+ # then call os_read() to get the rest
+ if size > 0:
+ stream.flush()
+ while True:
+ got = os_read(fd, rffi.ptradd(target_address, target_pos),
size)
+ if got > 0:
+ target_pos += got
+ size -= got
+ if size <= 0:
+ break
+ elif got == 0:
+ break
+ else:
+ err = rposix.get_saved_errno()
+ if err == errno.EINTR:
+ signal_checker(self.space)()
+ continue
+ if is_wouldblock_error(err) and target_pos > 0:
+ break
+ raise OSError(err, "read error")
+ keepalive_until_here(rwbuffer)
+
+ return self.space.wrap(target_pos)
diff --git a/pypy/module/_vmprof/__init__.py b/pypy/module/_vmprof/__init__.py
--- a/pypy/module/_vmprof/__init__.py
+++ b/pypy/module/_vmprof/__init__.py
@@ -1,8 +1,9 @@
from pypy.interpreter.mixedmodule import MixedModule
+from rpython.rlib.rvmprof import VMProfPlatformUnsupported
class Module(MixedModule):
"""
- Write me :)
+ VMProf for PyPy: a statistical profiler
"""
appleveldefs = {
}
@@ -10,9 +11,16 @@
interpleveldefs = {
'enable': 'interp_vmprof.enable',
'disable': 'interp_vmprof.disable',
+ 'VMProfError': 'space.fromcache(interp_vmprof.Cache).w_VMProfError',
}
- def setup_after_space_initialization(self):
- # force the __extend__ hacks to occur early
- from pypy.module._vmprof.interp_vmprof import VMProf
- self.vmprof = VMProf()
+
+# Force the __extend__ hacks and method replacements to occur
+# early. Without this, for example, 'PyCode._init_ready' was
+# already found by the annotator to be the original empty
+# method, and the annotator doesn't notice that interp_vmprof.py
+# (loaded later) replaces this method.
+try:
+ import pypy.module._vmprof.interp_vmprof
+except VMProfPlatformUnsupported, e:
+ pass
diff --git a/pypy/module/_vmprof/interp_vmprof.py
b/pypy/module/_vmprof/interp_vmprof.py
--- a/pypy/module/_vmprof/interp_vmprof.py
+++ b/pypy/module/_vmprof/interp_vmprof.py
@@ -1,252 +1,74 @@
-import py, os, sys
-from rpython.rtyper.lltypesystem import lltype, rffi, llmemory
-from rpython.translator.tool.cbuild import ExternalCompilationInfo
-from rpython.rtyper.annlowlevel import cast_instance_to_gcref,
cast_base_ptr_to_instance
-from rpython.rlib.objectmodel import we_are_translated
-from rpython.rlib import jit, rposix, rgc
-from rpython.rlib.rarithmetic import ovfcheck_float_to_int
-from rpython.rtyper.tool import rffi_platform as platform
-from rpython.rlib.rstring import StringBuilder
-from pypy.interpreter.baseobjspace import W_Root
-from pypy.interpreter.error import oefmt, wrap_oserror, OperationError
+from pypy.interpreter.error import OperationError
from pypy.interpreter.gateway import unwrap_spec
from pypy.interpreter.pyframe import PyFrame
from pypy.interpreter.pycode import PyCode
+from pypy.interpreter.baseobjspace import W_Root
+from rpython.rlib import rvmprof
-ROOT = py.path.local(__file__).join('..')
-SRC = ROOT.join('src')
+# ____________________________________________________________
-# by default, we statically link vmprof.c into pypy; however, if you set
-# DYNAMIC_VMPROF to True, it will be dynamically linked to the libvmprof.so
-# which is expected to be inside pypy/module/_vmprof/src: this is very useful
-# during development. Note that you have to manually build libvmprof by
-# running make inside the src dir
-DYNAMIC_VMPROF = False
-if sys.platform.startswith('linux'):
- libs = ['dl']
-else:
- libs = []
+_get_code = lambda frame, w_inputvalue, operr: frame.pycode
+_decorator = rvmprof.vmprof_execute_code("pypy", _get_code, W_Root)
+my_execute_frame = _decorator(PyFrame.execute_frame)
-eci_kwds = dict(
- include_dirs = [SRC],
- includes = ['vmprof.h', 'trampoline.h'],
- separate_module_files = [SRC.join('trampoline.vmprof.s')],
- libraries = libs,
-
- post_include_bits=["""
- int pypy_vmprof_init(void);
- """],
-
- separate_module_sources=["""
- int pypy_vmprof_init(void) {
- return vmprof_set_mainloop(pypy_execute_frame_trampoline, 0,
- NULL);
- }
- """],
- )
-
-
-if DYNAMIC_VMPROF:
- eci_kwds['libraries'] += ['vmprof']
- eci_kwds['link_extra'] = ['-Wl,-rpath,%s' % SRC, '-L%s' % SRC]
-else:
- eci_kwds['separate_module_files'] += [SRC.join('vmprof.c')]
-
-eci = ExternalCompilationInfo(**eci_kwds)
-
-check_eci = eci.merge(ExternalCompilationInfo(separate_module_files=[
- SRC.join('fake_pypy_api.c')]))
-
-platform.verify_eci(check_eci)
-
-pypy_execute_frame_trampoline = rffi.llexternal(
- "pypy_execute_frame_trampoline",
- [llmemory.GCREF, llmemory.GCREF, llmemory.GCREF, lltype.Signed],
- llmemory.GCREF,
- compilation_info=eci,
- _nowrapper=True, sandboxsafe=True,
- random_effects_on_gcobjs=True)
-
-pypy_vmprof_init = rffi.llexternal("pypy_vmprof_init", [], rffi.INT,
- compilation_info=eci)
-vmprof_enable = rffi.llexternal("vmprof_enable",
- [rffi.INT, rffi.LONG, rffi.INT,
- rffi.CCHARP, rffi.INT],
- rffi.INT, compilation_info=eci,
- save_err=rffi.RFFI_SAVE_ERRNO)
-vmprof_disable = rffi.llexternal("vmprof_disable", [], rffi.INT,
- compilation_info=eci,
- save_err=rffi.RFFI_SAVE_ERRNO)
-vmprof_get_error = rffi.llexternal("vmprof_get_error", [], rffi.CCHARP,
- compilation_info=eci,
- save_err=rffi.RFFI_SAVE_ERRNO)
-
-vmprof_register_virtual_function = rffi.llexternal(
- "vmprof_register_virtual_function",
- [rffi.CCHARP, rffi.VOIDP, rffi.VOIDP], lltype.Void,
- compilation_info=eci, _nowrapper=True)
-
-original_execute_frame = PyFrame.execute_frame.im_func
-original_execute_frame.c_name = 'pypy_pyframe_execute_frame'
-original_execute_frame._dont_inline_ = True
class __extend__(PyFrame):
- def execute_frame(frame, w_inputvalue=None, operr=None):
- # go through the asm trampoline ONLY if we are translated but not
being JITted.
- #
- # If we are not translated, we obviously don't want to go through the
- # trampoline because there is no C function it can call.
- #
- # If we are being JITted, we want to skip the trampoline, else the JIT
- # cannot see throug it
- if we_are_translated() and not jit.we_are_jitted():
- # if we are translated, call the trampoline
- gc_frame = cast_instance_to_gcref(frame)
- gc_inputvalue = cast_instance_to_gcref(w_inputvalue)
- gc_operr = cast_instance_to_gcref(operr)
- unique_id = frame.pycode._unique_id
- gc_result = pypy_execute_frame_trampoline(gc_frame, gc_inputvalue,
- gc_operr, unique_id)
- return cast_base_ptr_to_instance(W_Root, gc_result)
- else:
- return original_execute_frame(frame, w_inputvalue, operr)
+ def execute_frame(self, w_inputvalue=None, operr=None):
+ # indirection for the optional arguments
+ return my_execute_frame(self, w_inputvalue, operr)
+def _safe(s):
+ if len(s) > 110:
+ s = s[:107] + '...'
+ return s.replace(':', ';')
-def write_long_to_string_builder(l, b):
- if sys.maxint == 2147483647:
- b.append(chr(l & 0xff))
- b.append(chr((l >> 8) & 0xff))
- b.append(chr((l >> 16) & 0xff))
- b.append(chr((l >> 24) & 0xff))
- else:
- b.append(chr(l & 0xff))
- b.append(chr((l >> 8) & 0xff))
- b.append(chr((l >> 16) & 0xff))
- b.append(chr((l >> 24) & 0xff))
- b.append(chr((l >> 32) & 0xff))
- b.append(chr((l >> 40) & 0xff))
- b.append(chr((l >> 48) & 0xff))
- b.append(chr((l >> 56) & 0xff))
+def _get_full_name(pycode):
+ # careful, must not have extraneous ':' or be longer than 255 chars
+ return "py:%s:%d:%s" % (_safe(pycode.co_name), pycode.co_firstlineno,
+ _safe(pycode.co_filename))
-def try_cast_to_pycode(gcref):
- return rgc.try_cast_gcref_to_instance(PyCode, gcref)
+rvmprof.register_code_object_class(PyCode, _get_full_name)
-MAX_CODES = 1000
-class VMProf(object):
- def __init__(self):
- self.is_enabled = False
- self.ever_enabled = False
- self.fileno = -1
- self.current_codes = []
+def _init_ready(pycode):
+ rvmprof.register_code(pycode, _get_full_name)
- def enable(self, space, fileno, period_usec):
- if self.is_enabled:
- raise oefmt(space.w_ValueError, "_vmprof already enabled")
- self.fileno = fileno
- self.is_enabled = True
- self.write_header(fileno, period_usec)
- if not self.ever_enabled:
- if we_are_translated():
- res = pypy_vmprof_init()
- if res:
- raise OperationError(
- space.w_IOError,
- space.wrap(rffi.charp2str(vmprof_get_error())))
- self.ever_enabled = True
- self.gather_all_code_objs(space)
- space.register_code_callback(vmprof_register_code)
- if we_are_translated():
- # does not work untranslated
- res = vmprof_enable(fileno, period_usec, 0,
- lltype.nullptr(rffi.CCHARP.TO), 0)
- else:
- res = 0
- if res == -1:
- raise wrap_oserror(space, OSError(rposix.get_saved_errno(),
- "_vmprof.enable"))
+PyCode._init_ready = _init_ready
- def gather_all_code_objs(self, space):
- all_code_objs = rgc.do_get_objects(try_cast_to_pycode)
- for code in all_code_objs:
- self.register_code(space, code)
- def write_header(self, fileno, period_usec):
- assert period_usec > 0
- b = StringBuilder()
- write_long_to_string_builder(0, b)
- write_long_to_string_builder(3, b)
- write_long_to_string_builder(0, b)
- write_long_to_string_builder(period_usec, b)
- write_long_to_string_builder(0, b)
- b.append('\x04') # interp name
- b.append(chr(len('pypy')))
- b.append('pypy')
- os.write(fileno, b.build())
+# ____________________________________________________________
- def register_code(self, space, code):
- if self.fileno == -1:
- raise OperationError(space.w_RuntimeError,
- space.wrap("vmprof not running"))
- self.current_codes.append(code)
- if len(self.current_codes) >= MAX_CODES:
- self._flush_codes(space)
- def _flush_codes(self, space):
- b = StringBuilder()
- for code in self.current_codes:
- name = code._get_full_name()
- b.append('\x02')
- write_long_to_string_builder(code._unique_id, b)
- write_long_to_string_builder(len(name), b)
- b.append(name)
- os.write(self.fileno, b.build())
- self.current_codes = []
+class Cache:
+ def __init__(self, space):
+ self.w_VMProfError = space.new_exception_class("_vmprof.VMProfError")
- def disable(self, space):
- if not self.is_enabled:
- raise oefmt(space.w_ValueError, "_vmprof not enabled")
- self.is_enabled = False
- space.register_code_callback(None)
- self._flush_codes(space)
- self.fileno = -1
- if we_are_translated():
- # does not work untranslated
- res = vmprof_disable()
- else:
- res = 0
- if res == -1:
- raise wrap_oserror(space, OSError(rposix.get_saved_errno(),
- "_vmprof.disable"))
+def VMProfError(space, e):
+ w_VMProfError = space.fromcache(Cache).w_VMProfError
+ return OperationError(w_VMProfError, space.wrap(e.msg))
-def vmprof_register_code(space, code):
- from pypy.module._vmprof import Module
- mod_vmprof = space.getbuiltinmodule('_vmprof')
- assert isinstance(mod_vmprof, Module)
- mod_vmprof.vmprof.register_code(space, code)
@unwrap_spec(fileno=int, period=float)
-def enable(space, fileno, period=0.01): # default 100 Hz
- from pypy.module._vmprof import Module
- mod_vmprof = space.getbuiltinmodule('_vmprof')
- assert isinstance(mod_vmprof, Module)
- #
+def enable(space, fileno, period):
+ """Enable vmprof. Writes go to the given 'fileno', a file descriptor
+ opened for writing. *The file descriptor must remain open at least
+ until disable() is called.*
+
+ 'interval' is a float representing the sampling interval, in seconds.
+ Must be smaller than 1.0
+ """
try:
- period_usec = ovfcheck_float_to_int(period * 1000000.0 + 0.5)
- if period_usec <= 0 or period_usec >= 1e6:
- # we don't want seconds here at all
- raise ValueError
- except (ValueError, OverflowError):
- raise OperationError(space.w_ValueError,
- space.wrap("'period' too large or non positive"))
- #
- mod_vmprof.vmprof.enable(space, fileno, period_usec)
+ rvmprof.enable(fileno, period)
+ except rvmprof.VMProfError, e:
+ raise VMProfError(space, e)
def disable(space):
- from pypy.module._vmprof import Module
- mod_vmprof = space.getbuiltinmodule('_vmprof')
- assert isinstance(mod_vmprof, Module)
- mod_vmprof.vmprof.disable(space)
-
+ """Disable vmprof. Remember to close the file descriptor afterwards
+ if necessary.
+ """
+ try:
+ rvmprof.disable()
+ except rvmprof.VMProfError, e:
+ raise VMProfError(space, e)
diff --git a/pypy/module/_vmprof/src/config.h b/pypy/module/_vmprof/src/config.h
deleted file mode 100644
--- a/pypy/module/_vmprof/src/config.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#define HAVE_SYS_UCONTEXT_H
-#if defined(__FreeBSD__) || defined(__APPLE__)
-#define PC_FROM_UCONTEXT uc_mcontext.mc_rip
-#else
-#define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_RIP]
-#endif
diff --git a/pypy/module/_vmprof/src/fake_pypy_api.c
b/pypy/module/_vmprof/src/fake_pypy_api.c
deleted file mode 100644
--- a/pypy/module/_vmprof/src/fake_pypy_api.c
+++ /dev/null
@@ -1,4 +0,0 @@
-
-void pypy_pyframe_execute_frame(void)
-{
-}
diff --git a/pypy/module/_vmprof/src/get_custom_offset.c
b/pypy/module/_vmprof/src/get_custom_offset.c
deleted file mode 100644
--- a/pypy/module/_vmprof/src/get_custom_offset.c
+++ /dev/null
@@ -1,80 +0,0 @@
-
-#ifdef PYPY_JIT_CODEMAP
-
-extern volatile int pypy_codemap_currently_invalid;
-
-void *pypy_find_codemap_at_addr(long addr, long *start_addr);
-long pypy_yield_codemap_at_addr(void *codemap_raw, long addr,
- long *current_pos_addr);
-long pypy_jit_stack_depth_at_loc(long loc);
-
-#endif
-
-
-void vmprof_set_tramp_range(void* start, void* end)
-{
-}
-
-int custom_sanity_check()
-{
-#ifdef PYPY_JIT_CODEMAP
- return !pypy_codemap_currently_invalid;
-#else
- return 1;
-#endif
-}
-
-static ptrdiff_t vmprof_unw_get_custom_offset(void* ip, void *cp) {
-#ifdef PYPY_JIT_CODEMAP
- intptr_t ip_l = (intptr_t)ip;
- return pypy_jit_stack_depth_at_loc(ip_l);
-#else
- return -1;
-#endif
-}
-
-static long vmprof_write_header_for_jit_addr(void **result, long n,
- void *ip, int max_depth)
-{
-#ifdef PYPY_JIT_CODEMAP
- void *codemap;
- long current_pos = 0;
- intptr_t id;
- long start_addr = 0;
- intptr_t addr = (intptr_t)ip;
- int start, k;
- void *tmp;
-
- codemap = pypy_find_codemap_at_addr(addr, &start_addr);
- if (codemap == NULL)
- // not a jit code at all
- return n;
-
- // modify the last entry to point to start address and not the random one
- // in the middle
- result[n - 1] = (void*)start_addr;
- result[n] = (void*)2;
- n++;
- start = n;
- while (n < max_depth) {
- id = pypy_yield_codemap_at_addr(codemap, addr, ¤t_pos);
- if (id == -1)
- // finish
- break;
- if (id == 0)
- continue; // not main codemap
- result[n++] = (void *)id;
- }
- k = 0;
- while (k < (n - start) / 2) {
- tmp = result[start + k];
- result[start + k] = result[n - k - 1];
- result[n - k - 1] = tmp;
- k++;
- }
- if (n < max_depth) {
- result[n++] = (void*)3;
- }
-#endif
- return n;
-}
diff --git a/pypy/module/_vmprof/src/trampoline.h
b/pypy/module/_vmprof/src/trampoline.h
deleted file mode 100644
--- a/pypy/module/_vmprof/src/trampoline.h
+++ /dev/null
@@ -1,1 +0,0 @@
-void* pypy_execute_frame_trampoline(void*, void*, void*, long);
diff --git a/pypy/module/_vmprof/src/trampoline.vmprof.s
b/pypy/module/_vmprof/src/trampoline.vmprof.s
deleted file mode 100644
--- a/pypy/module/_vmprof/src/trampoline.vmprof.s
+++ /dev/null
@@ -1,15 +0,0 @@
-// NOTE: you need to use TABs, not spaces!
-
- .text
- .globl pypy_execute_frame_trampoline
- .type pypy_execute_frame_trampoline, @function
-pypy_execute_frame_trampoline:
- .cfi_startproc
- pushq %rcx
- .cfi_def_cfa_offset 16
- call pypy_pyframe_execute_frame@PLT
- popq %rcx
- .cfi_def_cfa_offset 8
- ret
- .cfi_endproc
- .size pypy_execute_frame_trampoline, .-pypy_execute_frame_trampoline
diff --git a/pypy/module/_vmprof/src/vmprof.c b/pypy/module/_vmprof/src/vmprof.c
deleted file mode 100644
--- a/pypy/module/_vmprof/src/vmprof.c
+++ /dev/null
@@ -1,463 +0,0 @@
-/* VMPROF
- *
- * statistical sampling profiler specifically designed to profile programs
- * which run on a Virtual Machine and/or bytecode interpreter, such as Python,
- * etc.
- *
- * The logic to dump the C stack traces is partly stolen from the code in
gperftools.
- * The file "getpc.h" has been entirely copied from gperftools.
- *
- * Tested only on gcc, linux, x86_64.
- *
- * Copyright (C) 2014-2015
- * Antonio Cuni - [email protected]
- * Maciej Fijalkowski - [email protected]
- *
- */
-
-
-#include "getpc.h" // should be first to get the _GNU_SOURCE dfn
-#include <signal.h>
-#include <stdio.h>
-#include <string.h>
-#include <stddef.h>
-#include <assert.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <pthread.h>
-#include <dlfcn.h>
-
-//#define UNW_LOCAL_ONLY
-//#include <libunwind.h>
-
-#include "vmprof.h"
-#if defined(__FreeBSD__) || defined(__APPLE__)
-#define sighandler_t sig_t
-#endif
-
-#define _unused(x) ((void)x)
-
-#define MAX_FUNC_NAME 128
-#define MAX_STACK_DEPTH 1024
-#define BUFFER_SIZE 8192
-
-
-static int profile_file = 0;
-static char profile_write_buffer[BUFFER_SIZE];
-static int profile_buffer_position = 0;
-void* vmprof_mainloop_func;
-char* vmprof_error = NULL;
-static ptrdiff_t mainloop_sp_offset;
-static vmprof_get_virtual_ip_t mainloop_get_virtual_ip;
-static long last_period_usec = 0;
-static int atfork_hook_installed = 0;
-
-
-/* *************************************************************
- * functions to write a profile file compatible with gperftools
- * *************************************************************
- */
-
-#define MARKER_STACKTRACE '\x01'
-#define MARKER_VIRTUAL_IP '\x02'
-#define MARKER_TRAILER '\x03'
-
-int (*unw_get_reg)(unw_cursor_t*, int, unw_word_t*) = NULL;
-int (*unw_step)(unw_cursor_t*) = NULL;
-int (*unw_init_local)(unw_cursor_t *, unw_context_t *) = NULL;
-int (*unw_get_proc_info)(unw_cursor_t *, unw_proc_info_t *) = NULL;
-
-static void prof_word(long x) {
- ((long*)(profile_write_buffer + profile_buffer_position))[0] = x;
- profile_buffer_position += sizeof(long);
-}
-
-static void prof_header(long period_usec) {
- // XXX never used here?
- prof_word(0);
- prof_word(3);
- prof_word(0);
- prof_word(period_usec);
- prof_word(0);
- write(profile_file, profile_write_buffer, profile_buffer_position);
- profile_buffer_position = 0;
-}
-
-static void prof_write_stacktrace(void** stack, int depth, int count) {
- int i;
- char marker = MARKER_STACKTRACE;
-
- profile_write_buffer[profile_buffer_position++] = MARKER_STACKTRACE;
- prof_word(count);
- prof_word(depth);
- for(i=0; i<depth; i++)
- prof_word((long)stack[i]);
- write(profile_file, profile_write_buffer, profile_buffer_position);
- profile_buffer_position = 0;
-}
-
-
-/* ******************************************************
- * libunwind workaround for process JIT frames correctly
- * ******************************************************
- */
-
-#include "get_custom_offset.c"
-
-typedef struct {
- void* _unused1;
- void* _unused2;
- void* sp;
- void* ip;
- void* _unused3[sizeof(unw_cursor_t)/sizeof(void*) - 4];
-} vmprof_hacked_unw_cursor_t;
-
-static int vmprof_unw_step(unw_cursor_t *cp, int first_run) {
- void* ip;
- void* sp;
- ptrdiff_t sp_offset;
- unw_get_reg (cp, UNW_REG_IP, (unw_word_t*)&ip);
- unw_get_reg (cp, UNW_REG_SP, (unw_word_t*)&sp);
- if (!first_run)
- // make sure we're pointing to the CALL and not to the first
- // instruction after. If the callee adjusts the stack for us
- // it's not safe to be at the instruction after
- ip -= 1;
- sp_offset = vmprof_unw_get_custom_offset(ip, cp);
-
- if (sp_offset == -1) {
- // it means that the ip is NOT in JITted code, so we can use the
- // stardard unw_step
- return unw_step(cp);
- }
- else {
- // this is a horrible hack to manually walk the stack frame, by
- // setting the IP and SP in the cursor
- vmprof_hacked_unw_cursor_t *cp2 = (vmprof_hacked_unw_cursor_t*)cp;
- void* bp = (void*)sp + sp_offset;
- cp2->sp = bp;
- bp -= sizeof(void*);
- cp2->ip = ((void**)bp)[0];
- // the ret is on the top of the stack minus WORD
- return 1;
- }
-}
-
-
-/* *************************************************************
- * functions to dump the stack trace
- * *************************************************************
- */
-
-// The original code here has a comment, "stolen from pprof",
-// about a "__thread int recursive". But general __thread
-// variables are not really supposed to be accessed from a
-// signal handler. Moreover, we are using SIGPROF, which
-// should not be recursively called on the same thread.
-//static __thread int recursive;
-
-int get_stack_trace(void** result, int max_depth, ucontext_t *ucontext) {
- void *ip;
- int n = 0;
- unw_cursor_t cursor;
- unw_context_t uc = *ucontext;
- //if (recursive) {
- // return 0;
- //}
- if (!custom_sanity_check()) {
- return 0;
- }
- //++recursive;
-
- int ret = unw_init_local(&cursor, &uc);
- assert(ret >= 0);
- _unused(ret);
- int first_run = 1;
-
- while (n < max_depth) {
- if (unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t *) &ip) < 0) {
- break;
- }
-
- unw_proc_info_t pip;
- unw_get_proc_info(&cursor, &pip);
-
- /* char funcname[4096]; */
- /* unw_word_t offset; */
- /* unw_get_proc_name(&cursor, funcname, 4096, &offset); */
- /* printf("%s+%#lx <%p>\n", funcname, offset, ip); */
-
- /* if n==0, it means that the signal handler interrupted us while we
- were in the trampoline, so we are not executing (yet) the real main
- loop function; just skip it */
- if (vmprof_mainloop_func &&
- (void*)pip.start_ip == (void*)vmprof_mainloop_func &&
- n > 0) {
- // found main loop stack frame
- void* sp;
- unw_get_reg(&cursor, UNW_REG_SP, (unw_word_t *) &sp);
- void *arg_addr = (char*)sp + mainloop_sp_offset;
- void **arg_ptr = (void**)arg_addr;
- // fprintf(stderr, "stacktrace mainloop: rsp %p &f2 %p offset
%ld\n",
- // sp, arg_addr, mainloop_sp_offset);
- if (mainloop_get_virtual_ip) {
- ip = mainloop_get_virtual_ip(*arg_ptr);
- } else {
- ip = *arg_ptr;
- }
- }
-
- result[n++] = ip;
- n = vmprof_write_header_for_jit_addr(result, n, ip, max_depth);
- if (vmprof_unw_step(&cursor, first_run) <= 0) {
- break;
- }
- first_run = 0;
- }
- //--recursive;
- return n;
-}
-
-
-static int __attribute__((noinline)) frame_forcer(int rv) {
- return rv;
-}
-
-static void sigprof_handler(int sig_nr, siginfo_t* info, void *ucontext) {
- void* stack[MAX_STACK_DEPTH];
- int saved_errno = errno;
- stack[0] = GetPC((ucontext_t*)ucontext);
- int depth = frame_forcer(get_stack_trace(stack+1, MAX_STACK_DEPTH-1,
ucontext));
- depth++; // To account for pc value in stack[0];
- prof_write_stacktrace(stack, depth, 1);
- errno = saved_errno;
-}
-
-/* *************************************************************
- * functions to enable/disable the profiler
- * *************************************************************
- */
-
-static int open_profile(int fd, long period_usec, int write_header, char *s,
- int slen) {
- if ((fd = dup(fd)) == -1) {
- return -1;
- }
- profile_buffer_position = 0;
- profile_file = fd;
- if (write_header)
- prof_header(period_usec);
- if (s)
- write(profile_file, s, slen);
- return 0;
-}
-
-static int close_profile(void) {
- // XXX all of this can happily fail
- FILE* src;
- char buf[BUFSIZ];
- size_t size;
- int marker = MARKER_TRAILER;
- write(profile_file, &marker, 1);
-
-#ifdef __linux__
- // copy /proc/PID/maps to the end of the profile file
- sprintf(buf, "/proc/%d/maps", getpid());
- src = fopen(buf, "r");
- if (!src) {
- vmprof_error = "error opening proc maps";
- return -1;
- }
- while ((size = fread(buf, 1, BUFSIZ, src))) {
- write(profile_file, buf, size);
- }
- fclose(src);
-#else
- // freebsd and mac
- sprintf(buf, "procstat -v %d", getpid());
- src = popen(buf, "r");
- if (!src) {
- vmprof_error = "error calling procstat";
- return -1;
- }
- while ((size = fread(buf, 1, BUFSIZ, src))) {
- write(profile_file, buf, size);
- }
- pclose(src);
-#endif
- close(profile_file);
- return 0;
-}
-
-
-static int install_sigprof_handler(void) {
- struct sigaction sa;
- memset(&sa, 0, sizeof(sa));
- sa.sa_sigaction = sigprof_handler;
- sa.sa_flags = SA_RESTART | SA_SIGINFO;
- if (sigemptyset(&sa.sa_mask) == -1 ||
- sigaction(SIGPROF, &sa, NULL) == -1) {
- return -1;
- }
- return 0;
-}
-
-static int remove_sigprof_handler(void) {
- sighandler_t res = signal(SIGPROF, SIG_DFL);
- if (res == SIG_ERR) {
- return -1;
- }
- return 0;
-};
-
-static int install_sigprof_timer(long period_usec) {
- static struct itimerval timer;
- last_period_usec = period_usec;
- timer.it_interval.tv_sec = 0;
- timer.it_interval.tv_usec = period_usec;
- timer.it_value = timer.it_interval;
- if (setitimer(ITIMER_PROF, &timer, NULL) != 0) {
- return -1;
- }
- return 0;
-}
-
-static int remove_sigprof_timer(void) {
- static struct itimerval timer;
- timer.it_interval.tv_sec = 0;
- timer.it_interval.tv_usec = 0;
- timer.it_value.tv_sec = 0;
- timer.it_value.tv_usec = 0;
- if (setitimer(ITIMER_PROF, &timer, NULL) != 0) {
- return -1;
- }
- return 0;
-}
-
-static void atfork_disable_timer(void) {
- if (last_period_usec) {
- remove_sigprof_timer();
- }
-}
-
-static void atfork_enable_timer(void) {
- if (last_period_usec) {
- install_sigprof_timer(last_period_usec);
- }
-}
-
-static int install_pthread_atfork_hooks(void) {
- /* this is needed to prevent the problems described there:
- - http://code.google.com/p/gperftools/issues/detail?id=278
- - http://lists.debian.org/debian-glibc/2010/03/msg00161.html
-
- TL;DR: if the RSS of the process is large enough, the clone() syscall
- will be interrupted by the SIGPROF before it can complete, then
- retried, interrupted again and so on, in an endless loop. The
- solution is to disable the timer around the fork, and re-enable it
- only inside the parent.
- */
- if (atfork_hook_installed)
- return 0;
- int ret = pthread_atfork(atfork_disable_timer, atfork_enable_timer, NULL);
- if (ret != 0)
- return -1;
- atfork_hook_installed = 1;
- return 0;
-}
-
-/* *************************************************************
- * public API
- * *************************************************************
- */
-
-int vmprof_set_mainloop(void* func, ptrdiff_t sp_offset,
- vmprof_get_virtual_ip_t get_virtual_ip) {
- void *libhandle;
-
- mainloop_sp_offset = sp_offset;
- mainloop_get_virtual_ip = get_virtual_ip;
- vmprof_mainloop_func = func;
- if (!unw_get_reg) {
- if (!(libhandle = dlopen("libunwind.so", RTLD_LAZY | RTLD_LOCAL))) {
- vmprof_error = dlerror();
- return -1;
- }
- if (!(unw_get_reg = dlsym(libhandle, "_ULx86_64_get_reg"))) {
- vmprof_error = dlerror();
- return -1;
- }
- if (!(unw_get_proc_info = dlsym(libhandle,
"_ULx86_64_get_proc_info"))){
- vmprof_error = dlerror();
- return -1;
- }
- if (!(unw_init_local = dlsym(libhandle, "_ULx86_64_init_local"))) {
- vmprof_error = dlerror();
- return -1;
- }
- if (!(unw_step = dlsym(libhandle, "_ULx86_64_step"))) {
- vmprof_error = dlerror();
- return -1;
- }
- }
- return 0;
-}
-
-char* vmprof_get_error()
-{
- char* res;
- res = vmprof_error;
- vmprof_error = NULL;
- return res;
-}
-
-int vmprof_enable(int fd, long period_usec, int write_header, char *s,
- int slen)
-{
- assert(period_usec > 0);
- if (open_profile(fd, period_usec, write_header, s, slen) == -1) {
- return -1;
- }
- if (install_sigprof_handler() == -1) {
- return -1;
- }
- if (install_sigprof_timer(period_usec) == -1) {
- return -1;
- }
- if (install_pthread_atfork_hooks() == -1) {
- return -1;
- }
- return 0;
-}
-
-int vmprof_disable(void) {
- if (remove_sigprof_timer() == -1) {
- return -1;
- }
- last_period_usec = 0;
- if (remove_sigprof_handler() == -1) {
- return -1;
- }
- if (close_profile() == -1) {
- return -1;
- }
- return 0;
-}
-
-void vmprof_register_virtual_function(const char* name, void* start, void*
end) {
- // XXX unused by pypy
- // for now *end is simply ignored
- char buf[1024];
- int lgt = strlen(name) + 2 * sizeof(long) + 1;
-
- if (lgt > 1024) {
- lgt = 1024;
- }
- buf[0] = MARKER_VIRTUAL_IP;
- ((void **)(((void*)buf) + 1))[0] = start;
- ((long *)(((void*)buf) + 1 + sizeof(long)))[0] = lgt - 2 * sizeof(long)
- 1;
- strncpy(buf + 2 * sizeof(long) + 1, name, 1024 - 2 * sizeof(long) - 1);
- write(profile_file, buf, lgt);
-}
diff --git a/pypy/module/_vmprof/src/vmprof.h b/pypy/module/_vmprof/src/vmprof.h
deleted file mode 100644
--- a/pypy/module/_vmprof/src/vmprof.h
+++ /dev/null
@@ -1,121 +0,0 @@
-#ifndef VMPROF_VMPROF_H_
-#define VMPROF_VMPROF_H_
-
-#include <stddef.h>
-#include <stdint.h>
-#include <ucontext.h>
-
-// copied from libunwind.h
-
-typedef enum
- {
- UNW_X86_64_RAX,
- UNW_X86_64_RDX,
- UNW_X86_64_RCX,
- UNW_X86_64_RBX,
- UNW_X86_64_RSI,
- UNW_X86_64_RDI,
- UNW_X86_64_RBP,
- UNW_X86_64_RSP,
- UNW_X86_64_R8,
- UNW_X86_64_R9,
- UNW_X86_64_R10,
- UNW_X86_64_R11,
- UNW_X86_64_R12,
- UNW_X86_64_R13,
- UNW_X86_64_R14,
- UNW_X86_64_R15,
- UNW_X86_64_RIP,
-#ifdef CONFIG_MSABI_SUPPORT
- UNW_X86_64_XMM0,
- UNW_X86_64_XMM1,
- UNW_X86_64_XMM2,
- UNW_X86_64_XMM3,
- UNW_X86_64_XMM4,
- UNW_X86_64_XMM5,
- UNW_X86_64_XMM6,
- UNW_X86_64_XMM7,
- UNW_X86_64_XMM8,
- UNW_X86_64_XMM9,
- UNW_X86_64_XMM10,
- UNW_X86_64_XMM11,
- UNW_X86_64_XMM12,
- UNW_X86_64_XMM13,
- UNW_X86_64_XMM14,
- UNW_X86_64_XMM15,
- UNW_TDEP_LAST_REG = UNW_X86_64_XMM15,
-#else
- UNW_TDEP_LAST_REG = UNW_X86_64_RIP,
-#endif
-
- /* XXX Add other regs here */
-
- /* frame info (read-only) */
- UNW_X86_64_CFA,
-
- UNW_TDEP_IP = UNW_X86_64_RIP,
- UNW_TDEP_SP = UNW_X86_64_RSP,
- UNW_TDEP_BP = UNW_X86_64_RBP,
- UNW_TDEP_EH = UNW_X86_64_RAX
- }
-x86_64_regnum_t;
-
-typedef uint64_t unw_word_t;
-
-#define UNW_TDEP_CURSOR_LEN 127
-
-typedef struct unw_cursor
- {
- unw_word_t opaque[UNW_TDEP_CURSOR_LEN];
- }
-unw_cursor_t;
-
-#define UNW_REG_IP UNW_X86_64_RIP
-#define UNW_REG_SP UNW_X86_64_RSP
-
-typedef ucontext_t unw_context_t;
-
-typedef struct unw_proc_info
- {
- unw_word_t start_ip; /* first IP covered by this procedure */
- unw_word_t end_ip; /* first IP NOT covered by this procedure */
- unw_word_t lsda; /* address of lang.-spec. data area (if any) */
- unw_word_t handler; /* optional personality routine */
- unw_word_t gp; /* global-pointer value for this procedure */
- unw_word_t flags; /* misc. flags */
-
- int format; /* unwind-info format (arch-specific) */
- int unwind_info_size; /* size of the information (if applicable) */
- void *unwind_info; /* unwind-info (arch-specific) */
- }
-unw_proc_info_t;
-
-// functions copied from libunwind using dlopen
-
-extern int (*unw_get_reg)(unw_cursor_t*, int, unw_word_t*);
-extern int (*unw_step)(unw_cursor_t*);
-extern int (*unw_init_local)(unw_cursor_t *, unw_context_t *);
-extern int (*unw_get_proc_info)(unw_cursor_t *, unw_proc_info_t *);
-
-// end of copy
-
-extern char* vmprof_error;
-
-typedef void* (*vmprof_get_virtual_ip_t)(void*);
-char* vmprof_get_error();
-
-extern void* vmprof_mainloop_func;
-int vmprof_set_mainloop(void* func, ptrdiff_t sp_offset,
- vmprof_get_virtual_ip_t get_virtual_ip);
-
-void vmprof_register_virtual_function(const char* name, void* start, void*
end);
-
-
-int vmprof_enable(int fd, long period_usec, int write_header, char* vips,
- int vips_len);
-int vmprof_disable(void);
-
-// XXX: this should be part of _vmprof (the CPython extension), not vmprof
(the library)
-void vmprof_set_tramp_range(void* start, void* end);
-
-#endif
diff --git a/pypy/module/_vmprof/test/test__vmprof.py
b/pypy/module/_vmprof/test/test__vmprof.py
--- a/pypy/module/_vmprof/test/test__vmprof.py
+++ b/pypy/module/_vmprof/test/test__vmprof.py
@@ -1,14 +1,14 @@
-import tempfile
+from rpython.tool.udir import udir
from pypy.tool.pytest.objspace import gettestobjspace
class AppTestVMProf(object):
def setup_class(cls):
cls.space = gettestobjspace(usemodules=['_vmprof', 'struct'])
- cls.tmpfile = tempfile.NamedTemporaryFile()
+ cls.tmpfile = udir.join('test__vmprof.1').open('wb')
cls.w_tmpfileno = cls.space.wrap(cls.tmpfile.fileno())
cls.w_tmpfilename = cls.space.wrap(cls.tmpfile.name)
- cls.tmpfile2 = tempfile.NamedTemporaryFile()
+ cls.tmpfile2 = udir.join('test__vmprof.2').open('wb')
cls.w_tmpfileno2 = cls.space.wrap(cls.tmpfile2.fileno())
cls.w_tmpfilename2 = cls.space.wrap(cls.tmpfile2.name)
@@ -29,17 +29,21 @@
while i < len(s):
if s[i] == 3:
break
- if s[i] == 1:
- xxx
- assert s[i] == 2
- i += 1
- _, size = struct.unpack("ll", s[i:i + 2 * WORD])
- count += 1
- i += 2 * WORD + size
+ elif s[i] == 1:
+ i += 1
+ _, size = struct.unpack("ll", s[i:i + 2 * WORD])
+ i += 2 * WORD + size * struct.calcsize("P")
+ elif s[i] == 2:
+ i += 1
+ _, size = struct.unpack("ll", s[i:i + 2 * WORD])
+ count += 1
+ i += 2 * WORD + size
+ else:
+ raise AssertionError(ord(s[i]))
return count
import _vmprof
- _vmprof.enable(self.tmpfileno)
+ _vmprof.enable(self.tmpfileno, 0.01)
_vmprof.disable()
s = open(self.tmpfilename, 'rb').read()
no_of_codes = count(s)
@@ -53,7 +57,7 @@
pass
""", d)
- _vmprof.enable(self.tmpfileno2)
+ _vmprof.enable(self.tmpfileno2, 0.01)
exec_("""def foo2():
pass
@@ -68,8 +72,9 @@
def test_enable_ovf(self):
import _vmprof
- raises(ValueError, _vmprof.enable, 999, 0)
- raises(ValueError, _vmprof.enable, 999, -2.5)
- raises(ValueError, _vmprof.enable, 999, 1e300)
- raises(ValueError, _vmprof.enable, 999, 1e300 * 1e300)
- raises(ValueError, _vmprof.enable, 999, (1e300*1e300) / (1e300*1e300))
+ raises(_vmprof.VMProfError, _vmprof.enable, 999, 0)
+ raises(_vmprof.VMProfError, _vmprof.enable, 999, -2.5)
+ raises(_vmprof.VMProfError, _vmprof.enable, 999, 1e300)
+ raises(_vmprof.VMProfError, _vmprof.enable, 999, 1e300 * 1e300)
+ NaN = (1e300*1e300) / (1e300*1e300)
+ raises(_vmprof.VMProfError, _vmprof.enable, 999, NaN)
diff --git a/pypy/module/_vmprof/test/test_direct.py
b/pypy/module/_vmprof/test/test_direct.py
--- a/pypy/module/_vmprof/test/test_direct.py
+++ b/pypy/module/_vmprof/test/test_direct.py
@@ -5,7 +5,8 @@
except ImportError:
py.test.skip('cffi required')
-srcdir = py.path.local(__file__).join("..", "..", "src")
+from rpython.rlib import rvmprof
+srcdir = py.path.local(rvmprof.__file__).join("..", "src")
ffi = cffi.FFI()
ffi.cdef("""
@@ -17,6 +18,8 @@
""")
lib = ffi.verify("""
+#define PYPY_JIT_CODEMAP
+
volatile int pypy_codemap_currently_invalid = 0;
long buffer[] = {0, 0, 0, 0, 0};
@@ -39,7 +42,7 @@
}
-""" + open(str(srcdir.join("get_custom_offset.c"))).read())
+""" + open(str(srcdir.join("rvmprof_get_custom_offset.h"))).read())
class TestDirect(object):
def test_infrastructure(self):
diff --git a/pypy/module/cpyext/TODO b/pypy/module/cpyext/TODO
deleted file mode 100644
--- a/pypy/module/cpyext/TODO
+++ /dev/null
@@ -1,26 +0,0 @@
- - Complete the PyTypeObject initialization code. (see XXX in the code)
- - Implement further method callers.
- - Copy the slots from the base.
- - Those tasks are necessary to be able to call slots from C code correctly.
- - Additionally, implement further slot wrappers. This is necessary to call
- slots of PTOs defined in C.
- - Complete the Members support.
-
- - Use a WeakKeyDictionary to count how often a PyObject is allocated for
- a given wrapped object and use this to assess whether optimizations are
- useful
-
- - replace @cpython_api(external=False) by another explicit name: all
- it does is a lltype function pointer, no C code involved.
-
- - Fix GIL handling (e.g. after releasing the GIL, GC operations might occur
in savethreads).
-
- - refactor management of py_objects_r2w and py_objects_w2r, this can
- probably be expressed in terms of _PyObject_GC_TRACK macros.
-
- - PyWeakref_GetObject() returns a borrowed reference, but this turns the
- WeakRef into a strong reference!
-
- - sort out pypy's buffer protocol. PyPy's buffer right now don't support
- raw memory (except array which supports it in a hackish way), which
- should be fixed in order to make it nicely work with cpyext.
diff --git a/pypy/module/micronumpy/casting.py
b/pypy/module/micronumpy/casting.py
--- a/pypy/module/micronumpy/casting.py
+++ b/pypy/module/micronumpy/casting.py
@@ -145,23 +145,32 @@
# equivalent to PyArray_CanCastTypeTo
if origin == target:
return True
- if origin.is_record() or target.is_record():
- return can_cast_record(space, origin, target, casting)
+ if casting == 'unsafe':
+ return True
+ elif casting == 'no':
+ return origin.eq(space, target)
+ if origin.num == target.num:
+ if origin.is_record():
+ return (target.is_record() and
+ can_cast_record(space, origin, target, casting))
+ else:
+ if casting == 'equiv':
+ return origin.elsize == target.elsize
+ elif casting == 'safe':
+ return origin.elsize <= target.elsize
+ else:
+ return True
- if casting == 'no':
- return origin.eq(space, target)
- elif casting == 'equiv':
- return origin.num == target.num and origin.elsize == target.elsize
- elif casting == 'unsafe':
- return True
elif casting == 'same_kind':
if can_cast_to(origin, target):
return True
if origin.kind in kind_ordering and target.kind in kind_ordering:
return kind_ordering[origin.kind] <= kind_ordering[target.kind]
return False
- else: # 'safe'
+ elif casting == 'safe':
return can_cast_to(origin, target)
+ else: # 'equiv'
+ return origin.num == target.num and origin.elsize == target.elsize
def can_cast_record(space, origin, target, casting):
if origin is target:
diff --git a/pypy/module/micronumpy/concrete.py
b/pypy/module/micronumpy/concrete.py
--- a/pypy/module/micronumpy/concrete.py
+++ b/pypy/module/micronumpy/concrete.py
@@ -52,11 +52,16 @@
@jit.unroll_safe
def setslice(self, space, arr):
- if len(arr.get_shape()) > 0 and len(self.get_shape()) == 0:
- raise oefmt(space.w_ValueError,
- "could not broadcast input array from shape "
- "(%s) into shape ()",
- ','.join([str(x) for x in arr.get_shape()]))
+ if len(arr.get_shape()) > len(self.get_shape()):
+ # record arrays get one extra dimension
+ if not self.dtype.is_record() or \
+ len(arr.get_shape()) > len(self.get_shape()) + 1:
+ raise oefmt(space.w_ValueError,
+ "could not broadcast input array from shape "
+ "(%s) into shape (%s)",
+ ','.join([str(x) for x in arr.get_shape()]),
+ ','.join([str(x) for x in self.get_shape()]),
+ )
shape = shape_agreement(space, self.get_shape(), arr)
impl = arr.implementation
if impl.storage == self.storage:
diff --git a/pypy/module/micronumpy/descriptor.py
b/pypy/module/micronumpy/descriptor.py
--- a/pypy/module/micronumpy/descriptor.py
+++ b/pypy/module/micronumpy/descriptor.py
@@ -589,7 +589,8 @@
return space.newtuple([w_class, builder_args, data])
def descr_setstate(self, space, w_data):
- if self.fields is None: # if builtin dtype
+ if self.fields is None and not isinstance(self.itemtype,
types.VoidType):
+ # if builtin dtype (but not w_voiddtype)
return space.w_None
version = space.int_w(space.getitem(w_data, space.wrap(0)))
@@ -1030,6 +1031,11 @@
elif space.isinstance_w(w_dtype, space.w_tuple):
w_dtype0 = space.getitem(w_dtype, space.wrap(0))
w_dtype1 = space.getitem(w_dtype, space.wrap(1))
+ if space.isinstance_w(w_dtype0, space.w_type) and \
+ space.isinstance_w(w_dtype1, space.w_list):
+ #obscure api - (subclass, spec). Ignore the subclass
+ return make_new_dtype(space, w_subtype, w_dtype1, alignment,
+ copy=copy, w_shape=w_shape, w_metadata=w_metadata)
subdtype = make_new_dtype(space, w_subtype, w_dtype0, alignment, copy)
assert isinstance(subdtype, W_Dtype)
if subdtype.elsize == 0:
diff --git a/pypy/module/micronumpy/iterators.py
b/pypy/module/micronumpy/iterators.py
--- a/pypy/module/micronumpy/iterators.py
+++ b/pypy/module/micronumpy/iterators.py
@@ -204,17 +204,16 @@
self.array.setitem(state.offset, elem)
-def AxisIter(array, shape, axis, cumulative):
+def AxisIter(array, shape, axis):
strides = array.get_strides()
backstrides = array.get_backstrides()
- if not cumulative:
- if len(shape) == len(strides):
- # keepdims = True
- strides = strides[:axis] + [0] + strides[axis + 1:]
- backstrides = backstrides[:axis] + [0] + backstrides[axis + 1:]
- else:
- strides = strides[:axis] + [0] + strides[axis:]
- backstrides = backstrides[:axis] + [0] + backstrides[axis:]
+ if len(shape) == len(strides):
+ # keepdims = True
+ strides = strides[:axis] + [0] + strides[axis + 1:]
+ backstrides = backstrides[:axis] + [0] + backstrides[axis + 1:]
+ else:
+ strides = strides[:axis] + [0] + strides[axis:]
+ backstrides = backstrides[:axis] + [0] + backstrides[axis:]
return ArrayIter(array, support.product(shape), shape, strides,
backstrides)
diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py
--- a/pypy/module/micronumpy/loop.py
+++ b/pypy/module/micronumpy/loop.py
@@ -9,7 +9,7 @@
from pypy.module.micronumpy import support, constants as NPY
from pypy.module.micronumpy.base import W_NDimArray, convert_to_array
from pypy.module.micronumpy.iterators import PureShapeIter, AxisIter, \
- AllButAxisIter
+ AllButAxisIter, ArrayIter
from pypy.interpreter.argument import Arguments
@@ -190,23 +190,64 @@
source_state = source_iter.next(source_state)
return target
-reduce_driver = jit.JitDriver(name='numpy_reduce',
- greens = ['shapelen', 'func', 'done_func',
- 'calc_dtype'],
- reds = 'auto')
-def compute_reduce(space, obj, calc_dtype, func, done_func, identity):
- obj_iter, obj_state = obj.create_iter()
+def split_iter(arr, axis_flags):
+ """Prepare 2 iterators for nested iteration over `arr`.
+
+ Arguments:
+ arr: instance of BaseConcreteArray
+ axis_flags: list of bools, one for each dimension of `arr`.The inner
+ iterator operates over the dimensions for which the flag is True
+ """
+ shape = arr.get_shape()
+ strides = arr.get_strides()
+ backstrides = arr.get_backstrides()
+ shapelen = len(shape)
+ assert len(axis_flags) == shapelen
+ inner_shape = [-1] * shapelen
+ inner_strides = [-1] * shapelen
+ inner_backstrides = [-1] * shapelen
+ outer_shape = [-1] * shapelen
+ outer_strides = [-1] * shapelen
+ outer_backstrides = [-1] * shapelen
+ for i in range(len(shape)):
+ if axis_flags[i]:
+ inner_shape[i] = shape[i]
+ inner_strides[i] = strides[i]
+ inner_backstrides[i] = backstrides[i]
+ outer_shape[i] = 1
+ outer_strides[i] = 0
+ outer_backstrides[i] = 0
+ else:
+ outer_shape[i] = shape[i]
+ outer_strides[i] = strides[i]
+ outer_backstrides[i] = backstrides[i]
+ inner_shape[i] = 1
+ inner_strides[i] = 0
+ inner_backstrides[i] = 0
+ inner_iter = ArrayIter(arr, support.product(inner_shape),
+ inner_shape, inner_strides, inner_backstrides)
+ outer_iter = ArrayIter(arr, support.product(outer_shape),
+ outer_shape, outer_strides, outer_backstrides)
+ return inner_iter, outer_iter
+
+
+reduce_flat_driver = jit.JitDriver(
+ name='numpy_reduce_flat',
+ greens = ['shapelen', 'func', 'done_func', 'calc_dtype'], reds = 'auto')
+
+def reduce_flat(space, func, w_arr, calc_dtype, done_func, identity):
+ obj_iter, obj_state = w_arr.create_iter()
if identity is None:
cur_value = obj_iter.getitem(obj_state).convert_to(space, calc_dtype)
obj_state = obj_iter.next(obj_state)
else:
cur_value = identity.convert_to(space, calc_dtype)
- shapelen = len(obj.get_shape())
+ shapelen = len(w_arr.get_shape())
while not obj_iter.done(obj_state):
- reduce_driver.jit_merge_point(shapelen=shapelen, func=func,
- done_func=done_func,
- calc_dtype=calc_dtype)
+ reduce_flat_driver.jit_merge_point(
+ shapelen=shapelen, func=func,
+ done_func=done_func, calc_dtype=calc_dtype)
rval = obj_iter.getitem(obj_state).convert_to(space, calc_dtype)
if done_func is not None and done_func(calc_dtype, rval):
return rval
@@ -214,33 +255,105 @@
obj_state = obj_iter.next(obj_state)
return cur_value
-reduce_cum_driver = jit.JitDriver(
- name='numpy_reduce_cum_driver',
+
+reduce_driver = jit.JitDriver(
+ name='numpy_reduce',
+ greens=['shapelen', 'func', 'dtype'], reds='auto')
+
+def reduce(space, func, w_arr, axis_flags, dtype, out, identity):
+ out_iter, out_state = out.create_iter()
+ out_iter.track_index = False
+ shape = w_arr.get_shape()
+ shapelen = len(shape)
+ inner_iter, outer_iter = split_iter(w_arr.implementation, axis_flags)
+ assert outer_iter.size == out_iter.size
+
+ if identity is not None:
+ identity = identity.convert_to(space, dtype)
+ outer_state = outer_iter.reset()
+ while not outer_iter.done(outer_state):
+ inner_state = inner_iter.reset()
+ inner_state.offset = outer_state.offset
+ if identity is not None:
+ w_val = identity
+ else:
+ w_val = inner_iter.getitem(inner_state).convert_to(space, dtype)
+ inner_state = inner_iter.next(inner_state)
+ while not inner_iter.done(inner_state):
+ reduce_driver.jit_merge_point(
+ shapelen=shapelen, func=func, dtype=dtype)
+ w_item = inner_iter.getitem(inner_state).convert_to(space, dtype)
+ w_val = func(dtype, w_item, w_val)
+ inner_state = inner_iter.next(inner_state)
+ out_iter.setitem(out_state, w_val)
+ out_state = out_iter.next(out_state)
+ outer_state = outer_iter.next(outer_state)
+ return out
+
+accumulate_flat_driver = jit.JitDriver(
+ name='numpy_accumulate_flat',
greens=['shapelen', 'func', 'dtype', 'out_dtype'],
reds='auto')
-def compute_reduce_cumulative(space, obj, out, calc_dtype, func, identity):
- obj_iter, obj_state = obj.create_iter()
- out_iter, out_state = out.create_iter()
+def accumulate_flat(space, func, w_arr, calc_dtype, w_out, identity):
+ arr_iter, arr_state = w_arr.create_iter()
+ out_iter, out_state = w_out.create_iter()
out_iter.track_index = False
if identity is None:
- cur_value = obj_iter.getitem(obj_state).convert_to(space, calc_dtype)
+ cur_value = arr_iter.getitem(arr_state).convert_to(space, calc_dtype)
out_iter.setitem(out_state, cur_value)
out_state = out_iter.next(out_state)
- obj_state = obj_iter.next(obj_state)
+ arr_state = arr_iter.next(arr_state)
else:
cur_value = identity.convert_to(space, calc_dtype)
- shapelen = len(obj.get_shape())
- out_dtype = out.get_dtype()
- while not obj_iter.done(obj_state):
- reduce_cum_driver.jit_merge_point(
- shapelen=shapelen, func=func,
- dtype=calc_dtype, out_dtype=out_dtype)
- rval = obj_iter.getitem(obj_state).convert_to(space, calc_dtype)
- cur_value = func(calc_dtype, cur_value, rval)
+ shapelen = len(w_arr.get_shape())
+ out_dtype = w_out.get_dtype()
+ while not arr_iter.done(arr_state):
+ accumulate_flat_driver.jit_merge_point(
+ shapelen=shapelen, func=func, dtype=calc_dtype,
+ out_dtype=out_dtype)
+ w_item = arr_iter.getitem(arr_state).convert_to(space, calc_dtype)
+ cur_value = func(calc_dtype, cur_value, w_item)
out_iter.setitem(out_state, out_dtype.coerce(space, cur_value))
out_state = out_iter.next(out_state)
- obj_state = obj_iter.next(obj_state)
+ arr_state = arr_iter.next(arr_state)
+
+accumulate_driver = jit.JitDriver(
+ name='numpy_accumulate',
+ greens=['shapelen', 'func', 'calc_dtype'], reds='auto')
+
+
+def accumulate(space, func, w_arr, axis, calc_dtype, w_out, identity):
+ out_iter, out_state = w_out.create_iter()
+ arr_shape = w_arr.get_shape()
+ temp_shape = arr_shape[:axis] + arr_shape[axis + 1:]
+ temp = W_NDimArray.from_shape(space, temp_shape, calc_dtype,
w_instance=w_arr)
+ temp_iter = AxisIter(temp.implementation, w_arr.get_shape(), axis)
+ temp_state = temp_iter.reset()
+ arr_iter, arr_state = w_arr.create_iter()
+ arr_iter.track_index = False
+ if identity is not None:
+ identity = identity.convert_to(space, calc_dtype)
+ shapelen = len(arr_shape)
+ while not out_iter.done(out_state):
+ accumulate_driver.jit_merge_point(shapelen=shapelen, func=func,
+ calc_dtype=calc_dtype)
+ w_item = arr_iter.getitem(arr_state).convert_to(space, calc_dtype)
+ arr_state = arr_iter.next(arr_state)
+
+ out_indices = out_iter.indices(out_state)
+ if out_indices[axis] == 0:
+ if identity is not None:
+ w_item = func(calc_dtype, identity, w_item)
+ else:
+ cur_value = temp_iter.getitem(temp_state)
+ w_item = func(calc_dtype, cur_value, w_item)
+
+ out_iter.setitem(out_state, w_item)
+ out_state = out_iter.next(out_state)
+ temp_iter.setitem(temp_state, w_item)
+ temp_state = temp_iter.next(temp_state)
+ return w_out
def fill(arr, box):
arr_iter, arr_state = arr.create_iter()
@@ -298,64 +411,56 @@
state = x_state
return out
-axis_reduce_driver = jit.JitDriver(name='numpy_axis_reduce',
- greens=['shapelen', 'func', 'dtype'],
- reds='auto')
-
-def do_axis_reduce(space, shape, func, arr, dtype, axis, out, identity,
cumulative,
- temp):
- out_iter = AxisIter(out.implementation, arr.get_shape(), axis, cumulative)
- out_state = out_iter.reset()
- if cumulative:
- temp_iter = AxisIter(temp.implementation, arr.get_shape(), axis, False)
- temp_state = temp_iter.reset()
- else:
- temp_iter = out_iter # hack
- temp_state = out_state
- arr_iter, arr_state = arr.create_iter()
- arr_iter.track_index = False
- if identity is not None:
- identity = identity.convert_to(space, dtype)
- shapelen = len(shape)
- while not out_iter.done(out_state):
- axis_reduce_driver.jit_merge_point(shapelen=shapelen, func=func,
- dtype=dtype)
- w_val = arr_iter.getitem(arr_state).convert_to(space, dtype)
- arr_state = arr_iter.next(arr_state)
-
- out_indices = out_iter.indices(out_state)
- if out_indices[axis] == 0:
- if identity is not None:
- w_val = func(dtype, identity, w_val)
- else:
- cur = temp_iter.getitem(temp_state)
- w_val = func(dtype, cur, w_val)
-
- out_iter.setitem(out_state, w_val)
- out_state = out_iter.next(out_state)
- if cumulative:
- temp_iter.setitem(temp_state, w_val)
- temp_state = temp_iter.next(temp_state)
- else:
- temp_state = out_state
- return out
-
def _new_argmin_argmax(op_name):
arg_driver = jit.JitDriver(name='numpy_' + op_name,
greens = ['shapelen', 'dtype'],
reds = 'auto')
+ arg_flat_driver = jit.JitDriver(name='numpy_flat_' + op_name,
+ greens = ['shapelen', 'dtype'],
+ reds = 'auto')
- def argmin_argmax(arr):
+ def argmin_argmax(space, w_arr, w_out, axis):
+ from pypy.module.micronumpy.descriptor import get_dtype_cache
+ dtype = w_arr.get_dtype()
+ shapelen = len(w_arr.get_shape())
+ axis_flags = [False] * shapelen
+ axis_flags[axis] = True
+ inner_iter, outer_iter = split_iter(w_arr.implementation, axis_flags)
+ outer_state = outer_iter.reset()
+ out_iter, out_state = w_out.create_iter()
+ while not outer_iter.done(outer_state):
+ inner_state = inner_iter.reset()
+ inner_state.offset = outer_state.offset
+ cur_best = inner_iter.getitem(inner_state)
+ inner_state = inner_iter.next(inner_state)
+ result = 0
+ idx = 1
+ while not inner_iter.done(inner_state):
+ arg_driver.jit_merge_point(shapelen=shapelen, dtype=dtype)
+ w_val = inner_iter.getitem(inner_state)
+ new_best = getattr(dtype.itemtype, op_name)(cur_best, w_val)
+ if dtype.itemtype.ne(new_best, cur_best):
+ result = idx
+ cur_best = new_best
+ inner_state = inner_iter.next(inner_state)
+ idx += 1
+ result = get_dtype_cache(space).w_longdtype.box(result)
+ out_iter.setitem(out_state, result)
+ out_state = out_iter.next(out_state)
+ outer_state = outer_iter.next(outer_state)
+ return w_out
+
+ def argmin_argmax_flat(w_arr):
result = 0
idx = 1
- dtype = arr.get_dtype()
- iter, state = arr.create_iter()
+ dtype = w_arr.get_dtype()
+ iter, state = w_arr.create_iter()
cur_best = iter.getitem(state)
state = iter.next(state)
- shapelen = len(arr.get_shape())
+ shapelen = len(w_arr.get_shape())
while not iter.done(state):
- arg_driver.jit_merge_point(shapelen=shapelen, dtype=dtype)
+ arg_flat_driver.jit_merge_point(shapelen=shapelen, dtype=dtype)
w_val = iter.getitem(state)
new_best = getattr(dtype.itemtype, op_name)(cur_best, w_val)
if dtype.itemtype.ne(new_best, cur_best):
@@ -364,9 +469,10 @@
state = iter.next(state)
idx += 1
return result
- return argmin_argmax
-argmin = _new_argmin_argmax('min')
-argmax = _new_argmin_argmax('max')
+
+ return argmin_argmax, argmin_argmax_flat
+argmin, argmin_flat = _new_argmin_argmax('min')
+argmax, argmax_flat = _new_argmin_argmax('max')
dot_driver = jit.JitDriver(name = 'numpy_dot',
greens = ['dtype'],
diff --git a/pypy/module/micronumpy/ndarray.py
b/pypy/module/micronumpy/ndarray.py
--- a/pypy/module/micronumpy/ndarray.py
+++ b/pypy/module/micronumpy/ndarray.py
@@ -23,6 +23,8 @@
get_shape_from_iterable, shape_agreement, shape_agreement_multiple,
is_c_contiguous, is_f_contiguous, calc_strides, new_view)
from pypy.module.micronumpy.casting import can_cast_array
+from pypy.module.micronumpy.descriptor import get_dtype_cache
+
def _match_dot_shapes(space, left, right):
@@ -245,6 +247,20 @@
if space.is_w(w_idx, space.w_Ellipsis):
self.implementation.setslice(space, convert_to_array(space,
w_value))
return
+ # TODO: multiarray/mapping.c calls a subclass's __getitem__ here, which
+ # is a big performance hit but necessary for the matrix class. The
original
+ # C code is like:
+ #/*
+ #* WARNING: There is a huge special case here. If this is not a
+ #* base class array, we have to get the view through its
+ #* very own index machinery.
+ #* Many subclasses should probably call __setitem__
+ #* with a base class ndarray view to avoid this.
+ #*/
+ #else if (!(index_type & (HAS_FANCY | HAS_SCALAR_ARRAY))
+ # && !PyArray_CheckExact(self)) {
+ #view = (PyArrayObject *)PyObject_GetItem((PyObject *)self, ind);
+
elif isinstance(w_idx, W_NDimArray) and w_idx.get_dtype().is_bool() \
and w_idx.ndims() > 0:
self.setitem_filter(space, w_idx, convert_to_array(space, w_value))
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit