Author: Richard Plangger <[email protected]>
Branch: new-jit-log
Changeset: r85809:755792b503d9
Date: 2016-07-22 10:46 +0200
http://bitbucket.org/pypy/pypy/changeset/755792b503d9/

Log:    refactor jitlog and unwind it into a new module

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
@@ -73,7 +73,7 @@
 def enable_jitlog(space, fileno):
     """ Enable PyPy's logging facility. """
     try:
-        rvmprof.enable_jitlog(fileno)
+        rjitlog.enable_jitlog(fileno)
     except rvmprof.VMProfError, e:
         raise VMProfError(space, e)
 
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
@@ -13,7 +13,7 @@
 from rpython.rlib.jitlog import _log_jit_counter
 from rpython.rtyper.annlowlevel import cast_instance_to_gcref, llhelper
 from rpython.rtyper.lltypesystem import rffi, lltype
-from rpython.rlib.rvmprof.rvmprof import _get_vmprof
+from rpython.rlib.rjitlog import rjitlog
 
 DEBUG_COUNTER = lltype.Struct('DEBUG_COUNTER',
     # 'b'ridge, 'l'abel or # 'e'ntry point
@@ -347,7 +347,7 @@
 
     @specialize.argtype(1)
     def _inject_debugging_code(self, looptoken, operations, tp, number):
-        if self._debug or _get_vmprof().cintf.jitlog_enabled():
+        if self._debug or rjitlog.jitlog_enabled():
             newoperations = []
             self._append_debugging_code(newoperations, tp, number, None)
             for op in operations:
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,7 +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.rvmprof.rvmprof import _get_vmprof
+from rpython.rlib.rjitlog import rjitlog
 from rpython.conftest import option
 
 from rpython.jit.metainterp.resoperation import ResOperation, rop,\
@@ -545,7 +545,7 @@
     operations = get_deep_immutable_oplist(loop.operations)
     metainterp_sd.profiler.start_backend()
     debug_start("jit-backend")
-    log = have_debug_prints() or _get_vmprof().cintf.jitlog_enabled()
+    log = have_debug_prints() or rjitlog.jitlog_enabled()
     try:
         loopname = jitdriver_sd.warmstate.get_location_str(greenkey)
         unique_id = jitdriver_sd.warmstate.get_unique_id(greenkey)
@@ -597,7 +597,7 @@
     operations = get_deep_immutable_oplist(operations)
     metainterp_sd.profiler.start_backend()
     debug_start("jit-backend")
-    log = have_debug_prints() or _get_vmprof().cintf.jitlog_enabled()
+    log = have_debug_prints() or rjitlog.jitlog_enabled()
     try:
         asminfo = do_compile_bridge(metainterp_sd, faildescr, inputargs,
                                     operations,
diff --git a/rpython/rlib/jitlog.py b/rpython/rlib/jitlog.py
deleted file mode 100644
--- a/rpython/rlib/jitlog.py
+++ /dev/null
@@ -1,551 +0,0 @@
-import sys
-import weakref
-import struct
-import os
-
-from rpython.rlib.rvmprof.rvmprof import _get_vmprof
-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
-
-@register_helper(None)
-def stats_flush_trace_counts(warmrunnerdesc):
-    warmrunnerdesc.metainterp_sd.cpu.assembler.flush_trace_counters()
-
-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):
-    cintf = _get_vmprof().cintf
-    if not cintf.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)
-    cintf.jitlog_write_marked(content, len(content))
-
-class VMProfJitLogger(object):
-    def __init__(self, cpu=None):
-        self.cpu = cpu
-        self.memo = {}
-        self.trace_id = -1
-        self.metainterp_sd = None
-        self.cintf = _get_vmprof().cintf
-        # legacy
-        self.logger_ops = None
-        self.logger_noopt = None
-
-    def setup_once(self):
-        if self.cintf.jitlog_enabled():
-            return
-        self.cintf.jitlog_try_init_using_env()
-        if not self.cintf.jitlog_enabled():
-            return
-        blob = assemble_header()
-        self.cintf.jitlog_write_marked(MARK_JITLOG_HEADER + blob, len(blob) + 
1)
-
-    def finish(self):
-        self.cintf.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 self.cintf.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 self.cintf.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 self.cintf.jitlog_enabled()
-        self.cintf.jitlog_write_marked(mark + line, len(line) + 1)
-
-    def log_jit_counter(self, struct):
-        _log_jit_counter(self.cintf, struct)
-
-    def log_trace(self, tag, metainterp_sd, mc, memo=None):
-        if not self.cintf.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 self.cintf.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/__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,605 @@
+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
+
[email protected]_look_inside
+def enable_jitlog(fileno):
+    # initialize the jit log
+    from rpython.rlib import jitlog as jl
+    p_error = jitlog_init(fileno)
+    if p_error:
+        raise JitlogError(rffi.charp2str(p_error))
+    blob = jl.assemble_header()
+    jitlog_write_marked(jl.MARK_JITLOG_HEADER + blob, len(blob) + 1)
+
+def disable_jitlog():
+    from rpython.rlib.jitlog import stats_flush_trace_counts
+    stats_flush_trace_counts(None)
+    jitlog_teardown()
+
+@register_helper(None)
+def stats_flush_trace_counts(warmrunnerdesc):
+    warmrunnerdesc.metainterp_sd.cpu.assembler.flush_trace_counters()
+
+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,86 @@
+#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
+#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
+void jitlog_teardown()
+{
+    jitlog_ready = 0;
+    if (jitlog_fd == -1) {
+        return;
+    }
+    // close the jitlog file descriptor
+    close(jitlog_fd);
+    jitlog_fd = -1;
+}
+
+RPY_EXTERN
+void jitlog_write_marked(char * text, int length)
+{
+    if (!jitlog_ready) { return; }
+
+    write(jitlog_fd, text, length);
+}
diff --git a/rpython/rlib/rjitlog/src/rjitlog.h 
b/rpython/rlib/rjitlog/src/rjitlog.h
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/rjitlog/src/rjitlog.h
@@ -0,0 +1,18 @@
+#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
+
+RPY_EXTERN char * jitlog_init(int);
+RPY_EXTERN void jitlog_try_init_using_env(void);
+RPY_EXTERN int jitlog_enabled();
+RPY_EXTERN void jitlog_write_marked(char*, int);
+RPY_EXTERN void jitlog_teardown();
diff --git a/rpython/rlib/rjitlog/test/test_jitlog.py 
b/rpython/rlib/rjitlog/test/test_jitlog.py
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/rjitlog/test/test_jitlog.py
@@ -0,0 +1,109 @@
+import py
+from rpython.jit.tool.oparser import pure_parse
+from rpython.jit.metainterp.optimizeopt.util import equaloplists
+from rpython.jit.metainterp.resoperation import ResOperation, rop
+from rpython.jit.backend.model import AbstractCPU
+from rpython.jit.metainterp.history import ConstInt, ConstPtr
+from rpython.rlib.rjitlog import rjitlog as jl
+
+class FakeLog(object):
+    def __init__(self):
+        self.values = []
+
+    def _write_marked(self, id, text):
+        self.values.append(id + text)
+
+def _get_location(greenkey_list):
+    assert len(greenkey_list) == 0
+    return '/home/pypy/jit.py', 0, 'enclosed', 99, 'DEL'
+
+class TestLogger(object):
+
+    def make_metainterp_sd(self):
+        class FakeJitDriver(object):
+            class warmstate(object):
+                get_location_types = [jl.MP_FILENAME,jl.MP_INT,jl.MP_SCOPE, 
jl.MP_INT, jl.MP_OPCODE]
+                @staticmethod
+                def get_location(greenkey_list):
+                    return [jl.wrap(jl.MP_FILENAME[0],'s','/home/pypy/jit.py'),
+                            jl.wrap(jl.MP_INT[0], 'i', 0),
+                            jl.wrap(jl.MP_SCOPE[0], 's', 'enclosed'),
+                            jl.wrap(jl.MP_INT[0], 'i', 99),
+                            jl.wrap(jl.MP_OPCODE[0], 's', 'DEL')
+                           ]
+
+
+        class FakeMetaInterpSd:
+            cpu = AbstractCPU()
+            cpu.ts = None
+            jitdrivers_sd = [FakeJitDriver()]
+            def get_name_from_address(self, addr):
+                return 'Name'
+        return FakeMetaInterpSd()
+
+    def test_debug_merge_point(self, tmpdir):
+        logger = jl.JitLogger()
+        file = tmpdir.join('binary_file')
+        file.ensure()
+        fd = file.open('wb')
+        jl.jitlog_init(fd.fileno())
+        logger.start_new_trace(self.make_metainterp_sd())
+        log_trace = logger.log_trace(jl.MARK_TRACE, None, None)
+        op = ResOperation(rop.DEBUG_MERGE_POINT, [ConstInt(0), ConstInt(0), 
ConstInt(0)])
+        log_trace.write([], [op])
+        #the next line will close 'fd'
+        fd.close()
+        logger.finish()
+        binary = file.read()
+        assert binary == (jl.MARK_START_TRACE) + jl.encode_le_addr(0) + \
+                         jl.encode_str('loop') + jl.encode_le_addr(0) + \
+                         (jl.MARK_TRACE) + jl.encode_le_addr(0) + \
+                         (jl.MARK_INPUT_ARGS) + jl.encode_str('') + \
+                         (jl.MARK_INIT_MERGE_POINT) + 
b'\x05\x00\x01s\x00i\x08s\x00i\x10s' + \
+                         (jl.MARK_MERGE_POINT) + \
+                         b'\xff' + jl.encode_str('/home/pypy/jit.py') + \
+                         b'\x00' + jl.encode_le_64bit(0) + \
+                         b'\xff' + jl.encode_str('enclosed') + \
+                         b'\x00' + jl.encode_le_64bit(99) + \
+                         b'\xff' + jl.encode_str('DEL')
+
+    def test_common_prefix(self):
+        fakelog = FakeLog()
+        compressor = jl.PrefixCompressor(1)
+        # nothing to compress yet!
+        result = jl.encode_merge_point(fakelog, compressor, 
[jl.StringValue(0x0,'s','hello')])
+        assert result == b"\xff\x05\x00\x00\x00hello"
+        assert fakelog.values == []
+        #
+        result = jl.encode_merge_point(fakelog, compressor, 
[jl.StringValue(0x0,'s','hello')])
+        assert result == b"\xef"
+        assert fakelog.values == [(jl.MARK_COMMON_PREFIX) + 
"\x00\x05\x00\x00\x00hello"]
+        #
+        fakelog.values = []
+        result = jl.encode_merge_point(fakelog, compressor, 
[jl.StringValue(0x0,'s','heiter')])
+        assert result == b"\x00\x04\x00\x00\x00iter"
+        assert fakelog.values == [(jl.MARK_COMMON_PREFIX) + 
"\x00\x02\x00\x00\x00he"]
+        #
+        fakelog.values = []
+        result = jl.encode_merge_point(fakelog, compressor, 
[jl.StringValue(0x0,'s','heute')])
+        assert result == b"\x00\x03\x00\x00\x00ute"
+        assert fakelog.values == []
+        #
+        fakelog.values = []
+        result = jl.encode_merge_point(fakelog, compressor, 
[jl.StringValue(0x0,'s','welt')])
+        assert result == b"\xff\x04\x00\x00\x00welt"
+        assert fakelog.values == []
+        #
+        fakelog.values = []
+        result = jl.encode_merge_point(fakelog, compressor, 
[jl.StringValue(0x0,'s','welle')])
+        assert result == b"\x00\x02\x00\x00\x00le"
+        assert fakelog.values == [(jl.MARK_COMMON_PREFIX) + 
"\x00\x03\x00\x00\x00wel"]
+
+    def test_common_prefix_func(self):
+        assert jl.commonprefix("","") == ""
+        assert jl.commonprefix("/hello/world","/path/to") == "/"
+        assert jl.commonprefix("pyramid","python") == "py"
+        assert jl.commonprefix("0"*100,"0"*100) == "0"*100
+        with py.test.raises(AssertionError):
+            jl.commonprefix(None,None)
+
diff --git a/rpython/rlib/rvmprof/__init__.py b/rpython/rlib/rvmprof/__init__.py
--- a/rpython/rlib/rvmprof/__init__.py
+++ b/rpython/rlib/rvmprof/__init__.py
@@ -35,11 +35,5 @@
 def enable(fileno, interval):
     _get_vmprof().enable(fileno, interval)
 
