282 lines
7.4 KiB
Lua
282 lines
7.4 KiB
Lua
--------------------------------------------------------------------------------
|
|
-- Copyright (c) 2015 - 2018 , 蒙占志(topameng) topameng@gmail.com
|
|
-- All rights reserved.
|
|
-- Use, modification and distribution are subject to the "MIT License"
|
|
--------------------------------------------------------------------------------
|
|
local LuaProfiler = LuaProfiler
|
|
local vmdef = jit and require("jit.vmdef")
|
|
|
|
--通过文件名和行数指定一个函数名字
|
|
local ffnames =
|
|
{
|
|
event =
|
|
{
|
|
[20] = "_xpcall.__call",
|
|
[142] = "event.__call",
|
|
},
|
|
|
|
slot =
|
|
{
|
|
[11] = "slot.__call",
|
|
},
|
|
|
|
MainScene =
|
|
{
|
|
[250] = "MainScene.Update"
|
|
}
|
|
}
|
|
|
|
--不需要Profiler的函数
|
|
local blacklist =
|
|
{
|
|
["ipairs_aux"] = 1,
|
|
["_xpcall.__call"] = 1,
|
|
["unknow"] = 1,
|
|
}
|
|
|
|
local profiler =
|
|
{
|
|
mark = 1,
|
|
cache = 1,
|
|
}
|
|
|
|
local stacktrace = {}
|
|
|
|
function profiler:scan(t, name)
|
|
if self.mark[t] then
|
|
return
|
|
end
|
|
|
|
self.mark[t] = true
|
|
|
|
for k, v in pairs(t) do
|
|
if type(k) == "string" then
|
|
if type(v) == "function" then
|
|
local str = k
|
|
|
|
if name then
|
|
str = name ..".".. str
|
|
end
|
|
|
|
if not blacklist[str] and k ~= "__index" and k ~= "__newindex" then
|
|
self.cache[v] = {name = str, id = -1}
|
|
end
|
|
elseif type(v) == "table" and not self.mark[v] then
|
|
self:scan(v, k)
|
|
end
|
|
elseif name and k == tolua.gettag or k == tolua.settag then
|
|
self:scan(v, name)
|
|
end
|
|
end
|
|
end
|
|
|
|
function profiler:scanlibs()
|
|
local t = package.loaded
|
|
self.mark[t] = true
|
|
|
|
for k, v in pairs(t) do
|
|
if type(k) == "string" and type(v) == "table" then
|
|
self:scan(v, k)
|
|
local mt = getmetatable(v)
|
|
|
|
if mt then
|
|
self:scan(mt, k)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function findstack(func)
|
|
local pos = #stacktrace + 1
|
|
|
|
for i, v in ipairs(stacktrace) do
|
|
if v == func then
|
|
pos = i
|
|
end
|
|
end
|
|
|
|
return pos
|
|
end
|
|
|
|
local function jitreturn(count)
|
|
local top = #stacktrace
|
|
|
|
if top > 0 then
|
|
local ar = debug.getinfo (5, "f")
|
|
|
|
if ar then
|
|
local func = ar.func
|
|
local index = findstack(func)
|
|
|
|
if index > top then
|
|
ar = debug.getinfo(6, "f")
|
|
|
|
if ar then
|
|
func = ar.func
|
|
index = findstack(func) or index
|
|
end
|
|
end
|
|
|
|
for i = index + 1, top do
|
|
table.remove(stacktrace)
|
|
LuaProfiler.EndSample()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function BeginSample(name, func, cache)
|
|
jitreturn()
|
|
table.insert(stacktrace, func)
|
|
|
|
if cache.id == -1 then
|
|
cache.name = name
|
|
cache.id = LuaProfiler.GetID(name)
|
|
end
|
|
|
|
LuaProfiler.BeginSample(cache.id)
|
|
end
|
|
|
|
local function BeginSampleNick(name, func, cache)
|
|
jitreturn()
|
|
table.insert(stacktrace, func)
|
|
local id = -1
|
|
|
|
if cache.nick == nil then
|
|
cache.nick = {}
|
|
end
|
|
|
|
id = cache.nick[name]
|
|
|
|
if not id then
|
|
id = LuaProfiler.GetID(name)
|
|
cache.nick[name] = id
|
|
end
|
|
|
|
LuaProfiler.BeginSample(id)
|
|
end
|
|
|
|
function profiler_hook(event, line)
|
|
if event == 'call' then
|
|
local name = nil
|
|
local func = debug.getinfo (2, 'f').func
|
|
local cache = profiler.cache[func]
|
|
|
|
if cache then
|
|
name = cache.name
|
|
end
|
|
|
|
if blacklist[name] then
|
|
return
|
|
end
|
|
|
|
if name == "event.__call" then
|
|
local ar = debug.getinfo (2, 'n')
|
|
BeginSampleNick(ar.name or name, func, cache)
|
|
elseif name then
|
|
BeginSample(name, func, cache)
|
|
else
|
|
local ar = debug.getinfo (2, 'Sn')
|
|
local method = ar.name
|
|
local linedefined = ar.linedefined
|
|
|
|
if not cache then
|
|
cache = {name = "unknow", id = -1}
|
|
profiler.cache[func] = cache
|
|
end
|
|
|
|
if ar.short_src == "[C]" then
|
|
if method == "__index" or method == "__newindex" then
|
|
return
|
|
end
|
|
|
|
local name = tostring(func)
|
|
local index = name:match("function: builtin#(%d+)")
|
|
|
|
if not index then
|
|
if method then
|
|
name = method
|
|
BeginSample(method, func, cache)
|
|
elseif linedefined ~= -1 then
|
|
name = ar.short_src .. linedefined
|
|
BeginSample(name, func, cache)
|
|
end
|
|
else
|
|
name = vmdef.ffnames[tonumber(index)]
|
|
|
|
if not blacklist[name] then
|
|
BeginSample(name, func, cache)
|
|
end
|
|
end
|
|
elseif linedefined ~= -1 or method then
|
|
local short_src = ar.short_src
|
|
method = method or linedefined
|
|
|
|
local name = nil
|
|
name = short_src:match('([^/\\]+)%.%w+$')
|
|
name = name or short_src:match('([^/\\]+)$')
|
|
|
|
local ffname = ffnames[name]
|
|
|
|
if ffname then
|
|
name = ffname[linedefined]
|
|
else
|
|
name = name .. "." .. method
|
|
end
|
|
|
|
if not name then
|
|
name = short_src .. "." .. method
|
|
end
|
|
|
|
BeginSample(name, func, cache)
|
|
else
|
|
BeginSample(name, func, cache)
|
|
end
|
|
end
|
|
elseif event == "return" then
|
|
local top = #stacktrace
|
|
|
|
if top == 0 then
|
|
return
|
|
end
|
|
|
|
local ar = debug.getinfo (2, 'f')
|
|
|
|
if ar.func == stacktrace[top] then
|
|
table.remove(stacktrace)
|
|
LuaProfiler.EndSample()
|
|
else
|
|
local index = findstack(ar.func)
|
|
if index > top then return end
|
|
|
|
for i = index, top do
|
|
table.remove(stacktrace)
|
|
LuaProfiler.EndSample()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function profiler:start()
|
|
self.mark = {}
|
|
self.cache = {__mode = "k"}
|
|
|
|
self:scan(_G, nil)
|
|
self:scanlibs()
|
|
self.mark = nil
|
|
|
|
debug.sethook(profiler_hook, 'cr', 0)
|
|
end
|
|
|
|
function profiler:print()
|
|
for k, v in pairs(self.cache) do
|
|
print(v.name)
|
|
end
|
|
end
|
|
|
|
function profiler:stop()
|
|
debug.sethook(nil)
|
|
self.cache = nil
|
|
end
|
|
|
|
return profiler |