Author: mattip Branch: numpypy-axisops Changeset: r50919:1714b0167e37 Date: 2011-12-28 03:02 +0200 http://bitbucket.org/pypy/pypy/changeset/1714b0167e37/
Log: merge with default diff --git a/pypy/interpreter/eval.py b/pypy/interpreter/eval.py --- a/pypy/interpreter/eval.py +++ b/pypy/interpreter/eval.py @@ -98,7 +98,6 @@ "Abstract. Get the expected number of locals." raise TypeError, "abstract" - @jit.dont_look_inside def fast2locals(self): # Copy values from the fastlocals to self.w_locals if self.w_locals is None: @@ -112,7 +111,6 @@ w_name = self.space.wrap(name) self.space.setitem(self.w_locals, w_name, w_value) - @jit.dont_look_inside def locals2fast(self): # Copy values from self.w_locals to the fastlocals assert self.w_locals is not None diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -619,7 +619,8 @@ self.descr_reqcls, args) except Exception, e: - raise self.handle_exception(space, e) + self.handle_exception(space, e) + w_result = None if w_result is None: w_result = space.w_None return w_result @@ -655,7 +656,8 @@ self.descr_reqcls, args) except Exception, e: - raise self.handle_exception(space, e) + self.handle_exception(space, e) + w_result = None if w_result is None: w_result = space.w_None return w_result @@ -674,7 +676,8 @@ self.descr_reqcls, args.prepend(w_obj)) except Exception, e: - raise self.handle_exception(space, e) + self.handle_exception(space, e) + w_result = None if w_result is None: w_result = space.w_None return w_result @@ -690,7 +693,8 @@ raise OperationError(space.w_SystemError, space.wrap("unexpected DescrMismatch error")) except Exception, e: - raise self.handle_exception(space, e) + self.handle_exception(space, e) + w_result = None if w_result is None: w_result = space.w_None return w_result @@ -708,7 +712,8 @@ self.descr_reqcls, Arguments(space, [w1])) except Exception, e: - raise self.handle_exception(space, e) + self.handle_exception(space, e) + w_result = None if w_result is None: w_result = space.w_None return w_result @@ -726,7 +731,8 @@ self.descr_reqcls, Arguments(space, [w1, w2])) except Exception, e: - raise self.handle_exception(space, e) + self.handle_exception(space, e) + w_result = None if w_result is None: w_result = space.w_None return w_result @@ -744,7 +750,8 @@ self.descr_reqcls, Arguments(space, [w1, w2, w3])) except Exception, e: - raise self.handle_exception(space, e) + self.handle_exception(space, e) + w_result = None if w_result is None: w_result = space.w_None return w_result @@ -763,7 +770,8 @@ Arguments(space, [w1, w2, w3, w4])) except Exception, e: - raise self.handle_exception(space, e) + self.handle_exception(space, e) + w_result = None if w_result is None: w_result = space.w_None return w_result diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -39,6 +39,7 @@ from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.codewriter import longlong from pypy.rlib.rarithmetic import intmask +from pypy.rlib.objectmodel import compute_unique_id # darwin requires the stack to be 16 bytes aligned on calls. Same for gcc 4.5.0, # better safe than sorry @@ -58,7 +59,8 @@ self.is_guard_not_invalidated = is_guard_not_invalidated DEBUG_COUNTER = lltype.Struct('DEBUG_COUNTER', ('i', lltype.Signed), - ('bridge', lltype.Signed), # 0 or 1 + ('type', lltype.Char), # 'b'ridge, 'l'abel or + # 'e'ntry point ('number', lltype.Signed)) class Assembler386(object): @@ -147,12 +149,15 @@ def finish_once(self): if self._debug: debug_start('jit-backend-counts') - for struct in self.loop_run_counters: - if struct.bridge: - prefix = 'bridge ' + for i in range(len(self.loop_run_counters)): + struct = self.loop_run_counters[i] + if struct.type == 'l': + prefix = 'TargetToken(%d)' % struct.number + elif struct.type == 'b': + prefix = 'bridge ' + str(struct.number) else: - prefix = 'loop ' - debug_print(prefix + str(struct.number) + ':' + str(struct.i)) + prefix = 'entry ' + str(struct.number) + debug_print(prefix + ':' + str(struct.i)) debug_stop('jit-backend-counts') def _build_float_constants(self): @@ -422,8 +427,8 @@ self.setup(looptoken) if log: - self._register_counter(False, looptoken.number) - operations = self._inject_debugging_code(looptoken, operations) + operations = self._inject_debugging_code(looptoken, operations, + 'e', looptoken.number) regalloc = RegAlloc(self, self.cpu.translate_support_code) # @@ -489,8 +494,8 @@ self.setup(original_loop_token) if log: - self._register_counter(True, descr_number) - operations = self._inject_debugging_code(faildescr, operations) + operations = self._inject_debugging_code(faildescr, operations, + 'b', descr_number) arglocs = self.rebuild_faillocs_from_descr(failure_recovery) if not we_are_translated(): @@ -597,17 +602,21 @@ return self.mc.materialize(self.cpu.asmmemmgr, allblocks, self.cpu.gc_ll_descr.gcrootmap) - def _register_counter(self, bridge, number): - if self._debug: - # YYY very minor leak -- we need the counters to stay alive - # forever, just because we want to report them at the end - # of the process - struct = lltype.malloc(DEBUG_COUNTER, flavor='raw', - track_allocation=False) - struct.i = 0 - struct.bridge = int(bridge) + def _register_counter(self, tp, number, token): + # YYY very minor leak -- we need the counters to stay alive + # forever, just because we want to report them at the end + # of the process + struct = lltype.malloc(DEBUG_COUNTER, flavor='raw', + track_allocation=False) + struct.i = 0 + struct.type = tp + if tp == 'b' or tp == 'e': struct.number = number - self.loop_run_counters.append(struct) + else: + assert token + struct.number = compute_unique_id(token) + self.loop_run_counters.append(struct) + return struct def _find_failure_recovery_bytecode(self, faildescr): adr_jump_offset = faildescr._x86_adr_jump_offset @@ -651,27 +660,36 @@ targettoken._x86_loop_code += rawstart self.target_tokens_currently_compiling = None + def _append_debugging_code(self, operations, tp, number, token): + counter = self._register_counter(tp, number, token) + c_adr = ConstInt(rffi.cast(lltype.Signed, counter)) + box = BoxInt() + box2 = BoxInt() + ops = [ResOperation(rop.GETFIELD_RAW, [c_adr], + box, descr=self.debug_counter_descr), + ResOperation(rop.INT_ADD, [box, ConstInt(1)], box2), + ResOperation(rop.SETFIELD_RAW, [c_adr, box2], + None, descr=self.debug_counter_descr)] + operations.extend(ops) + @specialize.argtype(1) - def _inject_debugging_code(self, looptoken, operations): + def _inject_debugging_code(self, looptoken, operations, tp, number): if self._debug: # before doing anything, let's increase a counter s = 0 for op in operations: s += op.getopnum() looptoken._x86_debug_checksum = s - c_adr = ConstInt(rffi.cast(lltype.Signed, - self.loop_run_counters[-1])) - box = BoxInt() - box2 = BoxInt() - ops = [ResOperation(rop.GETFIELD_RAW, [c_adr], - box, descr=self.debug_counter_descr), - ResOperation(rop.INT_ADD, [box, ConstInt(1)], box2), - ResOperation(rop.SETFIELD_RAW, [c_adr, box2], - None, descr=self.debug_counter_descr)] - if operations[0].getopnum() == rop.LABEL: - operations = [operations[0]] + ops + operations[1:] - else: - operations = ops + operations + + newoperations = [] + self._append_debugging_code(newoperations, tp, number, + None) + for op in operations: + newoperations.append(op) + if op.getopnum() == rop.LABEL: + self._append_debugging_code(newoperations, 'l', number, + op.getdescr()) + operations = newoperations return operations def _assemble(self, regalloc, operations): diff --git a/pypy/jit/backend/x86/test/test_runner.py b/pypy/jit/backend/x86/test/test_runner.py --- a/pypy/jit/backend/x86/test/test_runner.py +++ b/pypy/jit/backend/x86/test/test_runner.py @@ -519,6 +519,7 @@ from pypy.tool.logparser import parse_log_file, extract_category from pypy.rlib import debug + targettoken, preambletoken = TargetToken(), TargetToken() loop = """ [i0] label(i0, descr=preambletoken) @@ -533,8 +534,8 @@ guard_false(i12) [] jump(i11, descr=targettoken) """ - ops = parse(loop, namespace={'targettoken': TargetToken(), - 'preambletoken': TargetToken()}) + ops = parse(loop, namespace={'targettoken': targettoken, + 'preambletoken': preambletoken}) debug._log = dlog = debug.DebugLog() try: self.cpu.assembler.set_debug(True) @@ -545,11 +546,16 @@ struct = self.cpu.assembler.loop_run_counters[0] assert struct.i == 1 struct = self.cpu.assembler.loop_run_counters[1] - assert struct.i == 10 + assert struct.i == 1 + struct = self.cpu.assembler.loop_run_counters[2] + assert struct.i == 9 self.cpu.finish_once() finally: debug._log = None - assert ('jit-backend-counts', [('debug_print', 'loop -1:10')]) in dlog + l0 = ('debug_print', 'entry -1:1') + l1 = ('debug_print', preambletoken.repr_of_descr() + ':1') + l2 = ('debug_print', targettoken.repr_of_descr() + ':9') + assert ('jit-backend-counts', [l0, l1, l2]) in dlog def test_debugger_checksum(self): loop = """ diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py --- a/pypy/jit/codewriter/support.py +++ b/pypy/jit/codewriter/support.py @@ -162,7 +162,6 @@ _ll_4_list_setslice = rlist.ll_listsetslice _ll_2_list_delslice_startonly = rlist.ll_listdelslice_startonly _ll_3_list_delslice_startstop = rlist.ll_listdelslice_startstop -_ll_1_list_list2fixed = lltypesystem_rlist.ll_list2fixed _ll_2_list_inplace_mul = rlist.ll_inplace_mul _ll_2_list_getitem_foldable = _ll_2_list_getitem diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py --- a/pypy/jit/metainterp/compile.py +++ b/pypy/jit/metainterp/compile.py @@ -112,33 +112,26 @@ """ from pypy.jit.metainterp.optimizeopt import optimize_trace - history = metainterp.history metainterp_sd = metainterp.staticdata jitdriver_sd = metainterp.jitdriver_sd + history = metainterp.history - if False: - part = partial_trace - assert False - procedur_token = metainterp.get_procedure_token(greenkey) - assert procedure_token - all_target_tokens = [] - else: - jitcell_token = make_jitcell_token(jitdriver_sd) - part = create_empty_loop(metainterp) - part.inputargs = inputargs[:] - h_ops = history.operations - part.resume_at_jump_descr = resume_at_jump_descr - part.operations = [ResOperation(rop.LABEL, inputargs, None, descr=TargetToken(jitcell_token))] + \ - [h_ops[i].clone() for i in range(start, len(h_ops))] + \ - [ResOperation(rop.LABEL, jumpargs, None, descr=jitcell_token)] + jitcell_token = make_jitcell_token(jitdriver_sd) + part = create_empty_loop(metainterp) + part.inputargs = inputargs[:] + h_ops = history.operations + part.resume_at_jump_descr = resume_at_jump_descr + part.operations = [ResOperation(rop.LABEL, inputargs, None, descr=TargetToken(jitcell_token))] + \ + [h_ops[i].clone() for i in range(start, len(h_ops))] + \ + [ResOperation(rop.LABEL, jumpargs, None, descr=jitcell_token)] - try: - optimize_trace(metainterp_sd, part, jitdriver_sd.warmstate.enable_opts) - except InvalidLoop: - return None - target_token = part.operations[0].getdescr() - assert isinstance(target_token, TargetToken) - all_target_tokens = [target_token] + try: + optimize_trace(metainterp_sd, part, jitdriver_sd.warmstate.enable_opts) + except InvalidLoop: + return None + target_token = part.operations[0].getdescr() + assert isinstance(target_token, TargetToken) + all_target_tokens = [target_token] loop = create_empty_loop(metainterp) loop.inputargs = part.inputargs @@ -319,7 +312,10 @@ metainterp_sd.stats.compiled() metainterp_sd.log("compiled new " + type) # - metainterp_sd.logger_ops.log_loop(loop.inputargs, loop.operations, n, type, ops_offset) + loopname = jitdriver_sd.warmstate.get_location_str(greenkey) + metainterp_sd.logger_ops.log_loop(loop.inputargs, loop.operations, n, + type, ops_offset, + name=loopname) # if metainterp_sd.warmrunnerdesc is not None: # for tests metainterp_sd.warmrunnerdesc.memory_manager.keep_loop_alive(original_jitcell_token) diff --git a/pypy/jit/metainterp/heapcache.py b/pypy/jit/metainterp/heapcache.py --- a/pypy/jit/metainterp/heapcache.py +++ b/pypy/jit/metainterp/heapcache.py @@ -79,9 +79,9 @@ opnum == rop.COPYSTRCONTENT or opnum == rop.COPYUNICODECONTENT): return - if rop._OVF_FIRST <= opnum <= rop._OVF_LAST: - return - if rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST: + if (rop._OVF_FIRST <= opnum <= rop._OVF_LAST or + rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST or + rop._GUARD_FIRST <= opnum <= rop._GUARD_LAST): return if opnum == rop.CALL or opnum == rop.CALL_LOOPINVARIANT: effectinfo = descr.get_extra_info() diff --git a/pypy/jit/metainterp/logger.py b/pypy/jit/metainterp/logger.py --- a/pypy/jit/metainterp/logger.py +++ b/pypy/jit/metainterp/logger.py @@ -13,14 +13,14 @@ self.metainterp_sd = metainterp_sd self.guard_number = guard_number - def log_loop(self, inputargs, operations, number=0, type=None, ops_offset=None): + def log_loop(self, inputargs, operations, number=0, type=None, ops_offset=None, name=''): if type is None: debug_start("jit-log-noopt-loop") logops = self._log_operations(inputargs, operations, ops_offset) debug_stop("jit-log-noopt-loop") else: debug_start("jit-log-opt-loop") - debug_print("# Loop", number, ":", type, + debug_print("# Loop", number, '(%s)' % name , ":", type, "with", len(operations), "ops") logops = self._log_operations(inputargs, operations, ops_offset) debug_stop("jit-log-opt-loop") diff --git a/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py b/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py --- a/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py @@ -1,10 +1,13 @@ from __future__ import with_statement from pypy.jit.metainterp.optimizeopt.test.test_util import ( - LLtypeMixin, BaseTest, Storage, _sortboxes, FakeDescrWithSnapshot) + LLtypeMixin, BaseTest, Storage, _sortboxes, FakeDescrWithSnapshot, + FakeMetaInterpStaticData) from pypy.jit.metainterp.history import TreeLoop, JitCellToken, TargetToken from pypy.jit.metainterp.resoperation import rop, opname, ResOperation from pypy.jit.metainterp.optimize import InvalidLoop from py.test import raises +from pypy.jit.metainterp.optimizeopt.optimizer import Optimization +from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method class BaseTestMultiLabel(BaseTest): enable_opts = "intbounds:rewrite:virtualize:string:earlyforce:pure:heap:unroll" @@ -84,6 +87,8 @@ return optimized +class OptimizeoptTestMultiLabel(BaseTestMultiLabel): + def test_simple(self): ops = """ [i1] @@ -381,6 +386,55 @@ """ self.optimize_loop(ops, expected) -class TestLLtype(BaseTestMultiLabel, LLtypeMixin): + +class OptRenameStrlen(Optimization): + def propagate_forward(self, op): + dispatch_opt(self, op) + + def optimize_STRLEN(self, op): + newop = op.clone() + newop.result = op.result.clonebox() + self.emit_operation(newop) + self.make_equal_to(op.result, self.getvalue(newop.result)) + +dispatch_opt = make_dispatcher_method(OptRenameStrlen, 'optimize_', + default=OptRenameStrlen.emit_operation) + +class BaseTestOptimizerRenamingBoxes(BaseTestMultiLabel): + + def _do_optimize_loop(self, loop, call_pure_results): + from pypy.jit.metainterp.optimizeopt.unroll import optimize_unroll + from pypy.jit.metainterp.optimizeopt.util import args_dict + from pypy.jit.metainterp.optimizeopt.pure import OptPure + + self.loop = loop + loop.call_pure_results = args_dict() + metainterp_sd = FakeMetaInterpStaticData(self.cpu) + optimize_unroll(metainterp_sd, loop, [OptRenameStrlen(), OptPure()], True) + + def test_optimizer_renaming_boxes(self): + ops = """ + [p1] + i1 = strlen(p1) + label(p1) + i2 = strlen(p1) + i3 = int_add(i2, 7) + jump(p1) + """ + expected = """ + [p1] + i1 = strlen(p1) + label(p1, i1) + i11 = same_as(i1) + i2 = int_add(i11, 7) + jump(p1, i11) + """ + self.optimize_loop(ops, expected) + + + +class TestLLtype(OptimizeoptTestMultiLabel, LLtypeMixin): pass +class TestOptimizerRenamingBoxesLLtype(BaseTestOptimizerRenamingBoxes, LLtypeMixin): + pass diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -7759,7 +7759,7 @@ jump(i0, p0, i2) """ self.optimize_loop(ops, expected) - + class TestLLtype(OptimizeOptTest, LLtypeMixin): pass diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -265,7 +265,12 @@ self.optimizer.importable_values[value] = imp newvalue = self.optimizer.getvalue(op.result) newresult = newvalue.get_key_box() - assert newresult is op.result or newvalue.is_constant() + # note that emitting here SAME_AS should not happen, but + # in case it does, we would prefer to be suboptimal in asm + # to a fatal RPython exception. + if newresult is not op.result and not newvalue.is_constant(): + op = ResOperation(rop.SAME_AS, [op.result], newresult) + self.optimizer._newoperations.append(op) self.optimizer.flush() self.optimizer.emitting_dissabled = False diff --git a/pypy/jit/metainterp/test/test_compile.py b/pypy/jit/metainterp/test/test_compile.py --- a/pypy/jit/metainterp/test/test_compile.py +++ b/pypy/jit/metainterp/test/test_compile.py @@ -18,7 +18,7 @@ self.seen.append((inputargs, operations, token)) class FakeLogger(object): - def log_loop(self, inputargs, operations, number=0, type=None, ops_offset=None): + def log_loop(self, inputargs, operations, number=0, type=None, ops_offset=None, name=''): pass def repr_of_resop(self, op): diff --git a/pypy/jit/metainterp/test/test_heapcache.py b/pypy/jit/metainterp/test/test_heapcache.py --- a/pypy/jit/metainterp/test/test_heapcache.py +++ b/pypy/jit/metainterp/test/test_heapcache.py @@ -255,6 +255,11 @@ assert h.getarrayitem(box1, descr1, index1) is box2 assert h.getarrayitem(box1, descr1, index2) is box4 + h.invalidate_caches(rop.GUARD_TRUE, None, []) + assert h.getfield(box1, descr1) is box2 + assert h.getarrayitem(box1, descr1, index1) is box2 + assert h.getarrayitem(box1, descr1, index2) is box4 + h.invalidate_caches( rop.CALL_LOOPINVARIANT, FakeCallDescr(FakeEffektinfo.EF_LOOPINVARIANT), []) diff --git a/pypy/jit/metainterp/test/test_logger.py b/pypy/jit/metainterp/test/test_logger.py --- a/pypy/jit/metainterp/test/test_logger.py +++ b/pypy/jit/metainterp/test/test_logger.py @@ -180,7 +180,7 @@ def test_intro_loop(self): bare_logger = logger.Logger(self.make_metainterp_sd()) output = capturing(bare_logger.log_loop, [], [], 1, "foo") - assert output.splitlines()[0] == "# Loop 1 : foo with 0 ops" + assert output.splitlines()[0] == "# Loop 1 () : foo with 0 ops" pure_parse(output) def test_intro_bridge(self): diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -4,6 +4,7 @@ class PyPyModule(MixedModule): interpleveldefs = { 'debug_repr': 'interp_extras.debug_repr', + 'remove_invalidates': 'interp_extras.remove_invalidates', } appleveldefs = {} diff --git a/pypy/module/micronumpy/interp_extras.py b/pypy/module/micronumpy/interp_extras.py --- a/pypy/module/micronumpy/interp_extras.py +++ b/pypy/module/micronumpy/interp_extras.py @@ -5,3 +5,11 @@ @unwrap_spec(array=BaseArray) def debug_repr(space, array): return space.wrap(array.find_sig().debug_repr()) + +@unwrap_spec(array=BaseArray) +def remove_invalidates(space, array): + """ Array modification will no longer invalidate any of it's + potential children. Use only for performance debugging + """ + del array.invalidates[:] + return space.w_None diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1,6 +1,6 @@ from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.gateway import interp2app, unwrap_spec, NoneNotWrapped +from pypy.interpreter.gateway import interp2app, NoneNotWrapped from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.module.micronumpy import interp_ufuncs, interp_dtype, signature from pypy.module.micronumpy.strides import calculate_slice_strides @@ -14,22 +14,26 @@ numpy_driver = jit.JitDriver( greens=['shapelen', 'sig'], virtualizables=['frame'], - reds=['result_size', 'frame', 'ri', 'self', 'result'] + reds=['result_size', 'frame', 'ri', 'self', 'result'], + get_printable_location=signature.new_printable_location('numpy'), ) all_driver = jit.JitDriver( greens=['shapelen', 'sig'], virtualizables=['frame'], - reds=['frame', 'self', 'dtype'] + reds=['frame', 'self', 'dtype'], + get_printable_location=signature.new_printable_location('all'), ) any_driver = jit.JitDriver( greens=['shapelen', 'sig'], virtualizables=['frame'], - reds=['frame', 'self', 'dtype'] + reds=['frame', 'self', 'dtype'], + get_printable_location=signature.new_printable_location('any'), ) slice_driver = jit.JitDriver( greens=['shapelen', 'sig'], virtualizables=['frame'], - reds=['self', 'frame', 'source', 'res_iter'] + reds=['self', 'frame', 'source', 'res_iter'], + get_printable_location=signature.new_printable_location('slice'), ) def _find_shape_and_elems(space, w_iterable): @@ -294,7 +298,8 @@ def _reduce_argmax_argmin_impl(op_name): reduce_driver = jit.JitDriver( greens=['shapelen', 'sig'], - reds=['result', 'idx', 'frame', 'self', 'cur_best', 'dtype'] + reds=['result', 'idx', 'frame', 'self', 'cur_best', 'dtype'], + get_printable_location=signature.new_printable_location(op_name), ) def loop(self): sig = self.find_sig() @@ -581,8 +586,8 @@ strides.append(concrete.strides[i]) backstrides.append(concrete.backstrides[i]) shape.append(concrete.shape[i]) - return space.wrap(W_NDimSlice(concrete.start, strides[:], - backstrides[:], shape[:], concrete)) + return space.wrap(W_NDimSlice(concrete.start, strides, + backstrides, shape, concrete)) def descr_get_flatiter(self, space): return space.wrap(W_FlatIterator(self)) @@ -886,8 +891,8 @@ if self.order == 'C': strides.reverse() backstrides.reverse() - self.strides = strides[:] - self.backstrides = backstrides[:] + self.strides = strides + self.backstrides = backstrides def array_sig(self, res_shape): if res_shape is not None and self.shape != res_shape: @@ -1092,9 +1097,9 @@ strides.reverse() backstrides.reverse() new_shape.reverse() - self.strides = strides[:] - self.backstrides = backstrides[:] - self.shape = new_shape[:] + self.strides = strides + self.backstrides = backstrides + self.shape = new_shape return new_strides = calc_new_strides(new_shape, self.shape, self.strides) if new_strides is None: @@ -1104,7 +1109,7 @@ for nd in range(len(new_shape)): new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd] self.strides = new_strides[:] - self.backstrides = new_backstrides[:] + self.backstrides = new_backstrides self.shape = new_shape[:] class W_NDimArray(ConcreteArray): diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -1,10 +1,10 @@ from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.gateway import interp2app, unwrap_spec +from pypy.interpreter.gateway import interp2app from pypy.interpreter.typedef import TypeDef, GetSetProperty, interp_attrproperty -from pypy.module.micronumpy import interp_boxes, interp_dtype, types -from pypy.module.micronumpy.signature import (ReduceSignature, - ScalarSignature, find_sig) +from pypy.module.micronumpy import interp_boxes, interp_dtype +from pypy.module.micronumpy.signature import ReduceSignature, ScalarSignature,\ + find_sig, new_printable_location from pypy.rlib import jit from pypy.rlib.rarithmetic import LONG_BIT from pypy.tool.sourcetools import func_with_new_name @@ -12,7 +12,8 @@ reduce_driver = jit.JitDriver( greens = ['shapelen', "sig"], virtualizables = ["frame"], - reds = ["frame", "self", "dtype", "value", "obj"] + reds = ["frame", "self", "dtype", "value", "obj"], + get_printable_location=new_printable_location('reduce'), ) class W_Ufunc(Wrappable): diff --git a/pypy/module/micronumpy/signature.py b/pypy/module/micronumpy/signature.py --- a/pypy/module/micronumpy/signature.py +++ b/pypy/module/micronumpy/signature.py @@ -5,6 +5,11 @@ from pypy.module.micronumpy.strides import calculate_slice_strides from pypy.rlib.jit import hint, unroll_safe, promote +def new_printable_location(driver_name): + def get_printable_location(shapelen, sig): + return 'numpy ' + sig.debug_repr() + ' [%d dims,%s]' % (shapelen, driver_name) + return get_printable_location + def sigeq(one, two): return one.eq(two) diff --git a/pypy/module/micronumpy/strides.py b/pypy/module/micronumpy/strides.py --- a/pypy/module/micronumpy/strides.py +++ b/pypy/module/micronumpy/strides.py @@ -1,4 +1,9 @@ +from pypy.rlib import jit + +@jit.look_inside_iff(lambda shape, start, strides, backstrides, chunks: + jit.isconstant(len(chunks)) +) def calculate_slice_strides(shape, start, strides, backstrides, chunks): rstrides = [] rbackstrides = [] diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -906,6 +906,15 @@ b[0] = 3 assert debug_repr(b) == 'Array' + def test_remove_invalidates(self): + from numpypy import array + from numpypy.pypy import remove_invalidates + a = array([1, 2, 3]) + b = a + a + remove_invalidates(a) + a[0] = 14 + assert b[0] == 28 + def test_virtual_views(self): from numpypy import arange a = arange(15) diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -537,7 +537,7 @@ builder.append(by) builder.append_slice(input, upper, len(input)) else: - # An ok guess for the result size + # First compute the exact result size count = input.count(sub) if count > maxsplit and maxsplit > 0: count = maxsplit @@ -553,21 +553,16 @@ builder = StringBuilder(result_size) start = 0 sublen = len(sub) - first = True while maxsplit != 0: next = input.find(sub, start) if next < 0: break - if not first: - builder.append(by) - first = False builder.append_slice(input, start, next) + builder.append(by) start = next + sublen maxsplit -= 1 # NB. if it's already < 0, it stays < 0 - if not first: - builder.append(by) builder.append_slice(input, start, len(input)) return space.wrap(builder.build()) diff --git a/pypy/rlib/rsre/rsre_jit.py b/pypy/rlib/rsre/rsre_jit.py --- a/pypy/rlib/rsre/rsre_jit.py +++ b/pypy/rlib/rsre/rsre_jit.py @@ -22,7 +22,7 @@ info = '%s/%d' % (info, args[debugprint[2]]) else: info = '' - return '%s%s %s' % (name, info, s) + return 're %s%s %s' % (name, info, s) # self.get_printable_location = get_printable_location diff --git a/pypy/rpython/lltypesystem/rlist.py b/pypy/rpython/lltypesystem/rlist.py --- a/pypy/rpython/lltypesystem/rlist.py +++ b/pypy/rpython/lltypesystem/rlist.py @@ -375,7 +375,6 @@ newitems = malloc(LIST.items.TO, n) rgc.ll_arraycopy(olditems, newitems, 0, 0, n) return newitems -ll_list2fixed.oopspec = 'list.list2fixed(l)' def ll_list2fixed_exact(l): ll_assert(l.length == len(l.items), "ll_list2fixed_exact: bad length") diff --git a/pypy/rpython/test/test_generator.py b/pypy/rpython/test/test_generator.py --- a/pypy/rpython/test/test_generator.py +++ b/pypy/rpython/test/test_generator.py @@ -54,6 +54,26 @@ res = self.interpret(f, [0]) assert res == 42 + def test_except_block(self): + def foo(): + raise ValueError + def g(a, b, c): + yield a + yield b + try: + foo() + except ValueError: + pass + yield c + def f(): + gen = g(3, 5, 8) + x = gen.next() * 100 + x += gen.next() * 10 + x += gen.next() + return x + res = self.interpret(f, []) + assert res == 358 + class TestLLtype(BaseTestGenerator, LLRtypeMixin): pass diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py --- a/pypy/tool/jitlogparser/parser.py +++ b/pypy/tool/jitlogparser/parser.py @@ -3,6 +3,7 @@ from pypy.jit.metainterp.resoperation import opname from pypy.jit.tool.oparser import OpParser from pypy.tool.logparser import parse_log_file, extract_category +from copy import copy class Op(object): bridge = None @@ -23,19 +24,13 @@ self.failargs = failargs def getarg(self, i): - return self._getvar(self.args[i]) + return self.args[i] def getargs(self): - return [self._getvar(v) for v in self.args] + return self.args[:] def getres(self): - return self._getvar(self.res) - - def getdescr(self): - return self.descr - - def _getvar(self, v): - return v + return self.res def is_guard(self): return self._is_guard @@ -43,7 +38,7 @@ def repr(self): args = self.getargs() if self.descr is not None: - args.append('descr=%s' % self.getdescr()) + args.append('descr=%s' % self.descr) arglist = ', '.join(args) if self.res is not None: return '%s = %s(%s)' % (self.getres(), self.name, arglist) @@ -52,8 +47,6 @@ def __repr__(self): return self.repr() - ## return '<%s (%s)>' % (self.name, ', '.join([repr(a) - ## for a in self.args])) class SimpleParser(OpParser): @@ -145,18 +138,27 @@ is_bytecode = True inline_level = None - def __init__(self, operations, storage): - if operations[0].name == 'debug_merge_point': - self.inline_level = int(operations[0].args[0]) - m = re.search('<code object ([<>\w]+)\. file \'(.+?)\'\. line (\d+)> #(\d+) (\w+)', - operations[0].args[1]) - if m is None: - # a non-code loop, like StrLiteralSearch or something - self.bytecode_name = operations[0].args[1][1:-1] - else: - self.name, self.filename, lineno, bytecode_no, self.bytecode_name = m.groups() - self.startlineno = int(lineno) - self.bytecode_no = int(bytecode_no) + def parse_code_data(self, arg): + m = re.search('<code object ([<>\w]+)[\.,] file \'(.+?)\'[\.,] line (\d+)> #(\d+) (\w+)', + arg) + if m is None: + # a non-code loop, like StrLiteralSearch or something + self.bytecode_name = arg + else: + self.name, self.filename, lineno, bytecode_no, self.bytecode_name = m.groups() + self.startlineno = int(lineno) + self.bytecode_no = int(bytecode_no) + + + def __init__(self, operations, storage, loopname): + for op in operations: + if op.name == 'debug_merge_point': + self.inline_level = int(op.args[0]) + self.parse_code_data(op.args[1][1:-1]) + break + else: + self.inline_level = 0 + self.parse_code_data(loopname) self.operations = operations self.storage = storage self.code = storage.disassemble_code(self.filename, self.startlineno, @@ -164,7 +166,7 @@ def repr(self): if self.filename is None: - return "Unknown" + return self.bytecode_name return "%s, file '%s', line %d" % (self.name, self.filename, self.startlineno) @@ -219,7 +221,8 @@ self.storage = storage @classmethod - def from_operations(cls, operations, storage, limit=None, inputargs=''): + def from_operations(cls, operations, storage, limit=None, inputargs='', + loopname=''): """ Slice given operation list into a chain of TraceForOpcode chunks. Also detect inlined functions and make them Function """ @@ -245,13 +248,13 @@ for op in operations: if op.name == 'debug_merge_point': if so_far: - append_to_res(cls.TraceForOpcode(so_far, storage)) + append_to_res(cls.TraceForOpcode(so_far, storage, loopname)) if limit: break so_far = [] so_far.append(op) if so_far: - append_to_res(cls.TraceForOpcode(so_far, storage)) + append_to_res(cls.TraceForOpcode(so_far, storage, loopname)) # wrap stack back up if not stack: # no ops whatsoever @@ -299,7 +302,7 @@ def repr(self): if self.filename is None: - return "Unknown" + return self.chunks[0].bytecode_name return "%s, file '%s', line %d" % (self.name, self.filename, self.startlineno) @@ -384,9 +387,30 @@ parser.postprocess(loop, backend_tp=bname, backend_dump=dump, dump_start=start_ofs)) - loops.append(loop) + loops += split_trace(loop) return log, loops +def split_trace(trace): + labels = [0] + if trace.comment and 'Guard' in trace.comment: + descrs = ['bridge ' + re.search('Guard (\d+)', trace.comment).group(1)] + else: + descrs = ['entry ' + re.search('Loop (\d+)', trace.comment).group(1)] + for i, op in enumerate(trace.operations): + if op.name == 'label': + labels.append(i) + descrs.append(op.descr) + labels.append(len(trace.operations) - 1) + parts = [] + for i in range(len(labels) - 1): + start, stop = labels[i], labels[i+1] + part = copy(trace) + part.operations = trace.operations[start : stop + 1] + part.descr = descrs[i] + part.comment = trace.comment + parts.append(part) + + return parts def parse_log_counts(input, loops): if not input: @@ -394,11 +418,7 @@ lines = input[-1].splitlines() mapping = {} for loop in loops: - com = loop.comment - if 'Loop' in com: - mapping['loop ' + re.search('Loop (\d+)', com).group(1)] = loop - else: - mapping['bridge ' + re.search('Guard (\d+)', com).group(1)] = loop + mapping[loop.descr] = loop for line in lines: if line: num, count = line.split(':', 2) diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -1,6 +1,7 @@ from pypy.tool.jitlogparser.parser import (SimpleParser, TraceForOpcode, Function, adjust_bridges, - import_log, Op) + import_log, split_trace, Op, + parse_log_counts) from pypy.tool.jitlogparser.storage import LoopStorage import py, sys @@ -32,23 +33,26 @@ ''') res = Function.from_operations(ops.operations, LoopStorage()) assert len(res.chunks) == 1 - assert res.chunks[0].repr() + assert 'SomeRandomStuff' in res.chunks[0].repr() def test_split(): ops = parse(''' [i0] + label() debug_merge_point(0, "<code object stuff. file '/I/dont/exist.py'. line 200> #10 ADD") debug_merge_point(0, "<code object stuff. file '/I/dont/exist.py'. line 200> #11 SUB") i1 = int_add(i0, 1) debug_merge_point(0, "<code object stuff. file '/I/dont/exist.py'. line 200> #11 SUB") i2 = int_add(i1, 1) ''') - res = Function.from_operations(ops.operations, LoopStorage()) - assert len(res.chunks) == 3 + res = Function.from_operations(ops.operations, LoopStorage(), loopname='<loopname>') + assert len(res.chunks) == 4 assert len(res.chunks[0].operations) == 1 - assert len(res.chunks[1].operations) == 2 + assert len(res.chunks[1].operations) == 1 assert len(res.chunks[2].operations) == 2 - assert res.chunks[2].bytecode_no == 11 + assert len(res.chunks[3].operations) == 2 + assert res.chunks[3].bytecode_no == 11 + assert res.chunks[0].bytecode_name == '<loopname>' def test_inlined_call(): ops = parse(""" @@ -231,3 +235,51 @@ myrepr = 'c = foobar(a, b, descr=mydescr)' assert op.repr() == myrepr assert op.repr() == myrepr # do it twice + +def test_split_trace(): + loop = parse(''' + [i7] + i9 = int_lt(i7, 1003) + label(i9, descr=grrr) + guard_true(i9, descr=<Guard2>) [] + i13 = getfield_raw(151937600, descr=<SignedFieldDescr pypysig_long_struct.c_value 0>) + label(i13, descr=asb) + i19 = int_lt(i13, 1003) + guard_true(i19, descr=<Guard2>) [] + i113 = getfield_raw(151937600, descr=<SignedFieldDescr pypysig_long_struct.c_value 0>) + ''') + loop.comment = 'Loop 0' + parts = split_trace(loop) + assert len(parts) == 3 + assert len(parts[0].operations) == 2 + assert len(parts[1].operations) == 4 + assert len(parts[2].operations) == 4 + assert parts[1].descr == 'grrr' + assert parts[2].descr == 'asb' + +def test_parse_log_counts(): + loop = parse(''' + [i7] + i9 = int_lt(i7, 1003) + label(i9, descr=grrr) + guard_true(i9, descr=<Guard2>) [] + i13 = getfield_raw(151937600, descr=<SignedFieldDescr pypysig_long_struct.c_value 0>) + label(i13, descr=asb) + i19 = int_lt(i13, 1003) + guard_true(i19, descr=<Guard3>) [] + i113 = getfield_raw(151937600, descr=<SignedFieldDescr pypysig_long_struct.c_value 0>) + ''') + bridge = parse(''' + # bridge out of Guard 2 with 1 ops + [] + i0 = int_lt(1, 2) + finish(i0) + ''') + bridge.comment = 'bridge out of Guard 2 with 1 ops' + loop.comment = 'Loop 0' + loops = split_trace(loop) + split_trace(bridge) + input = ['grrr:123\nasb:12\nbridge 2:1234'] + parse_log_counts(input, loops) + assert loops[-1].count == 1234 + assert loops[1].count == 123 + assert loops[2].count == 12 diff --git a/pypy/translator/generator.py b/pypy/translator/generator.py --- a/pypy/translator/generator.py +++ b/pypy/translator/generator.py @@ -2,7 +2,7 @@ from pypy.objspace.flow.model import Variable, Constant, FunctionGraph from pypy.translator.unsimplify import insert_empty_startblock from pypy.translator.unsimplify import split_block -from pypy.translator.simplify import eliminate_empty_blocks +from pypy.translator.simplify import eliminate_empty_blocks, simplify_graph from pypy.tool.sourcetools import func_with_new_name from pypy.interpreter.argument import Signature @@ -64,6 +64,7 @@ def next(self): entry = self.current self.current = None + assert entry is not None # else, recursive generator invocation (next_entry, return_value) = func(entry) self.current = next_entry return return_value @@ -91,6 +92,10 @@ block.inputargs = [v_entry1] def tweak_generator_body_graph(Entry, graph): + # First, always run simplify_graph in order to reduce the number of + # variables passed around + simplify_graph(graph) + # assert graph.startblock.operations[0].opname == 'generator_mark' graph.startblock.operations.pop(0) # @@ -100,12 +105,20 @@ # mappings = [Entry] # + stopblock = Block([]) + v0 = Variable(); v1 = Variable() + stopblock.operations = [ + SpaceOperation('simple_call', [Constant(StopIteration)], v0), + SpaceOperation('type', [v0], v1), + ] + stopblock.closeblock(Link([v1, v0], graph.exceptblock)) + # for block in list(graph.iterblocks()): for exit in block.exits: if exit.target is graph.returnblock: - exit.args = [Constant(StopIteration), - Constant(StopIteration())] - exit.target = graph.exceptblock + exit.args = [] + exit.target = stopblock + assert block is not stopblock for index in range(len(block.operations)-1, -1, -1): op = block.operations[index] if op.opname == 'yield': diff --git a/pypy/translator/sandbox/pypy_interact.py b/pypy/translator/sandbox/pypy_interact.py --- a/pypy/translator/sandbox/pypy_interact.py +++ b/pypy/translator/sandbox/pypy_interact.py @@ -26,7 +26,8 @@ from pypy.translator.sandbox.sandlib import SimpleIOSandboxedProc from pypy.translator.sandbox.sandlib import VirtualizedSandboxedProc from pypy.translator.sandbox.vfs import Dir, RealDir, RealFile -from pypy.tool.lib_pypy import LIB_ROOT +import pypy +LIB_ROOT = os.path.dirname(os.path.dirname(pypy.__file__)) class PyPySandboxedProc(VirtualizedSandboxedProc, SimpleIOSandboxedProc): debug = True diff --git a/pypy/translator/sandbox/sandlib.py b/pypy/translator/sandbox/sandlib.py --- a/pypy/translator/sandbox/sandlib.py +++ b/pypy/translator/sandbox/sandlib.py @@ -30,8 +30,9 @@ # load(). Also, marshal.load(f) blocks with the GIL held when # f is a pipe with no data immediately avaialble, preventing the # _waiting_thread to run. -from pypy.tool.lib_pypy import import_from_lib_pypy -marshal = import_from_lib_pypy('marshal') +import pypy +marshal = py.path.local(pypy.__file__).join('..', '..', 'lib_pypy', + 'marshal.py').pyimport() # Non-marshal result types RESULTTYPE_STATRESULT = object() _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit