mirror of
https://github.com/LuaJIT/LuaJIT.git
synced 2025-02-07 23:24:09 +00:00
Low-overhead profiler, part 5: add annotation mode for -jp.
This commit is contained in:
parent
1fd2048c8d
commit
2befb8b1de
@ -31,6 +31,8 @@
|
|||||||
-- v Show VM states. Can be combined with stack dumps, e.g. vf or fv.
|
-- v Show VM states. Can be combined with stack dumps, e.g. vf or fv.
|
||||||
-- z Show zones. Can be combined with stack dumps, e.g. zf or fz.
|
-- z Show zones. Can be combined with stack dumps, e.g. zf or fz.
|
||||||
-- r Show raw sample counts. Default: show percentages.
|
-- r Show raw sample counts. Default: show percentages.
|
||||||
|
-- a Annotate excerpts from source code files.
|
||||||
|
-- A Annotate complete source code files.
|
||||||
-- G Produce output suitable for graphical tools (e.g. flame graphs).
|
-- G Produce output suitable for graphical tools (e.g. flame graphs).
|
||||||
-- m<number> Minimum sample percentage to be shown. Default: 3.
|
-- m<number> Minimum sample percentage to be shown. Default: 3.
|
||||||
-- i<number> Sampling interval in milliseconds. Default: 10.
|
-- i<number> Sampling interval in milliseconds. Default: 10.
|
||||||
@ -42,7 +44,8 @@ local jit = require("jit")
|
|||||||
assert(jit.version_num == 20100, "LuaJIT core/library version mismatch")
|
assert(jit.version_num == 20100, "LuaJIT core/library version mismatch")
|
||||||
local profile = require("jit.profile")
|
local profile = require("jit.profile")
|
||||||
local vmdef = require("jit.vmdef")
|
local vmdef = require("jit.vmdef")
|
||||||
local pairs, tonumber, floor, min = pairs, tonumber, math.floor, math.min
|
local math = math
|
||||||
|
local pairs, ipairs, tonumber, floor = pairs, ipairs, tonumber, math.floor
|
||||||
local sort, format = table.sort, string.format
|
local sort, format = table.sort, string.format
|
||||||
local stdout = io.stdout
|
local stdout = io.stdout
|
||||||
local zone -- Load jit.zone module on demand.
|
local zone -- Load jit.zone module on demand.
|
||||||
@ -54,7 +57,7 @@ local out
|
|||||||
|
|
||||||
local prof_ud
|
local prof_ud
|
||||||
local prof_states, prof_split, prof_min, prof_raw, prof_fmt, prof_depth
|
local prof_states, prof_split, prof_min, prof_raw, prof_fmt, prof_depth
|
||||||
local prof_count1, prof_count2, prof_samples
|
local prof_ann, prof_count1, prof_count2, prof_samples
|
||||||
|
|
||||||
local map_vmmode = {
|
local map_vmmode = {
|
||||||
N = "Compiled",
|
N = "Compiled",
|
||||||
@ -120,15 +123,14 @@ local function prof_top(count1, count2, samples, indent)
|
|||||||
t[n] = k
|
t[n] = k
|
||||||
end
|
end
|
||||||
sort(t, function(a, b) return count1[a] > count1[b] end)
|
sort(t, function(a, b) return count1[a] > count1[b] end)
|
||||||
local raw = prof_raw
|
|
||||||
for i=1,n do
|
for i=1,n do
|
||||||
local k = t[i]
|
local k = t[i]
|
||||||
local v = count1[k]
|
local v = count1[k]
|
||||||
local pct = floor(v*100/samples + 0.5)
|
local pct = floor(v*100/samples + 0.5)
|
||||||
if pct < prof_min then break end
|
if pct < prof_min then break end
|
||||||
if not raw then
|
if not prof_raw then
|
||||||
out:write(format("%s%2d%% %s\n", indent, pct, k))
|
out:write(format("%s%2d%% %s\n", indent, pct, k))
|
||||||
elseif raw == "r" then
|
elseif prof_raw == "r" then
|
||||||
out:write(format("%s%5d %s\n", indent, v, k))
|
out:write(format("%s%5d %s\n", indent, v, k))
|
||||||
else
|
else
|
||||||
out:write(format("%s %d\n", k, v))
|
out:write(format("%s %d\n", k, v))
|
||||||
@ -142,6 +144,75 @@ local function prof_top(count1, count2, samples, indent)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Annotate source code
|
||||||
|
local function prof_annotate(count1, samples)
|
||||||
|
local files = {}
|
||||||
|
local ms = 0
|
||||||
|
for k, v in pairs(count1) do
|
||||||
|
local pct = floor(v*100/samples + 0.5)
|
||||||
|
ms = math.max(ms, v)
|
||||||
|
if pct >= prof_min then
|
||||||
|
local file, line = k:match("^(.*):(%d+)$")
|
||||||
|
local fl = files[file]
|
||||||
|
if not fl then fl = {}; files[file] = fl; files[#files+1] = file end
|
||||||
|
line = tonumber(line)
|
||||||
|
fl[line] = prof_raw and v or pct
|
||||||
|
end
|
||||||
|
end
|
||||||
|
sort(files)
|
||||||
|
local fmtv, fmtn = " %3d%% | %s\n", " | %s\n"
|
||||||
|
if prof_raw then
|
||||||
|
local n = math.max(5, math.ceil(math.log10(ms)))
|
||||||
|
fmtv = "%"..n.."d | %s\n"
|
||||||
|
fmtn = (" "):rep(n).." | %s\n"
|
||||||
|
end
|
||||||
|
local ann = prof_ann
|
||||||
|
for _, file in ipairs(files) do
|
||||||
|
local f0 = file:byte()
|
||||||
|
if f0 == 40 or f0 == 91 then
|
||||||
|
out:write(format("\n====== %s ======\n[Cannot annotate non-file]\n", file))
|
||||||
|
break
|
||||||
|
end
|
||||||
|
local fp, err = io.open(file)
|
||||||
|
if not fp then
|
||||||
|
out:write(format("====== ERROR: %s: %s\n", file, err))
|
||||||
|
break
|
||||||
|
end
|
||||||
|
out:write(format("\n====== %s ======\n", file))
|
||||||
|
local fl = files[file]
|
||||||
|
local n, show = 1, false
|
||||||
|
if ann ~= 0 then
|
||||||
|
for i=1,ann do
|
||||||
|
if fl[i] then show = true; out:write("@@ 1 @@\n"); break end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for line in fp:lines() do
|
||||||
|
if line:byte() == 27 then
|
||||||
|
out:write("[Cannot annotate bytecode file]\n")
|
||||||
|
break
|
||||||
|
end
|
||||||
|
local v = fl[n]
|
||||||
|
if ann ~= 0 then
|
||||||
|
if show then
|
||||||
|
if v then show = n elseif show+ann < n then show = false end
|
||||||
|
elseif fl[n+ann] then
|
||||||
|
show = n+ann
|
||||||
|
out:write(format("@@ %d @@\n", n))
|
||||||
|
end
|
||||||
|
if not show then goto next end
|
||||||
|
end
|
||||||
|
if v then
|
||||||
|
out:write(format(fmtv, v, line))
|
||||||
|
else
|
||||||
|
out:write(format(fmtn, line))
|
||||||
|
end
|
||||||
|
::next::
|
||||||
|
n = n + 1
|
||||||
|
end
|
||||||
|
fp:close()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
-- Finish profiling and dump result.
|
-- Finish profiling and dump result.
|
||||||
@ -153,7 +224,11 @@ local function prof_finish()
|
|||||||
if prof_raw ~= true then out:write("[no samples collected]\n") end
|
if prof_raw ~= true then out:write("[no samples collected]\n") end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
if prof_ann then
|
||||||
|
prof_annotate(prof_count1, samples)
|
||||||
|
else
|
||||||
prof_top(prof_count1, prof_count2, samples, "")
|
prof_top(prof_count1, prof_count2, samples, "")
|
||||||
|
end
|
||||||
prof_count1 = nil
|
prof_count1 = nil
|
||||||
prof_count2 = nil
|
prof_count2 = nil
|
||||||
prof_ud = nil
|
prof_ud = nil
|
||||||
@ -182,7 +257,13 @@ local function prof_start(mode)
|
|||||||
else
|
else
|
||||||
prof_split = (scope == "" or mode:find("[zv].*[lfF]")) and 1 or 0
|
prof_split = (scope == "" or mode:find("[zv].*[lfF]")) and 1 or 0
|
||||||
end
|
end
|
||||||
if m.G and scope ~= "" then
|
prof_ann = m.A and 0 or (m.a and 3)
|
||||||
|
if prof_ann then
|
||||||
|
scope = "l"
|
||||||
|
prof_fmt = "pl"
|
||||||
|
prof_split = 0
|
||||||
|
prof_depth = 1
|
||||||
|
elseif m.G and scope ~= "" then
|
||||||
prof_fmt = flags..scope.."Z;"
|
prof_fmt = flags..scope.."Z;"
|
||||||
prof_depth = -100
|
prof_depth = -100
|
||||||
prof_raw = true
|
prof_raw = true
|
||||||
|
Loading…
Reference in New Issue
Block a user