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