aboutsummaryrefslogtreecommitdiff
path: root/src/jit/p.lua
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/jit/p.lua218
1 files changed, 218 insertions, 0 deletions
diff --git a/src/jit/p.lua b/src/jit/p.lua
new file mode 100644
index 00000000..75d93215
--- /dev/null
+++ b/src/jit/p.lua
@@ -0,0 +1,218 @@
1----------------------------------------------------------------------------
2-- LuaJIT profiler.
3--
4-- Copyright (C) 2005-2013 Mike Pall. All rights reserved.
5-- Released under the MIT license. See Copyright Notice in luajit.h
6----------------------------------------------------------------------------
7--
8-- This module is a simple command line interface to the built-in
9-- low-overhead profiler of LuaJIT.
10--
11-- The lower-level API of the profiler is accessible via the "jit.profile"
12-- module or the luaJIT_profile_* C API.
13--
14-- Example usage:
15--
16-- luajit -jp myapp.lua
17-- luajit -jp=s myapp.lua
18-- luajit -jp=-s myapp.lua
19-- luajit -jp=vl myapp.lua
20-- luajit -jp=G,profile.txt myapp.lua
21--
22-- The following dump features are available:
23--
24-- f Stack dump: function name, Otherwise module:line. Default mode
25-- F Stack dump: ditto, but always prepend module.
26-- l Stack dump: module:line.
27-- <number> stack dump depth (callee < caller). Default: 1.
28-- -<number> Inverse stack dump depth (caller > callee).
29-- s Split stack dump after first stack level. Implies abs(depth) >= 2.
30-- p Show full path for module names.
31-- v Show VM states. Can be combined with stack dumps, e.g. vf or fv.
32-- z Show zones. Can be combined with stack dumps, e.g. zf or fz.
33-- r Show raw sample counts. Default: show percentages.
34-- G Produce output suitable for graphical tools (e.g. flame graphs).
35-- n<number> Show top N samples. Default: 10.
36-- i<number> Sampling interval in milliseconds. Default: 10.
37--
38----------------------------------------------------------------------------
39
40-- Cache some library functions and objects.
41local jit = require("jit")
42assert(jit.version_num == 20100, "LuaJIT core/library version mismatch")
43local profile = require("jit.profile")
44local vmdef = require("jit.vmdef")
45local pairs, tonumber, floor, min = pairs, tonumber, math.floor, math.min
46local sort, format = table.sort, string.format
47local stdout = io.stdout
48local zone -- Load jit.zone module on demand.
49
50-- Output file handle.
51local out
52
53------------------------------------------------------------------------------
54
55local prof_ud
56local prof_states, prof_split, prof_maxn, prof_raw, prof_fmt, prof_depth
57local prof_count1, prof_count2, prof_samples
58
59local map_vmmode = {
60 N = "Compiled",
61 I = "Interpreted",
62 C = "C code",
63 G = "Garbage Collector",
64 J = "JIT Compiler",
65}
66
67-- Profiler callback.
68local function prof_cb(th, samples, vmmode)
69 prof_samples = prof_samples + samples
70 local key_stack, key_stack2, key_state
71 -- Collect keys for sample.
72 if prof_states then
73 if prof_states == "v" then
74 key_state = map_vmmode[vmmode] or vmmode
75 else
76 key_state = zone:get() or "(none)"
77 end
78 end
79 if prof_fmt then
80 key_stack = profile.dumpstack(th, prof_fmt, prof_depth)
81 key_stack = key_stack:gsub("%[builtin#(%d+)%]", function(x)
82 return vmdef.ffnames[tonumber(x)]
83 end)
84 if prof_split == 2 then
85 local k1, k2 = key_stack:match("(.-) [<>] (.*)")
86 if k2 then key_stack, key_stack2 = k1, k2 end
87 end
88 end
89 -- Order keys.
90 local k1, k2
91 if prof_split == 1 then
92 if key_state then
93 k1 = key_state
94 if key_stack then k2 = key_stack end
95 end
96 elseif key_stack then
97 k1 = key_stack
98 if key_stack2 then k2 = key_stack2 elseif key_state then k2 = key_state end
99 end
100 -- Coalesce samples in one or two levels.
101 if k1 then
102 local t1 = prof_count1
103 t1[k1] = (t1[k1] or 0) + samples
104 if k2 then
105 local t2 = prof_count2
106 local t3 = t2[k1]
107 if not t3 then t3 = {}; t2[k1] = t3 end
108 t3[k2] = (t3[k2] or 0) + samples
109 end
110 end
111end
112
113------------------------------------------------------------------------------
114
115-- Show top N list.
116local function prof_top(count1, count2, samples, indent)
117 local t, n = {}, 0
118 for k, v in pairs(count1) do
119 n = n + 1
120 t[n] = k
121 end
122 sort(t, function(a, b) return count1[a] > count1[b] end)
123 local raw = prof_raw
124 for i=1,min(n, prof_maxn) do
125 local k = t[i]
126 local v = count1[k]
127 if not raw then
128 out:write(format("%s%2d%% %s\n", indent, floor(v*100/samples + 0.5), k))
129 elseif raw == "r" then
130 out:write(format("%s%5d %s\n", indent, v, k))
131 else
132 out:write(format("%s %d\n", k, v))
133 end
134 if count2 then
135 local r = count2[k]
136 if r then
137 prof_top(r, nil, v, prof_depth < 0 and " -> " or " <- ")
138 end
139 end
140 end
141end
142
143------------------------------------------------------------------------------
144
145-- Finish profiling and dump result.
146local function prof_finish()
147 if prof_ud then
148 profile.stop()
149 local samples = prof_samples
150 if samples == 0 then
151 if prof_raw ~= true then out:write("[no samples collected]\n") end
152 return
153 end
154 prof_top(prof_count1, prof_count2, samples, "")
155 prof_count1 = nil
156 prof_count2 = nil
157 prof_ud = nil
158 end
159end
160
161-- Start profiling.
162local function prof_start(mode)
163 local interval = ""
164 mode = mode:gsub("i%d*", function(s) interval = s; return "" end)
165 prof_maxn = 10
166 mode = mode:gsub("n(%d+)", function(s) prof_maxn = tonumber(s); return "" end)
167 prof_depth = 1
168 mode = mode:gsub("%-?%d+", function(s) prof_depth = tonumber(s); return "" end)
169 local m = {}
170 for c in mode:gmatch(".") do m[c] = c end
171 prof_states = m.z or m.v
172 if prof_states == "z" then zone = require("jit.zone") end
173 local scope = m.l or m.f or m.F or (prof_states and "" or "f")
174 local flags = (m.p or "")
175 prof_raw = m.r
176 if m.s then
177 prof_split = 2
178 if prof_depth == -1 or m["-"] then prof_depth = -2
179 elseif prof_depth == 1 then prof_depth = 2 end
180 else
181 prof_split = (scope == "" or mode:find("[zv].*[lfF]")) and 1 or 0
182 end
183 if m.G and scope ~= "" then
184 prof_fmt = flags..scope.."Z;"
185 prof_depth = -100
186 prof_raw = true
187 prof_maxn = 2147483647
188 elseif scope == "" then
189 prof_fmt = false
190 else
191 prof_fmt = flags..scope..(prof_depth >= 0 and "Z < " or "Z > ")
192 end
193 prof_count1 = {}
194 prof_count2 = {}
195 prof_samples = 0
196 profile.start(scope:lower()..interval, prof_cb)
197 prof_ud = newproxy(true)
198 getmetatable(prof_ud).__gc = prof_finish
199end
200
201------------------------------------------------------------------------------
202
203local function start(mode, outfile)
204 if not outfile then outfile = os.getenv("LUAJIT_PROFILEFILE") end
205 if outfile then
206 out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
207 else
208 out = stdout
209 end
210 prof_start(mode or "f")
211end
212
213-- Public module functions.
214return {
215 start = start, -- For -j command line option.
216 stop = prof_finish
217}
218