aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/jit/p.lua216
1 files changed, 216 insertions, 0 deletions
diff --git a/src/jit/p.lua b/src/jit/p.lua
new file mode 100644
index 00000000..a93172da
--- /dev/null
+++ b/src/jit/p.lua
@@ -0,0 +1,216 @@
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 if not t[1] then return end
123 sort(t, function(a, b) return count1[a] > count1[b] end)
124 local raw = prof_raw
125 for i=1,min(n, prof_maxn) do
126 local k = t[i]
127 local v = count1[k]
128 if not raw then
129 out:write(format("%s%2d%% %s\n", indent, floor(v*100/samples + 0.5), k))
130 elseif raw == "r" then
131 out:write(format("%s%5d %s\n", indent, v, k))
132 else
133 out:write(format("%s %d\n", k, v))
134 end
135 if count2 then
136 local r = count2[k]
137 if r then
138 prof_top(r, nil, v, prof_depth < 0 and " -> " or " <- ")
139 end
140 end
141 end
142end
143
144------------------------------------------------------------------------------
145
146-- Finish profiling and dump result.
147local function prof_finish()
148 if prof_ud then
149 profile.stop()
150 local samples = prof_samples
151 if samples == 0 then return end
152 prof_top(prof_count1, prof_count2, samples, "")
153 prof_count1 = nil
154 prof_count2 = nil
155 prof_ud = nil
156 end
157end
158
159-- Start profiling.
160local function prof_start(mode)
161 local interval = ""
162 mode = mode:gsub("i%d*", function(s) interval = s; return "" end)
163 prof_maxn = 10
164 mode = mode:gsub("n(%d+)", function(s) prof_maxn = tonumber(s); return "" end)
165 prof_depth = 1
166 mode = mode:gsub("%-?%d+", function(s) prof_depth = tonumber(s); return "" end)
167 local m = {}
168 for c in mode:gmatch(".") do m[c] = c end
169 prof_states = m.z or m.v
170 if prof_states == "z" then zone = require("jit.zone") end
171 local scope = m.l or m.f or m.F or (prof_states and "" or "f")
172 local flags = (m.p or "")
173 prof_raw = m.r
174 if m.s then
175 prof_split = 2
176 if prof_depth == -1 or m["-"] then prof_depth = -2
177 elseif prof_depth == 1 then prof_depth = 2 end
178 else
179 prof_split = (scope == "" or mode:find("[zv].*[lfF]")) and 1 or 0
180 end
181 if m.G and scope ~= "" then
182 prof_fmt = flags..scope.."Z;"
183 prof_depth = -100
184 prof_raw = true
185 prof_maxn = 2147483647
186 elseif scope == "" then
187 prof_fmt = false
188 else
189 prof_fmt = flags..scope..(prof_depth >= 0 and "Z < " or "Z > ")
190 end
191 prof_count1 = {}
192 prof_count2 = {}
193 prof_samples = 0
194 profile.start(scope:lower()..interval, prof_cb)
195 prof_ud = newproxy(true)
196 getmetatable(prof_ud).__gc = prof_finish
197end
198
199------------------------------------------------------------------------------
200
201local function start(mode, outfile)
202 if not outfile then outfile = os.getenv("LUAJIT_PROFILEFILE") end
203 if outfile then
204 out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
205 else
206 out = stdout
207 end
208 prof_start(mode or "f")
209end
210
211-- Public module functions.
212return {
213 start = start, -- For -j command line option.
214 stop = prof_finish
215}
216