v.lua 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. ----------------------------------------------------------------------------
  2. -- Verbose mode of the LuaJIT compiler.
  3. --
  4. -- Copyright (C) 2005-2025 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. -- Cache some library functions and objects.
  60. local jit = require("jit")
  61. local jutil = require("jit.util")
  62. local vmdef = require("jit.vmdef")
  63. local funcinfo, traceinfo = jutil.funcinfo, jutil.traceinfo
  64. local type, sub, format = type, string.sub, string.format
  65. local stdout, stderr = io.stdout, io.stderr
  66. -- Active flag and output file handle.
  67. local active, out
  68. ------------------------------------------------------------------------------
  69. local startloc, startex
  70. local function fmtfunc(func, pc)
  71. local fi = funcinfo(func, pc)
  72. if fi.loc then
  73. return fi.loc
  74. elseif fi.ffid then
  75. return vmdef.ffnames[fi.ffid]
  76. elseif fi.addr then
  77. return format("C:%x", fi.addr)
  78. else
  79. return "(?)"
  80. end
  81. end
  82. -- Format trace error message.
  83. local function fmterr(err, info)
  84. if type(err) == "number" then
  85. if type(info) == "function" then info = fmtfunc(info) end
  86. local fmt = vmdef.traceerr[err]
  87. if fmt == "NYI: bytecode %s" then
  88. local oidx = 6 * info
  89. info = sub(vmdef.bcnames, oidx+1, oidx+6)
  90. end
  91. err = format(fmt, info)
  92. end
  93. return err
  94. end
  95. -- Dump trace states.
  96. local function dump_trace(what, tr, func, pc, otr, oex)
  97. if what == "start" then
  98. startloc = fmtfunc(func, pc)
  99. startex = otr and "("..otr.."/"..(oex == -1 and "stitch" or oex)..") " or ""
  100. else
  101. if what == "abort" then
  102. local loc = fmtfunc(func, pc)
  103. if loc ~= startloc then
  104. out:write(format("[TRACE --- %s%s -- %s at %s]\n",
  105. startex, startloc, fmterr(otr, oex), loc))
  106. else
  107. out:write(format("[TRACE --- %s%s -- %s]\n",
  108. startex, startloc, fmterr(otr, oex)))
  109. end
  110. elseif what == "stop" then
  111. local info = traceinfo(tr)
  112. local link, ltype = info.link, info.linktype
  113. if ltype == "interpreter" then
  114. out:write(format("[TRACE %3s %s%s -- fallback to interpreter]\n",
  115. tr, startex, startloc))
  116. elseif ltype == "stitch" then
  117. out:write(format("[TRACE %3s %s%s %s %s]\n",
  118. tr, startex, startloc, ltype, fmtfunc(func, pc)))
  119. elseif link == tr or link == 0 then
  120. out:write(format("[TRACE %3s %s%s %s]\n",
  121. tr, startex, startloc, ltype))
  122. elseif ltype == "root" then
  123. out:write(format("[TRACE %3s %s%s -> %d]\n",
  124. tr, startex, startloc, link))
  125. else
  126. out:write(format("[TRACE %3s %s%s -> %d %s]\n",
  127. tr, startex, startloc, link, ltype))
  128. end
  129. else
  130. out:write(format("[TRACE %s]\n", what))
  131. end
  132. out:flush()
  133. end
  134. end
  135. ------------------------------------------------------------------------------
  136. -- Detach dump handlers.
  137. local function dumpoff()
  138. if active then
  139. active = false
  140. jit.attach(dump_trace)
  141. if out and out ~= stdout and out ~= stderr then out:close() end
  142. out = nil
  143. end
  144. end
  145. -- Open the output file and attach dump handlers.
  146. local function dumpon(outfile)
  147. if active then dumpoff() end
  148. if not outfile then outfile = os.getenv("LUAJIT_VERBOSEFILE") end
  149. if outfile then
  150. out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
  151. else
  152. out = stderr
  153. end
  154. jit.attach(dump_trace, "trace")
  155. active = true
  156. end
  157. -- Public module functions.
  158. return {
  159. on = dumpon,
  160. off = dumpoff,
  161. start = dumpon -- For -j command line option.
  162. }