1 ----------------------------------------------------------------------------
2 -- Verbose mode of the LuaJIT compiler.
4 -- Copyright (C) 2005-2015 Mike Pall. All rights reserved.
5 -- Released under the MIT license. See Copyright Notice in luajit.h
6 ----------------------------------------------------------------------------
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.
15 -- luajit -jv -e "for i=1,1000 do for j=1,1000 do end end"
16 -- luajit -jv=myapp.out myapp.lua
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
23 -- The output from the first example should look like this:
25 -- [TRACE 1 (command line):1 loop]
26 -- [TRACE 2 (1/3) (command line):1 -> 1]
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.
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! :-)
43 -- Aborted traces are shown like this:
45 -- [TRACE --- foo.lua:44 -- leaving loop in root trace at foo:lua:50]
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.
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.
56 -- Also check out the -jdump module, which prints all the gory details.
58 ------------------------------------------------------------------------------
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
69 -- Active flag and output file handle.
72 ------------------------------------------------------------------------------
74 local startloc
, startex
76 local function fmtfunc(func
, pc
)
77 local fi
= funcinfo(func
, pc
)
81 return vmdef
.ffnames
[fi
.ffid
]
83 return format("C:%x", fi
.addr
)
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
)
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 ""
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
))
110 out
:write(format("[TRACE --- %s%s -- %s]\n",
111 startex
, startloc
, fmterr(otr
, oex
)))
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
))
129 out
:write(format("[TRACE %3s %s%s -> %d %s]\n",
130 tr
, startex
, startloc
, link
, ltype
))
133 out
:write(format("[TRACE %s]\n", what
))
139 ------------------------------------------------------------------------------
141 -- Detach dump handlers.
142 local function dumpoff()
145 jit
.attach(dump_trace
)
146 if out
and out
~= stdout
and out
~= stderr
then out
:close() end
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
156 out
= outfile
== "-" and stdout
or assert(io
.open(outfile
, "w"))
160 jit
.attach(dump_trace
, "trace")
164 -- Public module functions.
168 start
= dumpon
-- For -j command line option.