Author: Eric Seckler <eric.seck...@student.hpi.uni-potsdam.de> Branch: Changeset: r750:bead6833aef1 Date: 2014-01-14 14:28 +0100 http://bitbucket.org/pypy/lang-smalltalk/changeset/bead6833aef1/
Log: merge diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -1,8 +1,12 @@ syntax: glob *.py[co] *~ -pypy-c-jit-62116-b027d4428675-linux +pypy-c-jit-* images/Squeak* +images/resources* +*package-cache/ +Squeak* +*TAGS targetimageloadingsmalltalk-*c images/package-cache versions diff --git a/spyvm/constants.py b/spyvm/constants.py --- a/spyvm/constants.py +++ b/spyvm/constants.py @@ -146,6 +146,8 @@ TAGGED_MAXINT = 2 ** (LONG_BIT - 2) - 1 TAGGED_MININT = -2 ** (LONG_BIT - 2) +TAGGED_MASK = int(2 ** (LONG_BIT - 1) - 1) + # Entries into SO_SPECIAL_SELECTORS_ARRAY: #(#+ 1 #- 1 #< 1 #> 1 #<= 1 #>= 1 #= 1 #~= 1 #* 1 #/ 1 #\\ 1 #@ 1 #bitShift: 1 #// 1 #bitAnd: 1 #bitOr: 1 #at: 1 #at:put: 2 #size 0 #next 0 #nextPut: 1 #atEnd 0 #== 1 #class 0 #blockCopy: 1 #value 0 #value: 1 #do: 1 #new 0 #new: 1 #x 0 #y 0) diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py --- a/spyvm/interpreter.py +++ b/spyvm/interpreter.py @@ -126,7 +126,9 @@ class Interpreter(object): - + _immutable_fields_ = ["space", "image", "image_name", + "max_stack_depth", "interrupt_counter_size", + "startup_time"] _w_last_active_context = None cnt = 0 _last_indent = "" @@ -140,9 +142,11 @@ def __init__(self, space, image=None, image_name="", trace=False, max_stack_depth=constants.MAX_LOOP_DEPTH): + import time self.space = space self.image = image self.image_name = image_name + self.startup_time = time.time() self.max_stack_depth = max_stack_depth self.remaining_stack_depth = max_stack_depth self._loop = False @@ -325,13 +329,12 @@ def check_for_interrupts(self, s_frame): # parallel to Interpreter>>#checkForInterrupts - import time, math # Profiling is skipped # We don't adjust the check counter size # use the same time value as the primitive MILLISECOND_CLOCK - now = int(math.fmod(time.time()*1000, constants.TAGGED_MAXINT/2)) + now = self.time_now() # XXX the low space semaphore may be signaled here # Process inputs @@ -345,6 +348,11 @@ # We do not support external semaphores. # In cog, the method to add such a semaphore is only called in GC. + def time_now(self): + import time + from rpython.rlib.rarithmetic import intmask + return intmask(int((time.time() - self.startup_time) * 1000) & constants.TAGGED_MASK) + def padding(self, symbol=' '): return symbol * (self.max_stack_depth - self.remaining_stack_depth) diff --git a/spyvm/plugins/fileplugin.py b/spyvm/plugins/fileplugin.py --- a/spyvm/plugins/fileplugin.py +++ b/spyvm/plugins/fileplugin.py @@ -40,7 +40,10 @@ file_path = os.path.join(full_path, py_name) except OSError: raise PrimitiveFailedError - file_info = os.stat(file_path) + try: + file_info = os.stat(file_path) + except OSError: + raise PrimitiveFailedError w_name = space.wrap_string(py_name) w_creationTime = smalltalk_timestamp(space, file_info.st_ctime) diff --git a/spyvm/primitives.py b/spyvm/primitives.py --- a/spyvm/primitives.py +++ b/spyvm/primitives.py @@ -1019,8 +1019,7 @@ @expose_primitive(MILLISECOND_CLOCK, unwrap_spec=[object]) def func(interp, s_frame, w_arg): - import time, math - return interp.space.wrap_int(int(math.fmod(time.time()*1000, constants.TAGGED_MAXINT/2))) + return interp.space.wrap_int(interp.time_now()) @expose_primitive(SIGNAL_AT_MILLISECONDS, unwrap_spec=[object, object, int]) def func(interp, s_frame, w_delay, w_semaphore, timestamp): diff --git a/spyvm/test/jittest/__init__.py b/spyvm/test/jittest/__init__.py new file mode 100644 diff --git a/spyvm/test/jittest/base.py b/spyvm/test/jittest/base.py new file mode 100644 --- /dev/null +++ b/spyvm/test/jittest/base.py @@ -0,0 +1,121 @@ +import subprocess +import os + +# TODO: +from pypy.tool.jitlogparser.parser import SimpleParser, Op +from pypy.tool.jitlogparser.storage import LoopStorage + +from rpython.jit.metainterp.resoperation import opname +from rpython.jit.tool import oparser +from rpython.tool import logparser + + +BasePath = os.path.abspath( + os.path.join( + os.path.join(os.path.dirname(__file__), os.path.pardir), + os.path.pardir, + os.path.pardir + ) +) +BenchmarkImage = os.path.join(os.path.dirname(__file__), "benchmark.image") + +class BaseJITTest(object): + def run(self, spy, tmpdir, code): + proc = subprocess.Popen( + [str(spy), "-r", code.replace("\n", "\r\n"), BenchmarkImage], + cwd=str(tmpdir), + env={"PYPYLOG": "jit-log-opt:%s" % tmpdir.join("x.pypylog")} + ) + proc.wait() + data = logparser.parse_log_file(str(tmpdir.join("x.pypylog")), verbose=False) + data = logparser.extract_category(data, "jit-log-opt-") + + storage = LoopStorage() + traces = [SimpleParser.parse_from_input(t) for t in data] + main_loops = storage.reconnect_loops(traces) + traces_w = [] + for trace in traces: + if trace in main_loops: + traces_w.append(Trace(trace)) + else: + traces_w[len(traces_w) - 1].addbridge(trace) + return traces_w + + def assert_matches(self, trace, expected): + expected_lines = [ + line.strip() + for line in expected.splitlines() + if line and not line.isspace() + ] + parser = Parser(None, None, {}, "lltype", None, invent_fail_descr=None, nonstrict=True) + expected_ops = [parser.parse_next_op(l) for l in expected_lines] + aliases = {} + assert len(trace) == len(expected_ops) + for op, expected in zip(trace, expected_ops): + self._assert_ops_equal(aliases, op, expected) + + def _assert_ops_equal(self, aliases, op, expected): + assert op.name == expected.name + assert len(op.args) == len(expected.args) + for arg, expected_arg in zip(op.args, expected.args): + if arg in aliases: + arg = aliases[arg] + elif arg != expected_arg and expected_arg not in aliases.viewvalues(): + aliases[arg] = arg = expected_arg + assert arg == expected_arg + + +class Parser(oparser.OpParser): + def get_descr(self, poss_descr, allow_invent): + if poss_descr.startswith(("TargetToken", "<Guard")): + return poss_descr + return super(Parser, self).get_descr(poss_descr, allow_invent) + + def getvar(self, arg): + return arg + + def create_op(self, opnum, args, res, descr): + return Op(opname[opnum].lower(), args, res, descr) + + +class Trace(object): + def __init__(self, trace): + self._trace = trace + self._bridges = [] + self._bridgeops = None + self._loop = None + + def addbridge(self, trace): + self._bridges.append(trace) + + @property + def bridges(self): + if self._bridgeops: + return self._bridgeops + else: + self._bridgeops = [] + for bridge in self._bridges: + self._bridgeops.append([op for op in bridge.operations if not op.name.startswith("debug_")]) + return self._bridgeops + + @property + def loop(self): + if self._loop: + return self._loop + else: + self._loop = self._parse_loop_from(self._trace) + return self._loop + + def _parse_loop_from(self, trace, label_seen=None): + _loop = [] + for idx, op in enumerate(self._trace.operations): + if label_seen and not op.name.startswith("debug_"): + _loop.append(op) + if op.name == "label": + if label_seen is None: # first label + label_seen = False + else: + label_seen = True # second label + if len(_loop) == 0: + raise ValueError("Loop body couldn't be found") + return _loop diff --git a/spyvm/test/jittest/benchmark.image b/spyvm/test/jittest/benchmark.image new file mode 100644 index 0000000000000000000000000000000000000000..848cffbe175dbf07a5d4bdc4f958ce92779dd171 GIT binary patch [cut] diff --git a/spyvm/test/jittest/conftest.py b/spyvm/test/jittest/conftest.py new file mode 100644 --- /dev/null +++ b/spyvm/test/jittest/conftest.py @@ -0,0 +1,15 @@ +import py + + +def pytest_addoption(parser): + group = parser.getgroup("SPy JIT tests") + group.addoption( + "--spy", + dest="spy", + default=None, + help="Path to a compiled SPy binary" + ) + + +def pytest_funcarg__spy(request): + return str(py.path.local(request.config.getvalueorskip("spy"))) diff --git a/spyvm/test/jittest/test_basic.py b/spyvm/test/jittest/test_basic.py new file mode 100644 --- /dev/null +++ b/spyvm/test/jittest/test_basic.py @@ -0,0 +1,83 @@ +import py + +from .base import BaseJITTest + + +class TestBasic(BaseJITTest): + def test_while_loop(self, spy, tmpdir): + traces = self.run(spy, tmpdir, """ + 0 to: 1000000000 do: [:t|nil]. + """) + self.assert_matches(traces[0].loop, """ + guard_not_invalidated(descr=<Guard0xa15ec7c>) + i60 = int_le(i49, 10000) + guard_true(i60, descr=<Guard0xa15ec40>) + i61 = int_add(i49, 1) + i62 = int_sub(i61, -1073741824) + i63 = uint_lt(i62, -2147483648) + guard_true(i63, descr=<Guard0xa15ec04>) + i64 = int_sub(i57, 1) + setfield_gc(ConstPtr(ptr54), i64, descr=<FieldS spyvm.interpreter.Interpreter.inst_interrupt_check_counter 16>) + i65 = int_le(i64, 0) + guard_false(i65, descr=<Guard0xa15ebc8>) + jump(p0, p3, i61, p12, p14, p16, p18, p20, p22, p24, p26, p28, p30, p32, p34, p36, p38, i64, descr=TargetToken(169145008)) + """) + self.assert_matches(traces[0].bridges[0], """ + f18 = call(ConstClass(ll_time.ll_time_time), descr=<Callf 8 EF=4>) + setfield_gc(ConstPtr(ptr19), 10000, descr=<FieldS spyvm.interpreter.Interpreter.inst_interrupt_check_counter 24>) + guard_no_exception(descr=<Guard0x9732d30>) + f22 = float_sub(f18, 1387380038.806162) + f24 = float_mul(f22, 1000.000000) + i25 = cast_float_to_int(f24) + i27 = int_and(i25, 2147483647) + i28 = getfield_gc(ConstPtr(ptr19), descr=<FieldS spyvm.interpreter.Interpreter.inst_next_wakeup_tick 36>) + i29 = int_is_zero(i28) + guard_true(i29, descr=<Guard0x9761ad8>) + label(p0, p1, i16, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, descr=TargetToken(158475216)) + guard_class(p0, ConstClass(MethodContextShadow), descr=<Guard0x9761a9c>) + p31 = getfield_gc(p0, descr=<FieldP spyvm.shadow.MethodContextShadow.inst__w_method 44>) + guard_value(p31, ConstPtr(ptr32), descr=<Guard0x9761a60>) + guard_not_invalidated(descr=<Guard0x9761a24>) + i34 = int_le(i16, 1000000000) + guard_true(i34, descr=<Guard0x97619e8>) + i36 = int_add(i16, 1) + i38 = int_sub(i36, -1073741824) + i40 = uint_lt(i38, -2147483648) + guard_true(i40, descr=<Guard0x97619ac>) + setfield_gc(ConstPtr(ptr19), 9999, descr=<FieldS spyvm.interpreter.Interpreter.inst_interrupt_check_counter 24>) + jump(p0, p1, i36, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, 9999, descr=TargetToken(158474976)) + """) + + def test_constant_string(self, spy, tmpdir): + traces = self.run(spy, tmpdir, """ + | i | + i := 0. + [i <= 10000] whileTrue: [ i := i + 'a' size]. + ^ i + """) + self.assert_matches(traces[0].loop, """ + label(p0, p3, i58, p12, p14, p16, p18, p20, p22, p24, p26, p28, p30, p32, p34, p36, p38, i65, descr=TargetToken(153187472)) + debug_merge_point(0, 0, '2: [0x10]pushTemporaryVariableBytecode (codeTest1387373494)') + guard_not_invalidated(descr=<Guard0x92520c4>) + debug_merge_point(0, 0, '3: [0x21]pushLiteralConstantBytecode (codeTest1387373494)') + debug_merge_point(0, 0, '4: [0xb4]bytecodePrimLessOrEqual (codeTest1387373494)') + i68 = int_le(i58, 10000) + guard_true(i68, descr=<Guard0x9252088>) + debug_merge_point(0, 0, '5: [0x9e]shortConditionalJump (codeTest1387373494)') + debug_merge_point(0, 0, '6: [0x10]pushTemporaryVariableBytecode (codeTest1387373494)') + debug_merge_point(0, 0, '7: [0x20]pushLiteralConstantBytecode (codeTest1387373494)') + debug_merge_point(0, 0, '8: [0xc2]bytecodePrimSize (codeTest1387373494)') + debug_merge_point(0, 0, '9: [0xb0]bytecodePrimAdd (codeTest1387373494)') + i69 = int_add(i58, 1) + i70 = int_sub(i69, -1073741824) + i71 = uint_lt(i70, -2147483648) + guard_true(i71, descr=<Guard0x925204c>) + debug_merge_point(0, 0, '10: [0x68]storeAndPopTemporaryVariableBytecode (codeTest1387373494)') + debug_merge_point(0, 0, '11: [0xa3]longUnconditionalJump (codeTest1387373494)') + i72 = int_sub(i65, 1) + setfield_gc(ConstPtr(ptr55), i72, descr=<FieldS spyvm.interpreter.Interpreter.inst_interrupt_check_counter 16>) + i73 = int_le(i72, 0) + guard_false(i73, descr=<Guard0x9252010>) + debug_merge_point(0, 0, '2: [0x10]pushTemporaryVariableBytecode (codeTest1387373494)') + jump(p0, p3, i69, p12, p14, p16, p18, p20, p22, p24, p26, p28, p30, p32, p34, p36, p38, i72, descr=TargetToken(153187472)) + """) diff --git a/targetimageloadingsmalltalk.py b/targetimageloadingsmalltalk.py --- a/targetimageloadingsmalltalk.py +++ b/targetimageloadingsmalltalk.py @@ -59,6 +59,42 @@ except error.Exit, e: print e.msg +def _run_code(interp, code, as_benchmark=False): + import time + selector = "codeTest%d" % int(time.time()) + try: + w_result = interp.perform( + interp.space.w_SmallInteger, + "compile:classified:notifying:", + space.wrap_string("%s\r\n%s" % (selector, code)), + space.wrap_string("spy-run-code"), + space.w_nil + ) + except interpreter.ReturnFromTopLevel, e: + print e.object + return 1 + except error.Exit, e: + print e.msg + return 1 + + if not as_benchmark: + try: + w_result = interp.perform(space.wrap_int(0), selector) + except interpreter.ReturnFromTopLevel, e: + print e.object + return 1 + except error.Exit, e: + print e.msg + return 1 + if w_result: + if isinstance(w_result, model.W_BytesObject): + print w_result.as_string().replace('\r', '\n') + else: + print w_result.as_repr_string().replace('\r', '\n') + return 0 + else: + return _run_benchmark(interp, 0, selector, "") + space = objspace.ObjSpace() @@ -85,6 +121,8 @@ -m|--method [benchmark on smallint] -a|--arg [string argument to #method] --stm + -r|--run [code string] + -b|--benchmark [code string] [image path, default: Squeak.image] """ % argv[0] @@ -102,6 +140,8 @@ trace = False use_stm = False stringarg = "" + code = None + as_benchmark = False while idx < len(argv): arg = argv[idx] @@ -129,6 +169,16 @@ idx += 1 elif arg in ["--stm"]: use_stm = True + elif arg in ["-r", "--run"]: + _arg_missing(argv, idx, arg) + code = argv[idx + 1] + as_benchmark = False + idx += 1 + elif arg in ["-b", "--benchmark"]: + _arg_missing(argv, idx, arg) + code = argv[idx + 1] + as_benchmark = True + idx += 1 elif path is None: path = argv[idx] else: @@ -157,6 +207,8 @@ if benchmark is not None: print "Running Benchmark" return _run_benchmark(interp, number, benchmark, stringarg, use_stm) + elif code is not None: + return _run_code(interp, code, as_benchmark=as_benchmark) else: print "Running Image" _run_image(interp) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit