ljx

FORK: LuaJIT with native 5.2 and 5.3 support
git clone https://git.neptards.moe/neptards/ljx.git
Log | Files | Refs | README

v.lua (5755B)


      1 ----------------------------------------------------------------------------
      2 -- Verbose mode of the LuaJIT compiler.
      3 --
      4 -- Copyright (C) 2005-2016 Mike Pall. All rights reserved.
      5 -- Released under the MIT license. See Copyright Notice in luajit.h
      6 ----------------------------------------------------------------------------
      7 --
      8 -- This module shows verbose information about the progress of the
      9 -- JIT compiler. It prints one line for each generated trace. This module
     10 -- is useful to see which code has been compiled or where the compiler
     11 -- punts and falls back to the interpreter.
     12 --
     13 -- Example usage:
     14 --
     15 --   luajit -jv -e "for i=1,1000 do for j=1,1000 do end end"
     16 --   luajit -jv=myapp.out myapp.lua
     17 --
     18 -- Default output is to stderr. To redirect the output to a file, pass a
     19 -- filename as an argument (use '-' for stdout) or set the environment
     20 -- variable LUAJIT_VERBOSEFILE. The file is overwritten every time the
     21 -- module is started.
     22 --
     23 -- The output from the first example should look like this:
     24 --
     25 -- [TRACE   1 (command line):1 loop]
     26 -- [TRACE   2 (1/3) (command line):1 -> 1]
     27 --
     28 -- The first number in each line is the internal trace number. Next are
     29 -- the file name ('(command line)') and the line number (':1') where the
     30 -- trace has started. Side traces also show the parent trace number and
     31 -- the exit number where they are attached to in parentheses ('(1/3)').
     32 -- An arrow at the end shows where the trace links to ('-> 1'), unless
     33 -- it loops to itself.
     34 --
     35 -- In this case the inner loop gets hot and is traced first, generating
     36 -- a root trace. Then the last exit from the 1st trace gets hot, too,
     37 -- and triggers generation of the 2nd trace. The side trace follows the
     38 -- path along the outer loop and *around* the inner loop, back to its
     39 -- start, and then links to the 1st trace. Yes, this may seem unusual,
     40 -- if you know how traditional compilers work. Trace compilers are full
     41 -- of surprises like this -- have fun! :-)
     42 --
     43 -- Aborted traces are shown like this:
     44 --
     45 -- [TRACE --- foo.lua:44 -- leaving loop in root trace at foo:lua:50]
     46 --
     47 -- Don't worry -- trace aborts are quite common, even in programs which
     48 -- can be fully compiled. The compiler may retry several times until it
     49 -- finds a suitable trace.
     50 --
     51 -- Of course this doesn't work with features that are not-yet-implemented
     52 -- (NYI error messages). The VM simply falls back to the interpreter. This
     53 -- may not matter at all if the particular trace is not very high up in
     54 -- the CPU usage profile. Oh, and the interpreter is quite fast, too.
     55 --
     56 -- Also check out the -jdump module, which prints all the gory details.
     57 --
     58 ------------------------------------------------------------------------------
     59 
     60 -- Cache some library functions and objects.
     61 local jit = require("jit")
     62 assert(jit.version_num == 20100, "LuaJIT core/library version mismatch")
     63 local jutil = require("jit.util")
     64 local vmdef = require("jit.vmdef")
     65 local funcinfo, traceinfo = jutil.funcinfo, jutil.traceinfo
     66 local type, format = type, string.format
     67 local stdout, stderr = io.stdout, io.stderr
     68 
     69 -- Active flag and output file handle.
     70 local active, out
     71 
     72 ------------------------------------------------------------------------------
     73 
     74 local startloc, startex
     75 
     76 local function fmtfunc(func, pc)
     77   local fi = funcinfo(func, pc)
     78   if fi.loc then
     79     return fi.loc
     80   elseif fi.ffid then
     81     return vmdef.ffnames[fi.ffid]
     82   elseif fi.addr then
     83     return format("C:%x", fi.addr)
     84   else
     85     return "(?)"
     86   end
     87 end
     88 
     89 -- Format trace error message.
     90 local function fmterr(err, info)
     91   if type(err) == "number" then
     92     if type(info) == "function" then info = fmtfunc(info) end
     93     err = format(vmdef.traceerr[err], info)
     94   end
     95   return err
     96 end
     97 
     98 -- Dump trace states.
     99 local function dump_trace(what, tr, func, pc, otr, oex)
    100   if what == "start" then
    101     startloc = fmtfunc(func, pc)
    102     startex = otr and "("..otr.."/"..oex..") " or ""
    103   else
    104     if what == "abort" then
    105       local loc = fmtfunc(func, pc)
    106       if loc ~= startloc then
    107 	out:write(format("[TRACE --- %s%s -- %s at %s]\n",
    108 	  startex, startloc, fmterr(otr, oex), loc))
    109       else
    110 	out:write(format("[TRACE --- %s%s -- %s]\n",
    111 	  startex, startloc, fmterr(otr, oex)))
    112       end
    113     elseif what == "stop" then
    114       local info = traceinfo(tr)
    115       local link, ltype = info.link, info.linktype
    116       if ltype == "interpreter" then
    117 	out:write(format("[TRACE %3s %s%s -- fallback to interpreter]\n",
    118 	  tr, startex, startloc))
    119       elseif ltype == "stitch" then
    120 	out:write(format("[TRACE %3s %s%s %s %s]\n",
    121 	  tr, startex, startloc, ltype, fmtfunc(func, pc)))
    122       elseif link == tr or link == 0 then
    123 	out:write(format("[TRACE %3s %s%s %s]\n",
    124 	  tr, startex, startloc, ltype))
    125       elseif ltype == "root" then
    126 	out:write(format("[TRACE %3s %s%s -> %d]\n",
    127 	  tr, startex, startloc, link))
    128       else
    129 	out:write(format("[TRACE %3s %s%s -> %d %s]\n",
    130 	  tr, startex, startloc, link, ltype))
    131       end
    132     else
    133       out:write(format("[TRACE %s]\n", what))
    134     end
    135     out:flush()
    136   end
    137 end
    138 
    139 ------------------------------------------------------------------------------
    140 
    141 -- Detach dump handlers.
    142 local function dumpoff()
    143   if active then
    144     active = false
    145     jit.attach(dump_trace)
    146     if out and out ~= stdout and out ~= stderr then out:close() end
    147     out = nil
    148   end
    149 end
    150 
    151 -- Open the output file and attach dump handlers.
    152 local function dumpon(outfile)
    153   if active then dumpoff() end
    154   if not outfile then outfile = os.getenv("LUAJIT_VERBOSEFILE") end
    155   if outfile then
    156     out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
    157   else
    158     out = stderr
    159   end
    160   jit.attach(dump_trace, "trace")
    161   active = true
    162 end
    163 
    164 -- Public module functions.
    165 return {
    166   on = dumpon,
    167   off = dumpoff,
    168   start = dumpon -- For -j command line option.
    169 }
    170