-def enable_jitlog(fileno):
-    _get_vmprof().enable_jitlog(fileno)
-
 def disable():
     _get_vmprof().disable()
-
-def disable_jitlog():
-    _get_vmprof().disable_jitlog()
diff --git a/rpython/rlib/rvmprof/cintf.py b/rpython/rlib/rvmprof/cintf.py
--- a/rpython/rlib/rvmprof/cintf.py
+++ b/rpython/rlib/rvmprof/cintf.py
@@ -56,21 +56,6 @@
                                             compilation_info=eci,
                                             _nowrapper=True)
 
-    # 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)
-
     return CInterface(locals())
 
 
diff --git a/rpython/rlib/rvmprof/rvmprof.py b/rpython/rlib/rvmprof/rvmprof.py
--- a/rpython/rlib/rvmprof/rvmprof.py
+++ b/rpython/rlib/rvmprof/rvmprof.py
@@ -122,21 +122,6 @@
             raise VMProfError(os.strerror(rposix.get_saved_errno()))
         self.is_enabled = True
 
-    @jit.dont_look_inside
-    def enable_jitlog(self, fileno):
-        # initialize the jit log
-        from rpython.rlib import jitlog as jl
-        p_error = self.cintf.jitlog_init(fileno)
-        if p_error:
-            raise VMProfError(rffi.charp2str(p_error))
-        blob = jl.assemble_header()
-        self.cintf.jitlog_write_marked(jl.MARK_JITLOG_HEADER + blob, len(blob) 
+ 1)
-
-    def disable_jitlog(self):
-        from rpython.rlib.jitlog import stats_flush_trace_counts
-        stats_flush_trace_counts(None)
-        self.cintf.jitlog_teardown()
-
     def disable(self):
         """Disable vmprof.
         Raises VMProfError if something goes wrong.
diff --git a/rpython/rlib/rvmprof/src/jitlog_main.h 
b/rpython/rlib/rvmprof/src/jitlog_main.h
deleted file mode 100644
--- a/rpython/rlib/rvmprof/src/jitlog_main.h
+++ /dev/null
@@ -1,69 +0,0 @@
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.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
-void jitlog_teardown()
-{
-    jitlog_ready = 0;
-    if (jitlog_fd == -1) {
-        return;
-    }
-    // close the jitlog file descriptor
-    close(jitlog_fd);
-    jitlog_fd = -1;
-}
-
-RPY_EXTERN
-void jitlog_write_marked(char * text, int length)
-{
-    if (!jitlog_ready) { return; }
-
-    write(jitlog_fd, text, length);
-}
diff --git a/rpython/rlib/rvmprof/src/rvmprof.h 
b/rpython/rlib/rvmprof/src/rvmprof.h
--- a/rpython/rlib/rvmprof/src/rvmprof.h
+++ b/rpython/rlib/rvmprof/src/rvmprof.h
@@ -8,9 +8,3 @@
 RPY_EXTERN int vmprof_stack_append(void*, long);
 RPY_EXTERN long vmprof_stack_pop(void*);
 RPY_EXTERN void vmprof_stack_free(void*);
-
-RPY_EXTERN char * jitlog_init(int);
-RPY_EXTERN void jitlog_try_init_using_env(void);
-RPY_EXTERN int jitlog_enabled();
-RPY_EXTERN void jitlog_write_marked(char*, int);
-RPY_EXTERN void jitlog_teardown();
diff --git a/rpython/rlib/test/test_jitlog.py b/rpython/rlib/test/test_jitlog.py
deleted file mode 100644
--- a/rpython/rlib/test/test_jitlog.py
+++ /dev/null
@@ -1,110 +0,0 @@
-import py
-from rpython.jit.tool.oparser import pure_parse
-from rpython.jit.metainterp.optimizeopt.util import equaloplists
-from rpython.jit.metainterp.resoperation import ResOperation, rop
-from rpython.jit.backend.model import AbstractCPU
-from rpython.jit.metainterp.history import ConstInt, ConstPtr
-from rpython.rlib.jitlog import (encode_str, encode_le_16bit, encode_le_64bit)
-from rpython.rlib import jitlog as jl
-
-class FakeLog(object):
-    def __init__(self):
-        self.values = []
-
-    def _write_marked(self, id, text):
-        self.values.append(id + text)
-
-def _get_location(greenkey_list):
-    assert len(greenkey_list) == 0
-    return '/home/pypy/jit.py', 0, 'enclosed', 99, 'DEL'
-
-class TestLogger(object):
-
-    def make_metainterp_sd(self):
-        class FakeJitDriver(object):
-            class warmstate(object):
-                get_location_types = [jl.MP_FILENAME,jl.MP_INT,jl.MP_SCOPE, 
jl.MP_INT, jl.MP_OPCODE]
-                @staticmethod
-                def get_location(greenkey_list):
-                    return [jl.wrap(jl.MP_FILENAME[0],'s','/home/pypy/jit.py'),
-                            jl.wrap(jl.MP_INT[0], 'i', 0),
-                            jl.wrap(jl.MP_SCOPE[0], 's', 'enclosed'),
-                            jl.wrap(jl.MP_INT[0], 'i', 99),
-                            jl.wrap(jl.MP_OPCODE[0], 's', 'DEL')
-                           ]
-
-
-        class FakeMetaInterpSd:
-            cpu = AbstractCPU()
-            cpu.ts = None
-            jitdrivers_sd = [FakeJitDriver()]
-            def get_name_from_address(self, addr):
-                return 'Name'
-        return FakeMetaInterpSd()
-
-    def test_debug_merge_point(self, tmpdir):
-        logger = jl.VMProfJitLogger()
-        file = tmpdir.join('binary_file')
-        file.ensure()
-        fd = file.open('wb')
-        logger.cintf.jitlog_init(fd.fileno())
-        logger.start_new_trace(self.make_metainterp_sd())
-        log_trace = logger.log_trace(jl.MARK_TRACE, None, None)
-        op = ResOperation(rop.DEBUG_MERGE_POINT, [ConstInt(0), ConstInt(0), 
ConstInt(0)])
-        log_trace.write([], [op])
-        #the next line will close 'fd'
-        fd.close()
-        logger.finish()
-        binary = file.read()
-        assert binary == (jl.MARK_START_TRACE) + jl.encode_le_addr(0) + \
-                         jl.encode_str('loop') + jl.encode_le_addr(0) + \
-                         (jl.MARK_TRACE) + jl.encode_le_addr(0) + \
-                         (jl.MARK_INPUT_ARGS) + jl.encode_str('') + \
-                         (jl.MARK_INIT_MERGE_POINT) + 
b'\x05\x00\x01s\x00i\x08s\x00i\x10s' + \
-                         (jl.MARK_MERGE_POINT) + \
-                         b'\xff' + encode_str('/home/pypy/jit.py') + \
-                         b'\x00' + encode_le_64bit(0) + \
-                         b'\xff' + encode_str('enclosed') + \
-                         b'\x00' + encode_le_64bit(99) + \
-                         b'\xff' + encode_str('DEL')
-
-    def test_common_prefix(self):
-        fakelog = FakeLog()
-        compressor = jl.PrefixCompressor(1)
-        # nothing to compress yet!
-        result = jl.encode_merge_point(fakelog, compressor, 
[jl.StringValue(0x0,'s','hello')])
-        assert result == b"\xff\x05\x00\x00\x00hello"
-        assert fakelog.values == []
-        #
-        result = jl.encode_merge_point(fakelog, compressor, 
[jl.StringValue(0x0,'s','hello')])
-        assert result == b"\xef"
-        assert fakelog.values == [(jl.MARK_COMMON_PREFIX) + 
"\x00\x05\x00\x00\x00hello"]
-        #
-        fakelog.values = []
-        result = jl.encode_merge_point(fakelog, compressor, 
[jl.StringValue(0x0,'s','heiter')])
-        assert result == b"\x00\x04\x00\x00\x00iter"
-        assert fakelog.values == [(jl.MARK_COMMON_PREFIX) + 
"\x00\x02\x00\x00\x00he"]
-        #
-        fakelog.values = []
-        result = jl.encode_merge_point(fakelog, compressor, 
[jl.StringValue(0x0,'s','heute')])
-        assert result == b"\x00\x03\x00\x00\x00ute"
-        assert fakelog.values == []
-        #
-        fakelog.values = []
-        result = jl.encode_merge_point(fakelog, compressor, 
[jl.StringValue(0x0,'s','welt')])
-        assert result == b"\xff\x04\x00\x00\x00welt"
-        assert fakelog.values == []
-        #
-        fakelog.values = []
-        result = jl.encode_merge_point(fakelog, compressor, 
[jl.StringValue(0x0,'s','welle')])
-        assert result == b"\x00\x02\x00\x00\x00le"
-        assert fakelog.values == [(jl.MARK_COMMON_PREFIX) + 
"\x00\x03\x00\x00\x00wel"]
-
-    def test_common_prefix_func(self):
-        assert jl.commonprefix("","") == ""
-        assert jl.commonprefix("/hello/world","/path/to") == "/"
-        assert jl.commonprefix("pyramid","python") == "py"
-        assert jl.commonprefix("0"*100,"0"*100) == "0"*100
-        with py.test.raises(AssertionError):
-            jl.commonprefix(None,None)
-
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to