Author: Richard Plangger <[email protected]>
Branch:
Changeset: r85850:1a36f95ed5d8
Date: 2016-07-25 11:03 +0200
http://bitbucket.org/pypy/pypy/changeset/1a36f95ed5d8/
Log: merge new-jit-log
diff too long, truncating to 2000 out of 2221 lines
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -36,7 +36,7 @@
"cStringIO", "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array",
"binascii", "_multiprocessing", '_warnings', "_collections",
"_multibytecodec", "micronumpy", "_continuation", "_cffi_backend",
- "_csv", "cppyy", "_pypyjson",
+ "_csv", "cppyy", "_pypyjson", "_jitlog"
])
from rpython.jit.backend import detect_cpu
diff --git a/pypy/module/_jitlog/__init__.py b/pypy/module/_jitlog/__init__.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_jitlog/__init__.py
@@ -0,0 +1,13 @@
+from pypy.interpreter.mixedmodule import MixedModule
+from rpython.rlib.rvmprof import VMProfPlatformUnsupported
+
+class Module(MixedModule):
+ """ JitLog the new logging facility """
+ appleveldefs = {
+ }
+
+ interpleveldefs = {
+ 'enable': 'interp_jitlog.enable',
+ 'disable': 'interp_jitlog.disable',
+ 'JitlogError': 'space.fromcache(interp_jitlog.Cache).w_JitlogError',
+ }
diff --git a/pypy/module/_jitlog/interp_jitlog.py
b/pypy/module/_jitlog/interp_jitlog.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_jitlog/interp_jitlog.py
@@ -0,0 +1,28 @@
+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.rjitlog import rjitlog
+from rpython.rlib import jit
+
+class Cache:
+ def __init__(self, space):
+ self.w_JitlogError = space.new_exception_class("_jitlog.JitlogError")
+
+def JitlogError(space, e):
+ w_JitlogError = space.fromcache(Cache).w_JitlogError
+ return OperationError(w_JitlogError, space.wrap(e.msg))
+
+@unwrap_spec(fileno=int)
+def enable(space, fileno):
+ """ Enable PyPy's logging facility. """
+ try:
+ rjitlog.enable_jitlog(fileno)
+ except rjitlog.JitlogError, e:
+ raise JitlogError(space, e)
+
[email protected]_look_inside
+def disable(space):
+ """ Disable PyPy's logging facility. """
+ rjitlog.disable_jitlog()
diff --git a/pypy/module/_jitlog/test/__init__.py
b/pypy/module/_jitlog/test/__init__.py
new file mode 100644
diff --git a/pypy/module/_jitlog/test/test__jitlog.py
b/pypy/module/_jitlog/test/test__jitlog.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_jitlog/test/test__jitlog.py
@@ -0,0 +1,29 @@
+
+from rpython.tool.udir import udir
+from pypy.tool.pytest.objspace import gettestobjspace
+from rpython.rlib.rjitlog import rjitlog as jl
+
+class AppTestJitLog(object):
+ spaceconfig = {'usemodules': ['_jitlog', 'struct']}
+
+ def setup_class(cls):
+ cls.w_tmpfilename = cls.space.wrap(str(udir.join('test__jitlog.1')))
+ cls.w_mark_header = cls.space.wrap(jl.MARK_JITLOG_HEADER)
+ cls.w_version = cls.space.wrap(jl.JITLOG_VERSION_16BIT_LE)
+
+ def test_enable(self):
+ import _jitlog, struct
+ tmpfile = open(self.tmpfilename, 'wb')
+ fileno = tmpfile.fileno()
+ _jitlog.enable(fileno)
+ _jitlog.disable()
+ # no need to clsoe tmpfile, it is done by jitlog
+
+ with open(self.tmpfilename, 'rb') as fd:
+ assert fd.read(1) == self.mark_header
+ assert fd.read(2) == self.version
+ count, = struct.unpack('<h', fd.read(2))
+ for i in range(count):
+ opnum = struct.unpack('<h', fd.read(2))
+ strcount = struct.unpack('<i', fd.read(4))
+ fd.read(strcount)
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
@@ -3,7 +3,7 @@
from pypy.interpreter.pyframe import PyFrame
from pypy.interpreter.pycode import PyCode
from pypy.interpreter.baseobjspace import W_Root
-from rpython.rlib import rvmprof
+from rpython.rlib import rvmprof, jit
# ____________________________________________________________
diff --git a/pypy/module/pypyjit/interp_jit.py
b/pypy/module/pypyjit/interp_jit.py
--- a/pypy/module/pypyjit/interp_jit.py
+++ b/pypy/module/pypyjit/interp_jit.py
@@ -6,6 +6,7 @@
from rpython.rlib.rarithmetic import r_uint, intmask
from rpython.rlib.jit import JitDriver, hint, we_are_jitted, dont_look_inside
from rpython.rlib import jit, jit_hooks
+from rpython.rlib.rjitlog import rjitlog as jl
from rpython.rlib.jit import current_trace_length, unroll_parameters,\
JitHookInterface
from rpython.rtyper.annlowlevel import cast_instance_to_gcref
@@ -41,6 +42,19 @@
from rpython.rlib import rvmprof
return rvmprof.get_unique_id(bytecode)
[email protected](jl.MP_FILENAME, jl.MP_LINENO,
+ jl.MP_SCOPE, jl.MP_INDEX, jl.MP_OPCODE)
+def get_location(next_instr, is_being_profiled, bytecode):
+ from pypy.tool.stdlib_opcode import opcode_method_names
+ bcindex = ord(bytecode.co_code[next_instr])
+ opname = ""
+ if 0 <= bcindex < len(opcode_method_names):
+ opname = opcode_method_names[bcindex]
+ name = bytecode.co_name
+ if not name:
+ name = ""
+ return (bytecode.co_filename, bytecode.co_firstlineno,
+ name, intmask(next_instr), opname)
def should_unroll_one_iteration(next_instr, is_being_profiled, bytecode):
return (bytecode.co_flags & CO_GENERATOR) != 0
@@ -51,6 +65,7 @@
virtualizables = ['frame']
pypyjitdriver = PyPyJitDriver(get_printable_location = get_printable_location,
+ get_location = get_location,
get_unique_id = get_unique_id,
should_unroll_one_iteration =
should_unroll_one_iteration,
diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py
b/pypy/module/pypyjit/test_pypy_c/test_00_model.py
--- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py
@@ -57,7 +57,10 @@
cmdline.append(str(self.filepath))
#
env = os.environ.copy()
+ # TODO old logging system
env['PYPYLOG'] = self.log_string + ':' + str(logfile)
+ jitlogfile = str(logfile) + '.jlog'
+ env['JITLOG'] = str(jitlogfile)
pipe = subprocess.Popen(cmdline,
env=env,
stdout=subprocess.PIPE,
@@ -84,6 +87,7 @@
log = Log(rawtraces)
log.result = eval(stdout)
log.logfile = str(logfile)
+ log.jitlogfile = jitlogfile
#
summaries = logparser.extract_category(rawlog, 'jit-summary')
if len(summaries) > 0:
diff --git a/pypy/module/pypyjit/test_pypy_c/test_jitlogparser.py
b/pypy/module/pypyjit/test_pypy_c/test_jitlogparser.py
--- a/pypy/module/pypyjit/test_pypy_c/test_jitlogparser.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_jitlogparser.py
@@ -8,7 +8,6 @@
mangle_descr)
from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC
-
class TestLogParser(BaseTestPyPyC):
log_string = 'jit-log-opt,jit-backend'
diff --git a/rpython/jit/backend/arm/assembler.py
b/rpython/jit/backend/arm/assembler.py
--- a/rpython/jit/backend/arm/assembler.py
+++ b/rpython/jit/backend/arm/assembler.py
@@ -14,7 +14,7 @@
CoreRegisterManager, check_imm_arg, VFPRegisterManager,
operations as regalloc_operations)
from rpython.jit.backend.llsupport import jitframe, rewrite
-from rpython.jit.backend.llsupport.assembler import DEBUG_COUNTER,
BaseAssembler
+from rpython.jit.backend.llsupport.assembler import BaseAssembler
from rpython.jit.backend.llsupport.regalloc import get_scale,
valid_addressing_size
from rpython.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper
from rpython.jit.backend.model import CompiledLoopToken
@@ -633,9 +633,17 @@
'loop.asm')
ops_offset = self.mc.ops_offset
- if logger is not None:
- logger.log_loop(inputargs, operations, 0, "rewritten",
- name=loopname, ops_offset=ops_offset)
+
+ if logger:
+ log = logger.log_trace(jl.MARK_TRACE_ASM, None, self.mc)
+ log.write(inputargs, operations, ops_offset=ops_offset)
+
+ # legacy
+ if logger.logger_ops:
+ logger.logger_ops.log_loop(inputargs, operations, 0,
+ "rewritten", name=loopname,
+ ops_offset=ops_offset)
+
self.teardown()
debug_start("jit-backend-addr")
@@ -735,9 +743,18 @@
frame_depth_no_fixed_size + JITFRAME_FIXED_SIZE)
self.fixup_target_tokens(rawstart)
self.update_frame_depth(frame_depth)
+
if logger:
- logger.log_bridge(inputargs, operations, "rewritten", faildescr,
- ops_offset=ops_offset)
+ log = logger.log_trace(jl.MARK_TRACE_ASM, None, self.mc)
+ log.write(inputargs, operations, ops_offset)
+ # log that the already written bridge is stitched to a descr!
+ logger.log_patch_guard(descr_number, rawstart)
+
+ # legacy
+ if logger.logger_ops:
+ logger.logger_ops.log_bridge(inputargs, operations,
"rewritten",
+ faildescr, ops_offset=ops_offset)
+
self.teardown()
return AsmInfo(ops_offset, startpos + rawstart, codeendpos - startpos)
diff --git a/rpython/jit/backend/llsupport/asmmemmgr.py
b/rpython/jit/backend/llsupport/asmmemmgr.py
--- a/rpython/jit/backend/llsupport/asmmemmgr.py
+++ b/rpython/jit/backend/llsupport/asmmemmgr.py
@@ -223,6 +223,7 @@
self.init_block_builder()
else:
self._become_a_plain_block_builder()
+ self.rawstart = 0
def init_block_builder(self):
self._cursubblock = lltype.nullptr(self.SUBBLOCK)
@@ -245,6 +246,9 @@
self._cursubblock.data[index] = char
self._cursubindex = index + 1
+ def absolute_addr(self):
+ return self.rawstart
+
def overwrite(self, index, char):
assert 0 <= index < self.get_relative_pos()
block = self._cursubblock
@@ -280,6 +284,19 @@
targetindex -= self.SUBBLOCK_SIZE
assert not block
+ def copy_core_dump(self, addr, offset=0, count=-1):
+ HEX = '0123456789ABCDEF'
+ dump = []
+ src = rffi.cast(rffi.CCHARP, addr)
+ end = self.get_relative_pos()
+ if count != -1:
+ end = offset + count
+ for p in range(offset, end):
+ o = ord(src[p])
+ dump.append(HEX[o >> 4])
+ dump.append(HEX[o & 15])
+ return ''.join(dump)
+
def _dump(self, addr, logname, backend=None):
debug_start(logname)
if have_debug_prints():
@@ -293,17 +310,11 @@
else:
debug_print('SYS_EXECUTABLE', '??')
#
- HEX = '0123456789ABCDEF'
- dump = []
- src = rffi.cast(rffi.CCHARP, addr)
- for p in range(self.get_relative_pos()):
- o = ord(src[p])
- dump.append(HEX[o >> 4])
- dump.append(HEX[o & 15])
+ dump = self.copy_core_dump(addr)
debug_print('CODE_DUMP',
'@%x' % addr,
'+0 ', # backwards compatibility
- ''.join(dump))
+ dump)
#
debug_stop(logname)
@@ -315,6 +326,7 @@
allblocks.append(malloced)
rawstart = malloced[0]
rawstart = (rawstart + align - 1) & (-align)
+ self.rawstart = rawstart
self.copy_to_raw_memory(rawstart)
if self.gcroot_markers is not None:
assert gcrootmap is not None
diff --git a/rpython/jit/backend/llsupport/assembler.py
b/rpython/jit/backend/llsupport/assembler.py
--- a/rpython/jit/backend/llsupport/assembler.py
+++ b/rpython/jit/backend/llsupport/assembler.py
@@ -12,7 +12,7 @@
from rpython.rlib.objectmodel import specialize, compute_unique_id
from rpython.rtyper.annlowlevel import cast_instance_to_gcref, llhelper
from rpython.rtyper.lltypesystem import rffi, lltype
-
+from rpython.rlib.rjitlog import rjitlog as jl
DEBUG_COUNTER = lltype.Struct('DEBUG_COUNTER',
# 'b'ridge, 'l'abel or # 'e'ntry point
@@ -73,7 +73,9 @@
self.memcpy_addr = 0
self.memset_addr = 0
self.rtyper = cpu.rtyper
+ # do not rely on this attribute if you test for jitlog
self._debug = False
+ self.loop_run_counters = []
def stitch_bridge(self, faildescr, target):
raise NotImplementedError
@@ -129,11 +131,13 @@
self._build_stack_check_slowpath()
self._build_release_gil(gc_ll_descr.gcrootmap)
+ # do not rely on the attribute _debug for jitlog
if not self._debug:
# if self._debug is already set it means that someone called
# set_debug by hand before initializing the assembler. Leave it
# as it is
- self.set_debug(have_debug_prints_for('jit-backend-counts'))
+ should_debug = have_debug_prints_for('jit-backend-counts')
+ self.set_debug(should_debug)
# when finishing, we only have one value at [0], the rest dies
self.gcmap_for_finish = lltype.malloc(jitframe.GCMAP, 1,
flavor='raw',
@@ -337,16 +341,14 @@
# Here we join Path A and Path B again
self._call_assembler_patch_jmp(jmp_location)
+ def get_loop_run_counters(self, index):
+ return self.loop_run_counters[index]
+
@specialize.argtype(1)
def _inject_debugging_code(self, looptoken, operations, tp, number):
- if self._debug:
- s = 0
- for op in operations:
- s += op.getopnum()
-
+ if self._debug or jl.jitlog_enabled():
newoperations = []
- self._append_debugging_code(newoperations, tp, number,
- None)
+ self._append_debugging_code(newoperations, tp, number, None)
for op in operations:
newoperations.append(op)
if op.getopnum() == rop.LABEL:
@@ -362,10 +364,6 @@
ResOperation(rop.INCREMENT_DEBUG_COUNTER, [c_adr]))
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
-
# XXX the numbers here are ALMOST unique, but not quite, use a counter
# or something
struct = lltype.malloc(DEBUG_COUNTER, flavor='raw',
@@ -377,13 +375,18 @@
else:
assert token
struct.number = compute_unique_id(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
self.loop_run_counters.append(struct)
return struct
def finish_once(self):
if self._debug:
+ # TODO remove the old logging system when jitlog is complete
debug_start('jit-backend-counts')
- for i in range(len(self.loop_run_counters)):
+ length = len(self.loop_run_counters)
+ for i in range(length):
struct = self.loop_run_counters[i]
if struct.type == 'l':
prefix = 'TargetToken(%d)' % struct.number
@@ -400,6 +403,23 @@
debug_print(prefix + ':' + str(struct.i))
debug_stop('jit-backend-counts')
+ self.flush_trace_counters()
+
+ def flush_trace_counters(self):
+ # this is always called, the jitlog knows if it is enabled
+ length = len(self.loop_run_counters)
+ for i in range(length):
+ struct = self.loop_run_counters[i]
+ # only log if it has been executed
+ if struct.i > 0:
+ jl._log_jit_counter(struct)
+ # reset the counter, flush in a later point in time will
+ # add up the counters!
+ struct.i = 0
+ # here would be the point to free some counters
+ # see YYY comment above! but first we should run this every once in a
while
+ # not just when jitlog_disable is called
+
@staticmethod
@rgc.no_collect
def _reacquire_gil_asmgcc(css, old_rpy_fastgil):
diff --git a/rpython/jit/backend/llsupport/llmodel.py
b/rpython/jit/backend/llsupport/llmodel.py
--- a/rpython/jit/backend/llsupport/llmodel.py
+++ b/rpython/jit/backend/llsupport/llmodel.py
@@ -113,7 +113,7 @@
unique_id=0, log=True, name='', logger=None):
return self.assembler.assemble_loop(jd_id, unique_id, logger, name,
inputargs, operations,
- looptoken, log=log)
+ looptoken, log)
def stitch_bridge(self, faildescr, target):
self.assembler.stitch_bridge(faildescr, target)
diff --git a/rpython/jit/backend/llsupport/test/ztranslation_test.py
b/rpython/jit/backend/llsupport/test/ztranslation_test.py
--- a/rpython/jit/backend/llsupport/test/ztranslation_test.py
+++ b/rpython/jit/backend/llsupport/test/ztranslation_test.py
@@ -12,6 +12,7 @@
from rpython.config.config import ConfigError
from rpython.translator.tool.cbuild import ExternalCompilationInfo
from rpython.rtyper.lltypesystem import lltype, rffi
+from rpython.rlib.rjitlog import rjitlog as jl
class TranslationTest(CCompiledMixin):
@@ -48,9 +49,16 @@
lltype.Float, macro=True, releasegil=True,
compilation_info=eci)
+ @jl.returns(jl.MP_FILENAME,
+ jl.MP_LINENO,
+ jl.MP_INDEX)
+ def get_location():
+ return ("/home.py",0,0)
+
jitdriver = JitDriver(greens = [],
reds = ['total', 'frame', 'j'],
- virtualizables = ['frame'])
+ virtualizables = ['frame'],
+ get_location = get_location)
def f(i, j):
for param, _ in unroll_parameters:
defl = PARAMETERS[param]
@@ -233,6 +241,23 @@
assert res == 2
# one for loop and one for the prologue, no unrolling
+ def test_flush_trace_counts(self):
+ driver = JitDriver(greens = [], reds = ['i'])
+
+ def f():
+ i = 0
+ while i < 100000:
+ driver.jit_merge_point(i=i)
+ i += 1
+
+ def main():
+ jit_hooks.stats_set_debug(None, True)
+ f()
+ jl.stats_flush_trace_counts(None)
+ return 0
+
+ res = self.meta_interp(main, [])
+ assert res == 0
class TranslationRemoveTypePtrTest(CCompiledMixin):
CPUClass = getcpuclass()
diff --git a/rpython/jit/backend/ppc/ppc_assembler.py
b/rpython/jit/backend/ppc/ppc_assembler.py
--- a/rpython/jit/backend/ppc/ppc_assembler.py
+++ b/rpython/jit/backend/ppc/ppc_assembler.py
@@ -36,6 +36,7 @@
from rpython.rlib.jit import AsmInfo
from rpython.rlib.objectmodel import compute_unique_id
from rpython.rlib.rarithmetic import r_uint
+from rpython.rlib.rjitlog import rjitlog as jl
memcpy_fn = rffi.llexternal('memcpy', [llmemory.Address, llmemory.Address,
rffi.SIZE_T], lltype.Void,
@@ -794,9 +795,16 @@
looptoken._ppc_fullsize = full_size
looptoken._ppc_ops_offset = ops_offset
looptoken._ll_function_addr = rawstart
+
if logger:
- logger.log_loop(inputargs, operations, 0, "rewritten",
- name=loopname, ops_offset=ops_offset)
+ log = logger.log_trace(jl.MARK_TRACE_ASM, None, self.mc)
+ log.write(inputargs, operations, ops_offset=ops_offset)
+
+ # legacy
+ if logger.logger_ops:
+ logger.logger_ops.log_loop(inputargs, operations, 0,
+ "rewritten", name=loopname,
+ ops_offset=ops_offset)
self.fixup_target_tokens(rawstart)
self.teardown()
@@ -863,9 +871,18 @@
ops_offset = self.mc.ops_offset
frame_depth = max(self.current_clt.frame_info.jfi_frame_depth,
frame_depth_no_fixed_size + JITFRAME_FIXED_SIZE)
+
if logger:
- logger.log_bridge(inputargs, operations, "rewritten",
- ops_offset=ops_offset)
+ log = logger.log_trace(jl.MARK_TRACE_ASM, None, self.mc)
+ log.write(inputargs, operations, ops_offset)
+ # log that the already written bridge is stitched to a descr!
+ logger.log_patch_guard(descr_number, rawstart)
+
+ # legacy
+ if logger.logger_ops:
+ logger.logger_ops.log_bridge(inputargs, operations,
"rewritten",
+ faildescr, ops_offset=ops_offset)
+
self.fixup_target_tokens(rawstart)
self.update_frame_depth(frame_depth)
self.teardown()
diff --git a/rpython/jit/backend/test/jitlog_test.py
b/rpython/jit/backend/test/jitlog_test.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/test/jitlog_test.py
@@ -0,0 +1,80 @@
+import re
+import os
+from rpython.rlib import debug
+from rpython.jit.tool.oparser import pure_parse
+from rpython.jit.metainterp import logger
+from rpython.jit.metainterp.typesystem import llhelper
+from rpython.rlib.rjitlog import rjitlog as jl
+from StringIO import StringIO
+from rpython.jit.metainterp.optimizeopt.util import equaloplists
+from rpython.jit.metainterp.history import AbstractDescr, JitCellToken,
BasicFailDescr, BasicFinalDescr
+from rpython.jit.backend.model import AbstractCPU
+from rpython.rlib.jit import JitDriver
+from rpython.rlib.objectmodel import always_inline
+from rpython.jit.metainterp.test.support import LLJitMixin
+from rpython.rlib.rjitlog import rjitlog
+import tempfile
+
+class LoggerTest(LLJitMixin):
+
+ def test_explicit_enable(self, tmpdir):
+ file = tmpdir.join('jitlog')
+ fileno = os.open(file.strpath, os.O_WRONLY | os.O_CREAT)
+ enable_jitlog = lambda: rjitlog.enable_jitlog(fileno)
+ f = self.run_sample_loop(enable_jitlog)
+ self.meta_interp(f, [10, 0])
+
+ assert os.path.exists(file.strpath)
+ with file.open('rb') as f:
+ # check the file header
+ assert f.read(3) == jl.MARK_JITLOG_HEADER +
jl.JITLOG_VERSION_16BIT_LE
+ assert len(f.read()) > 0
+
+ def test_env(self, monkeypatch, tmpdir):
+ file = tmpdir.join('jitlog')
+ monkeypatch.setenv("JITLOG", file.strpath)
+ f = self.run_sample_loop(None)
+ self.meta_interp(f, [10,0])
+ assert os.path.exists(file.strpath)
+ with file.open('rb') as fd:
+ # check the file header
+ assert fd.read(3) == jl.MARK_JITLOG_HEADER +
jl.JITLOG_VERSION_16BIT_LE
+ assert len(fd.read()) > 0
+
+ def test_version(self, monkeypatch, tmpdir):
+ file = tmpdir.join('jitlog')
+ monkeypatch.setattr(jl, 'JITLOG_VERSION_16BIT_LE', '\xff\xfe')
+ monkeypatch.setenv("JITLOG", file.strpath)
+ f = self.run_sample_loop(None)
+ self.meta_interp(f, [10,0])
+ assert os.path.exists(file.strpath)
+ with file.open('rb') as fd:
+ # check the file header
+ assert fd.read(3) == jl.MARK_JITLOG_HEADER + '\xff\xfe'
+ assert len(fd.read()) > 0
+
+ def test_version(self, monkeypatch, tmpdir):
+ file = tmpdir.join('jitlog')
+ monkeypatch.setattr(jl, 'JITLOG_VERSION_16BIT_LE', '\xff\xfe')
+ monkeypatch.setenv("JITLOG", file.strpath)
+ f = self.run_sample_loop(None)
+ self.meta_interp(f, [10,0])
+ assert os.path.exists(file.strpath)
+ with file.open('rb') as fd:
+ # check the file header
+ assert fd.read(3) == jl.MARK_JITLOG_HEADER + '\xff\xfe'
+ assert len(fd.read()) > 0
+
+ def run_sample_loop(self, func, myjitdriver = None):
+ if not myjitdriver:
+ myjitdriver = JitDriver(greens = [], reds = 'auto')
+ def f(y, x):
+ res = 0
+ if func:
+ func()
+ while y > 0:
+ myjitdriver.jit_merge_point()
+ res += x
+ y -= 1
+ return res
+ return f
diff --git a/rpython/jit/backend/x86/assembler.py
b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -3,13 +3,13 @@
import py
from rpython.jit.backend.llsupport import symbolic, jitframe, rewrite
-from rpython.jit.backend.llsupport.assembler import (GuardToken, BaseAssembler,
- DEBUG_COUNTER)
+from rpython.jit.backend.llsupport.assembler import (GuardToken,
BaseAssembler, debug_bridge)
from rpython.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper
from rpython.jit.backend.llsupport.gcmap import allocate_gcmap
from rpython.jit.metainterp.history import (Const, VOID, ConstInt)
from rpython.jit.metainterp.history import AbstractFailDescr, INT, REF, FLOAT
from rpython.jit.metainterp.compile import ResumeGuardDescr
+from rpython.rlib.rjitlog import rjitlog as jl
from rpython.rtyper.lltypesystem import lltype, rffi, rstr, llmemory
from rpython.rtyper.lltypesystem.lloperation import llop
from rpython.rtyper.annlowlevel import cast_instance_to_gcref
@@ -490,8 +490,9 @@
clt.frame_info.clear() # for now
if log:
+ number = looptoken.number
operations = self._inject_debugging_code(looptoken, operations,
- 'e', looptoken.number)
+ 'e', number)
regalloc = RegAlloc(self, self.cpu.translate_support_code)
#
@@ -538,9 +539,16 @@
looptoken._x86_fullsize = full_size
looptoken._x86_ops_offset = ops_offset
looptoken._ll_function_addr = rawstart + functionpos
+
if logger:
- logger.log_loop(inputargs, operations, 0, "rewritten",
- name=loopname, ops_offset=ops_offset)
+ log = logger.log_trace(jl.MARK_TRACE_ASM, None, self.mc)
+ log.write(inputargs, operations, ops_offset=ops_offset)
+
+ # legacy
+ if logger.logger_ops:
+ logger.logger_ops.log_loop(inputargs, operations, 0,
+ "rewritten", name=loopname,
+ ops_offset=ops_offset)
self.fixup_target_tokens(rawstart)
self.teardown()
@@ -605,9 +613,18 @@
ops_offset = self.mc.ops_offset
frame_depth = max(self.current_clt.frame_info.jfi_frame_depth,
frame_depth_no_fixed_size + JITFRAME_FIXED_SIZE)
+
if logger:
- logger.log_bridge(inputargs, operations, "rewritten", faildescr,
- ops_offset=ops_offset)
+ log = logger.log_trace(jl.MARK_TRACE_ASM, None, self.mc)
+ log.write(inputargs, operations, ops_offset)
+ # log that the already written bridge is stitched to a descr!
+ logger.log_patch_guard(descr_number, rawstart)
+
+ # legacy
+ if logger.logger_ops:
+ logger.logger_ops.log_bridge(inputargs, operations,
"rewritten",
+ faildescr, ops_offset=ops_offset)
+
self.fixup_target_tokens(rawstart)
self.update_frame_depth(frame_depth)
self.teardown()
diff --git a/rpython/jit/backend/x86/runner.py
b/rpython/jit/backend/x86/runner.py
--- a/rpython/jit/backend/x86/runner.py
+++ b/rpython/jit/backend/x86/runner.py
@@ -114,9 +114,10 @@
looptoken.compiled_loop_token.invalidate_positions = []
def get_all_loop_runs(self):
+ asm = self.assembler
l = lltype.malloc(LOOP_RUN_CONTAINER,
- len(self.assembler.loop_run_counters))
- for i, ll_s in enumerate(self.assembler.loop_run_counters):
+ len(asm.loop_run_counters))
+ for i, ll_s in enumerate(asm.loop_run_counters):
l[i].type = ll_s.type
l[i].number = ll_s.number
l[i].counter = ll_s.i
diff --git a/rpython/jit/backend/x86/test/test_jitlog.py
b/rpython/jit/backend/x86/test/test_jitlog.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/x86/test/test_jitlog.py
@@ -0,0 +1,8 @@
+
+from rpython.jit.backend.x86.test.test_basic import Jit386Mixin
+from rpython.jit.backend.test.jitlog_test import LoggerTest
+
+class TestJitlog(Jit386Mixin, LoggerTest):
+ # for the individual tests see
+ # ====> ../../../test/jitlog_test.py
+ pass
diff --git a/rpython/jit/backend/x86/test/test_runner.py
b/rpython/jit/backend/x86/test/test_runner.py
--- a/rpython/jit/backend/x86/test/test_runner.py
+++ b/rpython/jit/backend/x86/test/test_runner.py
@@ -590,11 +590,11 @@
self.cpu.compile_loop(ops.inputargs, ops.operations, looptoken)
self.cpu.execute_token(looptoken, 0)
# check debugging info
- struct = self.cpu.assembler.loop_run_counters[0]
+ struct = self.cpu.assembler.get_loop_run_counters(0)
assert struct.i == 1
- struct = self.cpu.assembler.loop_run_counters[1]
+ struct = self.cpu.assembler.get_loop_run_counters(1)
assert struct.i == 1
- struct = self.cpu.assembler.loop_run_counters[2]
+ struct = self.cpu.assembler.get_loop_run_counters(2)
assert struct.i == 9
self.cpu.finish_once()
finally:
diff --git a/rpython/jit/backend/zarch/assembler.py
b/rpython/jit/backend/zarch/assembler.py
--- a/rpython/jit/backend/zarch/assembler.py
+++ b/rpython/jit/backend/zarch/assembler.py
@@ -32,6 +32,7 @@
from rpython.rtyper.lltypesystem import lltype, rffi, llmemory
from rpython.rtyper.annlowlevel import llhelper, cast_instance_to_gcref
from rpython.rlib.jit import AsmInfo
+from rpython.rlib.rjitlog import rjitlog as jl
class JitFrameTooDeep(Exception):
pass
@@ -669,9 +670,16 @@
looptoken._zarch_rawstart = rawstart
looptoken._zarch_fullsize = full_size
looptoken._zarch_ops_offset = ops_offset
+
if logger:
- logger.log_loop(inputargs, operations, 0, "rewritten",
- name=loopname, ops_offset=ops_offset)
+ log = logger.log_trace(jl.MARK_TRACE_ASM, None, self.mc)
+ log.write(inputargs, operations, ops_offset=ops_offset)
+
+ # legacy
+ if logger.logger_ops:
+ logger.logger_ops.log_loop(inputargs, operations, 0,
+ "rewritten", name=loopname,
+ ops_offset=ops_offset)
self.fixup_target_tokens(rawstart)
self.teardown()
@@ -736,9 +744,18 @@
ops_offset = self.mc.ops_offset
frame_depth = max(self.current_clt.frame_info.jfi_frame_depth,
frame_depth_no_fixed_size + JITFRAME_FIXED_SIZE)
+
if logger:
- logger.log_bridge(inputargs, operations, "rewritten",
- ops_offset=ops_offset)
+ log = logger.log_trace(jl.MARK_TRACE_ASM, None, self.mc)
+ log.write(inputargs, operations, ops_offset)
+ # log that the already written bridge is stitched to a descr!
+ logger.log_patch_guard(descr_number, rawstart)
+
+ # legacy
+ if logger.logger_ops:
+ logger.logger_ops.log_bridge(inputargs, operations,
"rewritten",
+ faildescr, ops_offset=ops_offset)
+
self.fixup_target_tokens(rawstart)
self.update_frame_depth(frame_depth)
self.teardown()
diff --git a/rpython/jit/backend/zarch/test/test_jitlog.py
b/rpython/jit/backend/zarch/test/test_jitlog.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/zarch/test/test_jitlog.py
@@ -0,0 +1,8 @@
+
+from rpython.jit.backend.zarch.test.support import JitZARCHMixin
+from rpython.jit.backend.test.jitlog_test import LoggerTest
+
+class TestJitlog(JitZARCHMixin, LoggerTest):
+ # for the individual tests see
+ # ====> ../../../test/jitlog_test.py
+ pass
diff --git a/rpython/jit/metainterp/compile.py
b/rpython/jit/metainterp/compile.py
--- a/rpython/jit/metainterp/compile.py
+++ b/rpython/jit/metainterp/compile.py
@@ -6,6 +6,7 @@
from rpython.rlib.rarithmetic import r_uint, intmask
from rpython.rlib import rstack
from rpython.rlib.jit import JitDebugInfo, Counters, dont_look_inside
+from rpython.rlib.rjitlog import rjitlog as jl
from rpython.conftest import option
from rpython.jit.metainterp.resoperation import ResOperation, rop,\
@@ -217,6 +218,7 @@
loop_info, ops = optimize_trace(metainterp_sd, jitdriver_sd,
data, metainterp.box_names_memo)
except InvalidLoop:
+ metainterp_sd.jitlog.trace_aborted()
trace.cut_at(cut_at)
return None
loop = create_empty_loop(metainterp)
@@ -250,7 +252,9 @@
history = metainterp.history
trace = history.trace
warmstate = jitdriver_sd.warmstate
-
+ #
+ metainterp_sd.jitlog.start_new_trace(metainterp_sd, None, False)
+ #
enable_opts = jitdriver_sd.warmstate.enable_opts
if try_disabling_unroll:
if 'unroll' not in enable_opts:
@@ -275,6 +279,7 @@
preamble_data,
metainterp.box_names_memo)
except InvalidLoop:
+ metainterp_sd.jitlog.trace_aborted()
history.cut(cut_at)
return None
@@ -291,6 +296,7 @@
loop_data,
metainterp.box_names_memo)
except InvalidLoop:
+ metainterp_sd.jitlog.trace_aborted()
history.cut(cut_at)
return None
@@ -340,7 +346,9 @@
metainterp_sd = metainterp.staticdata
jitdriver_sd = metainterp.jitdriver_sd
history = metainterp.history
-
+ #
+ metainterp_sd.jitlog.start_new_trace(metainterp_sd, resumekey, False)
+ #
loop_jitcell_token = metainterp.get_procedure_token(greenkey)
assert loop_jitcell_token
@@ -368,6 +376,7 @@
loop_data,
metainterp.box_names_memo)
except InvalidLoop:
+ metainterp_sd.jitlog.trace_aborted()
history.cut(cut)
return None
@@ -476,22 +485,28 @@
def do_compile_loop(jd_id, unique_id, metainterp_sd, inputargs, operations,
looptoken, log=True, name='', memo=None):
+ # legacy
metainterp_sd.logger_ops.log_loop(inputargs, operations, -2,
'compiling', None, name, memo)
+ _log = metainterp_sd.jitlog.log_trace(jl.MARK_TRACE_OPT, metainterp_sd,
None)
+ _log.write(inputargs, operations)
return metainterp_sd.cpu.compile_loop(inputargs,
operations, looptoken,
jd_id=jd_id, unique_id=unique_id,
log=log, name=name,
- logger=metainterp_sd.logger_ops)
+ logger=metainterp_sd.jitlog)
def do_compile_bridge(metainterp_sd, faildescr, inputargs, operations,
original_loop_token, log=True, memo=None):
+ # legacy
metainterp_sd.logger_ops.log_bridge(inputargs, operations, "compiling",
memo=memo)
+ _log = metainterp_sd.jitlog.log_trace(jl.MARK_TRACE_OPT, metainterp_sd,
None)
+ _log.write(inputargs, operations)
assert isinstance(faildescr, AbstractFailDescr)
return metainterp_sd.cpu.compile_bridge(faildescr, inputargs, operations,
original_loop_token, log=log,
- logger=metainterp_sd.logger_ops)
+ logger=metainterp_sd.jitlog)
def forget_optimization_info(lst, reset_values=False):
for item in lst:
@@ -511,9 +526,7 @@
patch_new_loop_to_load_virtualizable_fields(loop, jitdriver_sd, vable)
original_jitcell_token = loop.original_jitcell_token
- globaldata = metainterp_sd.globaldata
- original_jitcell_token.number = n = globaldata.loopnumbering
- globaldata.loopnumbering += 1
+ original_jitcell_token.number = n = metainterp_sd.jitlog.trace_id
if not we_are_translated():
show_procedures(metainterp_sd, loop)
@@ -531,6 +544,7 @@
operations = get_deep_immutable_oplist(loop.operations)
metainterp_sd.profiler.start_backend()
debug_start("jit-backend")
+ log = have_debug_prints() or jl.jitlog_enabled()
try:
loopname = jitdriver_sd.warmstate.get_location_str(greenkey)
unique_id = jitdriver_sd.warmstate.get_unique_id(greenkey)
@@ -538,7 +552,7 @@
loop.inputargs,
operations, original_jitcell_token,
name=loopname,
- log=have_debug_prints(),
+ log=log,
memo=memo)
finally:
debug_stop("jit-backend")
@@ -582,10 +596,11 @@
operations = get_deep_immutable_oplist(operations)
metainterp_sd.profiler.start_backend()
debug_start("jit-backend")
+ log = have_debug_prints() or jl.jitlog_enabled()
try:
asminfo = do_compile_bridge(metainterp_sd, faildescr, inputargs,
operations,
- original_loop_token, have_debug_prints(),
+ original_loop_token, log,
memo)
finally:
debug_stop("jit-backend")
@@ -1020,7 +1035,7 @@
def compile_trace(metainterp, resumekey, runtime_boxes):
"""Try to compile a new bridge leading from the beginning of the history
- to some existging place.
+ to some existing place.
"""
from rpython.jit.metainterp.optimizeopt import optimize_trace
@@ -1033,6 +1048,9 @@
metainterp_sd = metainterp.staticdata
jitdriver_sd = metainterp.jitdriver_sd
+ #
+ metainterp_sd.jitlog.start_new_trace(metainterp_sd, resumekey, False)
+ #
if isinstance(resumekey, ResumeAtPositionDescr):
inline_short_preamble = False
else:
@@ -1057,6 +1075,7 @@
info, newops = optimize_trace(metainterp_sd, jitdriver_sd,
data, metainterp.box_names_memo)
except InvalidLoop:
+ metainterp_sd.jitlog.trace_aborted()
#pdb.post_mortem(sys.exc_info()[2])
debug_print("compile_new_bridge: got an InvalidLoop")
# XXX I am fairly convinced that optimize_bridge cannot actually raise
diff --git a/rpython/jit/metainterp/optimizeopt/__init__.py
b/rpython/jit/metainterp/optimizeopt/__init__.py
--- a/rpython/jit/metainterp/optimizeopt/__init__.py
+++ b/rpython/jit/metainterp/optimizeopt/__init__.py
@@ -7,6 +7,7 @@
from rpython.jit.metainterp.optimizeopt.simplify import OptSimplify
from rpython.jit.metainterp.optimizeopt.pure import OptPure
from rpython.jit.metainterp.optimizeopt.earlyforce import OptEarlyForce
+from rpython.rlib.rjitlog import rjitlog as jl
from rpython.rlib.jit import PARAMETERS, ENABLE_ALL_OPTS
from rpython.rlib.unroll import unrolling_iterable
from rpython.rlib.debug import debug_start, debug_stop, debug_print
@@ -53,6 +54,9 @@
"""
debug_start("jit-optimize")
try:
+ # mark that a new trace has been started
+ log = metainterp_sd.jitlog.log_trace(jl.MARK_TRACE, metainterp_sd,
None)
+ log.write_trace(compile_data.trace)
if compile_data.log_noopt:
metainterp_sd.logger_noopt.log_loop_from_trace(compile_data.trace,
memo=memo)
if memo is None:
diff --git a/rpython/jit/metainterp/optimizeopt/dependency.py
b/rpython/jit/metainterp/optimizeopt/dependency.py
--- a/rpython/jit/metainterp/optimizeopt/dependency.py
+++ b/rpython/jit/metainterp/optimizeopt/dependency.py
@@ -22,6 +22,8 @@
, (rop.UNICODESETITEM, 0, -1)
]
+UNROLLED_MODIFY_COMPLEX_OBJ = unrolling_iterable(MODIFY_COMPLEX_OBJ)
+
LOAD_COMPLEX_OBJ = [ (rop.GETARRAYITEM_GC_I, 0, 1)
, (rop.GETARRAYITEM_GC_F, 0, 1)
, (rop.GETARRAYITEM_GC_R, 0, 1)
@@ -40,6 +42,8 @@
, (rop.GETFIELD_RAW_R, 0, -1)
]
+UNROLLED_LOAD_COMPLEX_OBJ = unrolling_iterable(LOAD_COMPLEX_OBJ)
+
class Path(object):
def __init__(self,path):
self.path = path
@@ -202,7 +206,7 @@
args = []
op = self.op
if self.modifies_complex_object():
- for opnum, i, j in unrolling_iterable(MODIFY_COMPLEX_OBJ):
+ for opnum, i, j in UNROLLED_MODIFY_COMPLEX_OBJ:
#unrolling_iterable(MODIFY_COMPLEX_OBJ):
if op.getopnum() == opnum:
op_args = op.getarglist()
if j == -1:
@@ -723,7 +727,7 @@
if node.loads_from_complex_object():
# If this complex object load operation loads an index that has
been
# modified, the last modification should be used to put a def-use
edge.
- for opnum, i, j in unrolling_iterable(LOAD_COMPLEX_OBJ):
+ for opnum, i, j in UNROLLED_LOAD_COMPLEX_OBJ:
if opnum == op.getopnum():
cobj = op.getarg(i)
if j != -1:
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_util.py
b/rpython/jit/metainterp/optimizeopt/test/test_util.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_util.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_util.py
@@ -21,6 +21,7 @@
from rpython.jit.metainterp.resoperation import (rop, ResOperation,
InputArgRef, AbstractValue, OpHelpers)
from rpython.jit.metainterp.optimizeopt.util import args_dict
+from rpython.rlib.rjitlog import rjitlog as jl
def test_sort_descrs():
@@ -484,6 +485,7 @@
self.options = Fake()
self.globaldata = Fake()
self.config = get_combined_translation_config(translating=True)
+ self.jitlog = jl.JitLogger()
class logger_noopt:
@classmethod
diff --git a/rpython/jit/metainterp/pyjitpl.py
b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -13,6 +13,7 @@
from rpython.jit.metainterp.logger import Logger
from rpython.jit.metainterp.optimizeopt.util import args_dict
from rpython.jit.metainterp.resoperation import rop, OpHelpers, GuardResOp
+from rpython.rlib.rjitlog import rjitlog as jl
from rpython.rlib import nonconst, rstack
from rpython.rlib.debug import debug_start, debug_stop, debug_print
from rpython.rlib.debug import have_debug_prints, make_sure_not_resized
@@ -1760,8 +1761,12 @@
self.cpu = cpu
self.stats = self.cpu.stats
self.options = options
+ self.jitlog = jl.JitLogger(self.cpu)
self.logger_noopt = Logger(self)
self.logger_ops = Logger(self, guard_number=True)
+ # legacy loggers
+ self.jitlog.logger_noopt = self.logger_noopt
+ self.jitlog.logger_ops = self.logger_ops
self.profiler = ProfilerClass()
self.profiler.cpu = cpu
@@ -1849,6 +1854,7 @@
def _setup_once(self):
"""Runtime setup needed by the various components of the JIT."""
if not self.globaldata.initialized:
+ self.jitlog.setup_once()
debug_print(self.jit_starting_line)
self.cpu.setup_once()
if not self.profiler.initialized:
@@ -1925,7 +1931,6 @@
self.initialized = False
self.indirectcall_dict = None
self.addr2name = None
- self.loopnumbering = 0
# ____________________________________________________________
diff --git a/rpython/jit/metainterp/test/test_compile.py
b/rpython/jit/metainterp/test/test_compile.py
--- a/rpython/jit/metainterp/test/test_compile.py
+++ b/rpython/jit/metainterp/test/test_compile.py
@@ -4,6 +4,7 @@
from rpython.jit.metainterp.compile import compile_loop
from rpython.jit.metainterp.compile import compile_tmp_callback
from rpython.jit.metainterp import jitexc
+from rpython.rlib.rjitlog import rjitlog as jl
from rpython.jit.metainterp import jitprof, typesystem, compile
from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin
from rpython.jit.tool.oparser import parse, convert_loop_to_trace
@@ -51,13 +52,14 @@
return 'location'
class FakeGlobalData(object):
- loopnumbering = 0
+ pass
class FakeMetaInterpStaticData(object):
all_descrs = []
logger_noopt = FakeLogger()
logger_ops = FakeLogger()
config = get_combined_translation_config(translating=True)
+ jitlog = jl.JitLogger()
stats = Stats(None)
profiler = jitprof.EmptyProfiler()
@@ -78,8 +80,8 @@
cpu = FakeCPU()
staticdata = FakeMetaInterpStaticData()
staticdata.cpu = cpu
- staticdata.globaldata = FakeGlobalData()
- staticdata.globaldata.loopnumbering = 1
+ staticdata.jitlog = jl.JitLogger(cpu)
+ staticdata.jitlog.trace_id = 1
#
loop = parse('''
[p1]
@@ -106,8 +108,7 @@
jitcell_token = target_token.targeting_jitcell_token
assert jitcell_token == target_token.original_jitcell_token
assert jitcell_token.target_tokens == [target_token]
- assert jitcell_token.number == 1
- assert staticdata.globaldata.loopnumbering == 2
+ assert jitcell_token.number == 2
#
assert len(cpu.seen) == 1
assert cpu.seen[0][2] == jitcell_token
diff --git a/rpython/jit/metainterp/warmspot.py
b/rpython/jit/metainterp/warmspot.py
--- a/rpython/jit/metainterp/warmspot.py
+++ b/rpython/jit/metainterp/warmspot.py
@@ -6,6 +6,7 @@
cast_base_ptr_to_instance, hlstr, cast_instance_to_gcref)
from rpython.rtyper.llannotation import lltype_to_annotation
from rpython.annotator import model as annmodel
+from rpython.annotator.dictdef import DictDef
from rpython.rtyper.llinterp import LLException
from rpython.rtyper.test.test_llinterp import get_interpreter, clear_tcache
from rpython.flowspace.model import SpaceOperation, Variable, Constant
@@ -119,6 +120,7 @@
return interp, graph
res = interp.eval_graph(graph, args)
if not kwds.get('translate_support_code', False):
+ warmrunnerdesc.metainterp_sd.jitlog.finish()
warmrunnerdesc.metainterp_sd.profiler.finish()
warmrunnerdesc.metainterp_sd.cpu.finish_once()
print '~~~ return value:', repr(res)
@@ -563,12 +565,12 @@
jd._EnterJitAssembler = EnterJitAssembler
def make_driverhook_graphs(self):
- s_Str = annmodel.SomeString()
#
annhelper = MixLevelHelperAnnotator(self.translator.rtyper)
for jd in self.jitdrivers_sd:
jd._get_printable_location_ptr = self._make_hook_graph(jd,
- annhelper, jd.jitdriver.get_printable_location, s_Str)
+ annhelper, jd.jitdriver.get_printable_location,
+ annmodel.SomeString())
jd._get_unique_id_ptr = self._make_hook_graph(jd,
annhelper, jd.jitdriver.get_unique_id, annmodel.SomeInteger())
jd._confirm_enter_jit_ptr = self._make_hook_graph(jd,
@@ -579,6 +581,34 @@
jd._should_unroll_one_iteration_ptr = self._make_hook_graph(jd,
annhelper, jd.jitdriver.should_unroll_one_iteration,
annmodel.s_Bool)
+ #
+ items = []
+ types = ()
+ pos = ()
+ if jd.jitdriver.get_location:
+ assert hasattr(jd.jitdriver.get_location, '_loc_types'), """
+ You must decorate your get_location function:
+
+ from rpython.rlib.rjitlog import rjitlog as jl
+ @jl.returns(jl.MP_FILENAME, jl.MP_XXX, ...)
+ def get_loc(your, green, keys):
+ name = "x.txt" # extract it from your green keys
+ return (name, ...)
+ """
+ types = jd.jitdriver.get_location._loc_types
+ del jd.jitdriver.get_location._loc_types
+ #
+ for _,type in types:
+ if type == 's':
+ items.append(annmodel.SomeString())
+ elif type == 'i':
+ items.append(annmodel.SomeInteger())
+ else:
+ raise NotImplementedError
+ s_Tuple = annmodel.SomeTuple(items)
+ jd._get_location_ptr = self._make_hook_graph(jd,
+ annhelper, jd.jitdriver.get_location, s_Tuple)
+ jd._get_loc_types = types
annhelper.finish()
def _make_hook_graph(self, jitdriver_sd, annhelper, func,
diff --git a/rpython/jit/metainterp/warmstate.py
b/rpython/jit/metainterp/warmstate.py
--- a/rpython/jit/metainterp/warmstate.py
+++ b/rpython/jit/metainterp/warmstate.py
@@ -6,6 +6,7 @@
from rpython.rlib.debug import debug_start, debug_stop, debug_print
from rpython.rlib.debug import have_debug_prints_for
from rpython.rlib.jit import PARAMETERS
+from rpython.rlib.rjitlog import rjitlog as jl
from rpython.rlib.nonconst import NonConstant
from rpython.rlib.objectmodel import specialize, we_are_translated, r_dict
from rpython.rlib.rarithmetic import intmask, r_uint
@@ -703,8 +704,35 @@
drivername = jitdriver.name
else:
drivername = '<unknown jitdriver>'
- get_location_ptr = self.jitdriver_sd._get_printable_location_ptr
- if get_location_ptr is None:
+ # get_location returns
+ get_location_ptr = getattr(self.jitdriver_sd, '_get_location_ptr',
None)
+ if get_location_ptr is not None:
+ types = self.jitdriver_sd._get_loc_types
+ unwrap_greenkey = self.make_unwrap_greenkey()
+ unrolled_types = unrolling_iterable(enumerate(types))
+ def get_location(greenkey):
+ greenargs = unwrap_greenkey(greenkey)
+ fn = support.maybe_on_top_of_llinterp(rtyper, get_location_ptr)
+ value_tuple = fn(*greenargs)
+ values = []
+ for i, (sem_type,gen_type) in unrolled_types:
+ if gen_type == "s":
+ value = getattr(value_tuple, 'item' + str(i))
+ values.append(jl.wrap(sem_type,gen_type,hlstr(value)))
+ elif gen_type == "i":
+ value = getattr(value_tuple, 'item' + str(i))
+
values.append(jl.wrap(sem_type,gen_type,intmask(value)))
+ else:
+ raise NotImplementedError
+ return values
+ self.get_location_types = list(types)
+ self.get_location = get_location
+ else:
+ self.get_location_types = None
+ self.get_location = None
+ #
+ printable_loc_ptr = self.jitdriver_sd._get_printable_location_ptr
+ if printable_loc_ptr is None:
missing = '(%s: no get_printable_location)' % drivername
def get_location_str(greenkey):
return missing
@@ -720,7 +748,7 @@
if not have_debug_prints_for("jit-"):
return missing
greenargs = unwrap_greenkey(greenkey)
- fn = support.maybe_on_top_of_llinterp(rtyper, get_location_ptr)
+ fn = support.maybe_on_top_of_llinterp(rtyper,
printable_loc_ptr)
llres = fn(*greenargs)
if not we_are_translated() and isinstance(llres, str):
return llres
diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py
--- a/rpython/rlib/jit.py
+++ b/rpython/rlib/jit.py
@@ -604,8 +604,27 @@
get_printable_location=None, confirm_enter_jit=None,
can_never_inline=None, should_unroll_one_iteration=None,
name='jitdriver', check_untranslated=True, vectorize=False,
- get_unique_id=None, is_recursive=False):
- "NOT_RPYTHON"
+ get_unique_id=None, is_recursive=False, get_location=None):
+ """ NOT_RPYTHON
+ get_location:
+ The return value is designed to provide enough information to
express the
+ state of an interpreter when invoking jit_merge_point.
+ For a bytecode interperter such as PyPy this includes, filename,
line number,
+ function name, and more information. However, it should also be
able to express
+ the same state for an interpreter that evaluates an AST.
+ return paremter:
+ 0 -> filename. An absolute path specifying the file the
interpreter invoked.
+ If the input source is no file it should start
with the
+ prefix: "string://<name>"
+ 1 -> line number. The line number in filename. This should at
least point to
+ the enclosing name. It can however point to
the specific
+ source line of the instruction executed by
the interpreter.
+ 2 -> enclosing name. E.g. the function name.
+ 3 -> index. 64 bit number indicating the execution progress.
It can either be
+ an offset to byte code, or an index to the node in an AST
+ 4 -> operation name. a name further describing the current
program counter.
+ this can be either a byte code name or the name of an AST
node
+ """
if greens is not None:
self.greens = greens
self.name = name
@@ -639,6 +658,7 @@
assert get_jitcell_at is None, "get_jitcell_at no longer used"
assert set_jitcell_at is None, "set_jitcell_at no longer used"
self.get_printable_location = get_printable_location
+ self.get_location = get_location
if get_unique_id is None:
get_unique_id = lambda *args: 0
self.get_unique_id = get_unique_id
@@ -879,6 +899,7 @@
driver = self.instance.im_self
h = self.annotate_hook
h(driver.get_printable_location, driver.greens, **kwds_s)
+ h(driver.get_location, driver.greens, **kwds_s)
def annotate_hook(self, func, variables, args_s=[], **kwds_s):
if func is None:
diff --git a/rpython/rlib/rjitlog/__init__.py b/rpython/rlib/rjitlog/__init__.py
new file mode 100644
diff --git a/rpython/rlib/rjitlog/rjitlog.py b/rpython/rlib/rjitlog/rjitlog.py
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/rjitlog/rjitlog.py
@@ -0,0 +1,606 @@
+import py
+import sys
+import sys
+import weakref
+import struct
+import os
+from rpython.rlib import jit
+from rpython.tool.udir import udir
+from rpython.tool.version import rpythonroot
+from rpython.rtyper.lltypesystem import lltype, rffi
+from rpython.translator.tool.cbuild import ExternalCompilationInfo
+from rpython.jit.metainterp import resoperation as resoperations
+from rpython.jit.metainterp.resoperation import rop
+from rpython.jit.metainterp.history import ConstInt, ConstFloat
+from rpython.rlib.objectmodel import we_are_translated
+from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
+from rpython.rlib.objectmodel import compute_unique_id, always_inline
+from rpython.rlib.objectmodel import we_are_translated, specialize
+from rpython.rlib.unroll import unrolling_iterable
+from rpython.rlib.jit_hooks import register_helper
+from rpython.annotator import model as annmodel
+
+
+ROOT = py.path.local(rpythonroot).join('rpython', 'rlib', 'rjitlog')
+SRC = ROOT.join('src')
+
+_libs = []
+if sys.platform.startswith('linux'):
+ _libs = ['dl']
+eci_kwds = dict(
+ include_dirs = [SRC],
+ includes = ['rjitlog.h'],
+ libraries = _libs,
+ separate_module_files = [SRC.join('rjitlog.c')],
+ post_include_bits=['#define RPYTHON_JITLOG\n'],
+ )
+eci = ExternalCompilationInfo(**eci_kwds)
+
+# jit log functions
+jitlog_init = rffi.llexternal("jitlog_init", [rffi.INT],
+ rffi.CCHARP, compilation_info=eci)
+jitlog_try_init_using_env = rffi.llexternal("jitlog_try_init_using_env",
+ [], lltype.Void, compilation_info=eci)
+jitlog_write_marked = rffi.llexternal("jitlog_write_marked",
+ [rffi.CCHARP, rffi.INT],
+ lltype.Void, compilation_info=eci,
+ releasegil=False)
+jitlog_enabled = rffi.llexternal("jitlog_enabled", [], rffi.INT,
+ compilation_info=eci,
+ releasegil=False)
+jitlog_teardown = rffi.llexternal("jitlog_teardown", [], lltype.Void,
+ compilation_info=eci)
+
+class JitlogError(Exception):
+ def __init__(self, msg):
+ self.msg = msg
+ def __str__(self):
+ return self.msg
+
+@register_helper(None)
+def stats_flush_trace_counts(warmrunnerdesc):
+ if not we_are_translated():
+ return # first param is None untranslated
+ warmrunnerdesc.metainterp_sd.cpu.assembler.flush_trace_counters()
+
[email protected]_look_inside
+def enable_jitlog(fileno):
+ # initialize the jit log
+ p_error = jitlog_init(fileno)
+ if p_error:
+ raise JitlogError(rffi.charp2str(p_error))
+ blob = assemble_header()
+ jitlog_write_marked(MARK_JITLOG_HEADER + blob, len(blob) + 1)
+
+def disable_jitlog():
+ stats_flush_trace_counts(None)
+ jitlog_teardown()
+
+
+def commonprefix(a,b):
+ "Given a list of pathnames, returns the longest common leading component"
+ assert a is not None
+ assert b is not None
+ la = len(a)
+ lb = len(b)
+ c = min(la,lb)
+ if c == 0:
+ return ""
+ for i in range(c):
+ if a[i] != b[i]:
+ return a[:i] # partly matching
+ return a # full match
+
+@always_inline
+def encode_str(string):
+ return encode_le_32bit(len(string)) + string
+
+@always_inline
+def encode_le_16bit(val):
+ return chr((val >> 0) & 0xff) + chr((val >> 8) & 0xff)
+
+@always_inline
+def encode_le_32bit(val):
+ return ''.join([chr((val >> 0) & 0xff),
+ chr((val >> 8) & 0xff),
+ chr((val >> 16) & 0xff),
+ chr((val >> 24) & 0xff)])
+
+@always_inline
+def encode_le_64bit(val):
+ return ''.join([chr((val >> 0) & 0xff),
+ chr((val >> 8) & 0xff),
+ chr((val >> 16) & 0xff),
+ chr((val >> 24) & 0xff),
+ chr((val >> 32) & 0xff),
+ chr((val >> 40) & 0xff),
+ chr((val >> 48) & 0xff),
+ chr((val >> 56)& 0xff)])
+
+@always_inline
+def encode_le_addr(val):
+ if IS_32_BIT:
+ return encode_le_32bit(val)
+ else:
+ return encode_le_64bit(val)
+
+def encode_type(type, value):
+ if type == "s":
+ return encode_str(value)
+ elif type == "q":
+ return encode_le_64bit(value)
+ elif type == "i":
+ return encode_le_32bit(value)
+ elif type == "h":
+ return encode_le_32bit(value)
+ else:
+ raise NotImplementedError
+
+# more variable parameters
+MP_STR = (0x0, "s")
+MP_INT = (0x0, "i")
+
+# concrete parameters
+MP_FILENAME = (0x1, "s")
+MP_LINENO = (0x2, "i")
+MP_INDEX = (0x4, "i")
+MP_SCOPE = (0x8, "s")
+MP_OPCODE = (0x10, "s")
+
+class WrappedValue(object):
+ def encode(self, log, i, compressor):
+ raise NotImplementedError
+
+class StringValue(WrappedValue):
+ def __init__(self, sem_type, gen_type, value):
+ self.value = value
+
+ def encode(self, log, i, compressor):
+ str_value = self.value
+ last_prefix = compressor.get_last_written(i)
+ cp = compressor.compress(i, str_value)
+ if cp is None:
+ return b'\xff' + encode_str(str_value)
+
+ else:
+ cp_len = len(cp)
+ if cp == last_prefix:
+ # we have the same prefix
+ pass
+ else:
+ compressor.write(log, i, cp)
+ if len(str_value) == len(cp):
+ return b'\xef'
+ return b'\x00' + encode_str(str_value[len(cp):])
+
+class IntValue(WrappedValue):
+ def __init__(self, sem_type, gen_type, value):
+ self.value = value
+
+ def encode(self, log, i, prefixes):
+ return b'\x00' + encode_le_64bit(self.value)
+
+# note that a ...
+# "semantic_type" is an integer denoting which meaning does a type at a merge
point have
+# there are very common ones that are predefined. E.g.
MP_FILENAME
+# "generic_type" is one of the primitive types supported (string,int)
+
[email protected](2)
+def wrap(sem_type, gen_type, value):
+ if isinstance(value, int):
+ return IntValue(sem_type, gen_type, value)
+ elif isinstance(value, str):
+ return StringValue(sem_type, gen_type, value)
+ raise NotImplementedError
+
+def returns(*args):
+ """ Decorate your get_location function to specify the types.
+ Use MP_* constant as parameters. An example impl for get_location
+ would return the following:
+
+ @returns(MP_FILENAME, MP_LINENO)
+ def get_location(...):
+ return ("a.py", 0)
+ """
+ def decor(method):
+ method._loc_types = args
+ return method
+ return decor
+
+JITLOG_VERSION = 1
+JITLOG_VERSION_16BIT_LE = struct.pack("<H", JITLOG_VERSION)
+
+marks = [
+ ('INPUT_ARGS',),
+ ('RESOP_META',),
+ ('RESOP',),
+ ('RESOP_DESCR',),
+ ('ASM_ADDR',),
+ ('ASM',),
+
+ # which type of trace is logged after this
+ # the trace as it is recorded by the tracer
+ ('TRACE',),
+ # the trace that has passed the optimizer
+ ('TRACE_OPT',),
+ # the trace assembled to machine code (after rewritten)
+ ('TRACE_ASM',),
+
+ # the machine code was patched (e.g. guard)
+ ('STITCH_BRIDGE',),
+
+ ('START_TRACE',),
+
+ ('JITLOG_COUNTER',),
+ ('INIT_MERGE_POINT',),
+
+ ('JITLOG_HEADER',),
+ ('MERGE_POINT',),
+ ('COMMON_PREFIX',),
+ ('ABORT_TRACE',),
+ ('SOURCE_CODE',),
+]
+
+start = 0x11
+for mark, in marks:
+ globals()['MARK_' + mark] = chr(start)
+ start += 1
+
+if __name__ == "__main__":
+ print("# generated constants from rpython/rlib/jitlog.py")
+ print 'MARK_JITLOG_START = struct.pack("b", "%s")' % hex(0x10)
+ for mark, in marks:
+ nmr = globals()['MARK_' + mark]
+ h = hex(ord(nmr))
+ print '%s = struct.pack("b", "%s")' % ('MARK_' + mark, h)
+ print 'MARK_JITLOG_END = struct.pack("b", "%s")' % hex(start)
+ for key,value in locals().items():
+ if key.startswith("MP_"):
+ print '%s = (%s,"%s")' % (key, hex(value[0]), value[1])
+ print 'SEM_TYPE_NAMES = {'
+ for key,value in locals().items():
+ if key.startswith("MP_") and value[0] != 0:
+ print ' %s: "%s",' % (hex(value[0]), key[3:].lower())
+ print '}'
+
+MP_STR = (0x0, "s")
+MP_INT = (0x0, "i")
+
+# concrete parameters
+MP_FILENAME = (0x1, "s")
+MP_LINENO = (0x2, "i")
+MP_INDEX = (0x4, "i")
+MP_SCOPE = (0x8, "s")
+MP_OPCODE = (0x10, "s")
+
+del marks
+del start
+
+IS_32_BIT = sys.maxint == 2**31-1
+
+def assemble_header():
+ version = JITLOG_VERSION_16BIT_LE
+ count = len(resoperations.opname)
+ content = [version, MARK_RESOP_META,
+ encode_le_16bit(count)]
+ for opnum, opname in resoperations.opname.items():
+ content.append(encode_le_16bit(opnum))
+ content.append(encode_str(opname.lower()))
+ return ''.join(content)
+
+def _log_jit_counter(struct):
+ if not jitlog_enabled():
+ return
+ # addr is either a number (trace_id), or the address
+ # of the descriptor. for entries it is a the trace_id,
+ # for any label/bridge entry the addr is the address
+ list = [MARK_JITLOG_COUNTER, encode_le_addr(struct.number),
+ struct.type, encode_le_64bit(struct.i)]
+ content = ''.join(list)
+ jitlog_write_marked(content, len(content))
+
+class JitLogger(object):
+ def __init__(self, cpu=None):
+ self.cpu = cpu
+ self.memo = {}
+ self.trace_id = -1
+ self.metainterp_sd = None
+ # legacy
+ self.logger_ops = None
+ self.logger_noopt = None
+
+ def setup_once(self):
+ if jitlog_enabled():
+ return
+ jitlog_try_init_using_env()
+ if not jitlog_enabled():
+ return
+ blob = assemble_header()
+ jitlog_write_marked(MARK_JITLOG_HEADER + blob, len(blob) + 1)
+
+ def finish(self):
+ jitlog_teardown()
+
+ def start_new_trace(self, metainterp_sd, faildescr=None,
entry_bridge=False):
+ # even if the logger is not enabled, increment the trace id
+ self.trace_id += 1
+ if not jitlog_enabled():
+ return
+ self.metainterp_sd = metainterp_sd
+ content = [encode_le_addr(self.trace_id)]
+ if faildescr:
+ content.append(encode_str('bridge'))
+ descrnmr = compute_unique_id(faildescr)
+ content.append(encode_le_addr(descrnmr))
+ else:
+ content.append(encode_str('loop'))
+ content.append(encode_le_addr(int(entry_bridge)))
+ self._write_marked(MARK_START_TRACE, ''.join(content))
+
+ def trace_aborted(self):
+ if not jitlog_enabled():
+ return
+ self._write_marked(MARK_ABORT_TRACE, encode_le_64bit(self.trace_id))
+
+ def _write_marked(self, mark, line):
+ if not we_are_translated():
+ assert jitlog_enabled()
+ jitlog_write_marked(mark + line, len(line) + 1)
+
+ def log_jit_counter(self, struct):
+ _log_jit_counter(struct)
+
+ def log_trace(self, tag, metainterp_sd, mc, memo=None):
+ if not jitlog_enabled():
+ return EMPTY_TRACE_LOG
+ assert self.metainterp_sd is not None
+ if memo is None:
+ memo = {}
+ return LogTrace(tag, memo, self.metainterp_sd, mc, self)
+
+ def log_patch_guard(self, descr_number, addr):
+ if not jitlog_enabled():
+ return
+ le_descr_number = encode_le_addr(descr_number)
+ le_addr = encode_le_addr(addr)
+ lst = [le_descr_number, le_addr]
+ self._write_marked(MARK_STITCH_BRIDGE, ''.join(lst))
+
+class BaseLogTrace(object):
+ def write_trace(self, trace):
+ return None
+
+ def write(self, args, ops, ops_offset={}):
+ return None
+
+EMPTY_TRACE_LOG = BaseLogTrace()
+
+class PrefixCompressor(object):
+ def __init__(self, count):
+ self.prefixes = [None] * count
+ self.written_prefixes = [None] * count
+
+ def get_last(self, index):
+ return self.prefixes[index]
+
+ def get_last_written(self, index):
+ return self.written_prefixes[index]
+
+ def compress(self, index, string):
+ assert string is not None
+ last = self.get_last(index)
+ if last is None:
+ self.prefixes[index] = string
+ return None
+ cp = commonprefix(last, string)
+ if len(cp) <= 1: # prevent very small common prefixes (like "/")
+ self.prefixes[index] = string
+ return None
+ return cp
+
+
+ def write(self, log, index, prefix):
+ # we have a new prefix
+ log._write_marked(MARK_COMMON_PREFIX, chr(index) \
+ + encode_str(prefix))
+ self.written_prefixes[index] = prefix
+
+def encode_merge_point(log, compressor, values):
+ line = []
+ unrolled = unrolling_iterable(values)
+ i = 0
+ for value in unrolled:
+ line.append(value.encode(log,i,compressor))
+ i += 1
+ return ''.join(line)
+
+
+class LogTrace(BaseLogTrace):
+ def __init__(self, tag, memo, metainterp_sd, mc, logger):
+ self.memo = memo
+ self.metainterp_sd = metainterp_sd
+ self.ts = None
+ if self.metainterp_sd is not None:
+ self.ts = metainterp_sd.cpu.ts
+ self.tag = tag
+ self.mc = mc
+ self.logger = logger
+ self.common_prefix = None
+
+ def write_trace(self, trace):
+ ops = []
+ i = trace.get_iter()
+ while not i.done():
+ ops.append(i.next())
+ self.write(i.inputargs, ops)
+
+ def write(self, args, ops, ops_offset={}):
+ log = self.logger
+ log._write_marked(self.tag, encode_le_64bit(self.logger.trace_id))
+
+ # input args
+ str_args = [self.var_to_str(arg) for arg in args]
+ string = encode_str(','.join(str_args))
+ log._write_marked(MARK_INPUT_ARGS, string)
+
+ # assembler address (to not duplicate it in write_code_dump)
+ if self.mc is not None:
+ absaddr = self.mc.absolute_addr()
+ rel = self.mc.get_relative_pos()
+ # packs <start addr> <end addr> as two unsigend longs
+ le_addr1 = encode_le_addr(absaddr)
+ le_addr2 = encode_le_addr(absaddr + rel)
+ log._write_marked(MARK_ASM_ADDR, le_addr1 + le_addr2)
+ for i,op in enumerate(ops):
+ if rop.DEBUG_MERGE_POINT == op.getopnum():
+ self.encode_debug_info(op)
+ continue
+ mark, line = self.encode_op(op)
+ log._write_marked(mark, line)
+ self.write_core_dump(ops, i, op, ops_offset)
+
+ self.memo = {}
+
+ def encode_once(self):
+ pass
+
+ def encode_debug_info(self, op):
+ # the idea is to write the debug merge point as it's own well known
+ # tag. Compression for common prefixes is implemented:
+
+ log = self.logger
+ jd_sd = self.metainterp_sd.jitdrivers_sd[op.getarg(0).getint()]
+ if not jd_sd.warmstate.get_location:
+ return
+ values = jd_sd.warmstate.get_location(op.getarglist()[3:])
+ if values is None:
+ # indicates that this function is not provided to the jit driver
+ return
+ types = jd_sd.warmstate.get_location_types
+
+ if self.common_prefix is None:
+ # first time visiting a merge point
+ # setup the common prefix
+ self.common_prefix = PrefixCompressor(len(types))
+ encoded_types = []
+ for i, (semantic_type, generic_type) in enumerate(types):
+ encoded_types.append(chr(semantic_type))
+ encoded_types.append(generic_type)
+ count = encode_le_16bit(len(types))
+ log._write_marked(MARK_INIT_MERGE_POINT, count +
''.join(encoded_types))
+
+ # the types have already been written
+ encoded = encode_merge_point(log, self.common_prefix, values)
+ log._write_marked(MARK_MERGE_POINT, encoded)
+
+ def encode_op(self, op):
+ """ an operation is written as follows:
+ <marker> <opid (16 bit)> \
+ <len (32 bit)> \
+ <res_val>,<arg_0>,...,<arg_n>,<descr>
+ The marker indicates if the last argument is
+ a descr or a normal argument.
+ """
+ str_args = [self.var_to_str(arg) for arg in op.getarglist()]
+ descr = op.getdescr()
+ le_opnum = encode_le_16bit(op.getopnum())
+ str_res = self.var_to_str(op)
+ line = ','.join([str_res] + str_args)
+ if descr:
+ descr_str = descr.repr_of_descr()
+ line = line + ',' + descr_str
+ string = encode_str(line)
+ descr_number = compute_unique_id(descr)
+ le_descr_number = encode_le_addr(descr_number)
+ return MARK_RESOP_DESCR, le_opnum + string + le_descr_number
+ else:
+ string = encode_str(line)
+ return MARK_RESOP, le_opnum + string
+
+
+ def write_core_dump(self, operations, i, op, ops_offset):
+ if self.mc is None:
+ return
+
+ op2 = None
+ j = i+1
+ # find the next op that is in the offset hash
+ while j < len(operations):
+ op2 = operations[j]
+ if op in ops_offset:
+ break
+ j += 1
+
+ # this op has no known offset in the machine code (it might be
+ # a debug operation)
+ if op not in ops_offset:
+ return
+ # there is no well defined boundary for the end of the
+ # next op in the assembler
+ if op2 is not None and op2 not in ops_offset:
+ return
+ dump = []
+
+ start_offset = ops_offset[op]
+ assert start_offset >= 0
+ # end offset is either the last pos in the assembler
+ # or the offset of op2
+ if op2 is None:
+ end_offset = self.mc.get_relative_pos()
+ else:
+ end_offset = ops_offset[op2]
+
+ count = end_offset - start_offset
+ dump = self.copy_core_dump(self.mc.absolute_addr(), start_offset,
count)
+ offset = encode_le_16bit(start_offset)
+ edump = encode_str(dump)
+ self.logger._write_marked(MARK_ASM, offset + edump)
+
+ def copy_core_dump(self, addr, offset=0, count=-1):
+ dump = []
+ src = rffi.cast(rffi.CCHARP, addr)
+ end = self.mc.get_relative_pos()
+ if count != -1:
+ end = offset + count
+ for p in range(offset, end):
+ dump.append(src[p])
+ return ''.join(dump)
+
+ def var_to_str(self, arg):
+ try:
+ mv = self.memo[arg]
+ except KeyError:
+ mv = len(self.memo)
+ self.memo[arg] = mv
+ if isinstance(arg, ConstInt):
+ if self.metainterp_sd and int_could_be_an_address(arg.value):
+ addr = arg.getaddr()
+ name = self.metainterp_sd.get_name_from_address(addr)
+ if name:
+ return 'ConstClass(' + name + ')'
+ return str(arg.value)
+ elif self.ts is not None and isinstance(arg, self.ts.ConstRef):
+ if arg.value:
+ return 'ConstPtr(ptr' + str(mv) + ')'
+ return 'ConstPtr(null)'
+ if isinstance(arg, ConstFloat):
+ return str(arg.getfloat())
+ elif arg is None:
+ return 'None'
+ elif arg.is_vector():
+ return 'v' + str(mv)
+ elif arg.type == 'i':
+ return 'i' + str(mv)
+ elif arg.type == 'r':
+ return 'p' + str(mv)
+ elif arg.type == 'f':
+ return 'f' + str(mv)
+ else:
+ return '?'
+
+def int_could_be_an_address(x):
+ if we_are_translated():
+ x = rffi.cast(lltype.Signed, x) # force it
+ return not (-32768 <= x <= 32767)
+ else:
+ return isinstance(x, llmemory.AddressAsInt)
diff --git a/rpython/rlib/rjitlog/src/rjitlog.c
b/rpython/rlib/rjitlog/src/rjitlog.c
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/rjitlog/src/rjitlog.c
@@ -0,0 +1,91 @@
+#define _GNU_SOURCE 1
+
+#ifdef RPYTHON_LL2CTYPES
+/* only for testing: ll2ctypes sets RPY_EXTERN from the command-line */
+#ifndef RPY_EXTERN
+#define RPY_EXTERN RPY_EXPORTED
+#endif
+#ifdef _WIN32
+#define RPY_EXPORTED __declspec(dllexport)
+#else
+#define RPY_EXPORTED extern __attribute__((visibility("default")))
+#endif
+#else
+#include "common_header.h"
+#include "structdef.h"
+#include "src/threadlocal.h"
+#include "rjitlog.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+static int jitlog_fd = -1;
+static int jitlog_ready = 0;
+
+RPY_EXTERN
+int jitlog_enabled()
+{
+ return jitlog_ready;
+}
+
+RPY_EXTERN
+void jitlog_try_init_using_env(void) {
+ if (jitlog_ready) { return; }
+
+ char *filename = getenv("JITLOG");
+
+ if (filename && filename[0]) {
+ // mode is 775
+ mode_t mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
+ jitlog_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, mode);
+ if (jitlog_fd == -1) {
+ dprintf(2, "could not open '%s': ", filename);
+ perror(NULL);
+ exit(-1);
+ }
+ } else {
+ jitlog_ready = 0;
+ return;
+ }
+#ifndef _WIN32
+ unsetenv("JITLOG");
+#else
+ putenv("JITLOG=");
+#endif
+ jitlog_ready = 1;
+}
+
+RPY_EXTERN
+char *jitlog_init(int fd)
+{
+ jitlog_fd = fd;
+ jitlog_ready = 1;
+ return NULL;
+}
+
+RPY_EXTERN
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit