我正在为基于钩子的lua代码编写小型分析库,因为我不能使用任何现有的(公司策略)。
我正在考虑通过将变量设置为true来允许始终对所有脚本进行按需分析是否有意义,例如。
function hook(event)
if prof_enabled then
do_stuff()
end
end
--(in main context)
debug.sethook(hook, "cr")
所以问题是,如果prof_enabled = false并且始终设置了钩子,我是否应该期待显着的性能损失?我不期待确切的答案,而是一些见解(也许,例如lua翻译器会优化它吗?)
我知道最好的解决方案是只在必要时设置挂钩,但我不能在这里做。
答案 0 :(得分:0)
有没有钩子功能的方法。一种方法是将“感兴趣的函数”替换为“生成”函数,该函数对事物进行概要分析(如计数调用次数),然后调用“实际”函数。像这样:
-- set up profiling
local profile = {}
-- stub function to profile an existing function
local function make_profile_func (fname, f)
profile [fname] = { func = f, count = 0 }
return function (...)
profile [fname].count = profile [fname].count + 1
local results = { f (...) } -- call original function
return unpack (results) -- return results
end -- function
end -- make_profile_func
function pairsByKeys (t, f)
local a = {}
-- build temporary table of the keys
for n in pairs (t) do
table.insert (a, n)
end
table.sort (a, f) -- sort using supplied function, if any
local i = 0 -- iterator variable
return function () -- iterator function
i = i + 1
return a[i], t[a[i]]
end -- iterator function
end -- pairsByKeys
-- show profile, called by alias
-- non-profiled functions
local npfunctions = {
string_format = string.format,
string_rep = string.rep,
string_gsub = string.gsub,
table_insert = table.insert,
table_sort = table.sort,
pairs = pairs,
}
function show_profile (name, line, wildcards)
print (npfunctions.string_rep ("-", 20), "Function profile - alpha order",
npfunctions.string_rep ("-", 20))
print ""
print (npfunctions.string_format ("%25s %8s", "Function", "Count"))
print ""
for k, v in pairsByKeys (profile) do
if v.count > 0 then
print (npfunctions.string_format ("%25s %8i", k, v.count))
end -- if
end -- for
print ""
local t = {}
for k, v in npfunctions.pairs (profile) do
if v.count > 0 then
npfunctions.table_insert (t, k)
end -- if used
end -- for
npfunctions.table_sort (t, function (a, b) return profile [a].count > profile [b].count end )
print (npfunctions.string_rep ("-", 20), "Function profile - count order",
npfunctions.string_rep ("-", 20))
print ""
print (npfunctions.string_format ("%25s %8s", "Function", "Count"))
print ""
for _, k in ipairs (t) do
print (npfunctions.string_format ("%25s %8i", k, profile [k].count))
end -- for
print ""
end -- show_profile
-- replace string functions by profiling stub function
for k, f in pairs (string) do
if type (f) == "function" then
string [k] = make_profile_func (k, f)
end -- if
end -- for
-- test
for i = 1, 10 do
string.gsub ("aaaa", "a", "b")
end -- for
for i = 1, 20 do
string.match ("foo", "f")
end -- for
-- display results
show_profile ()
在这个特定的测试中,我调用了string.gsub 10次,string.match调用了20次。现在输出是:
-------------------- Function profile - alpha order --------------------
Function Count
gsub 10
match 20
-------------------- Function profile - count order --------------------
Function Count
match 20
gsub 10
如果你有一个高精度计时器,你可以做其他的事情,比如时间函数。
我在MUSHclient forum的帖子中对此进行了调整,我也得到了精确的时间。
make_profile_func
做的是将原始函数指针的副本保存在upvalue中,并返回一个向调用计数添加一个函数,调用原始函数并返回其结果的函数。这样做的好处在于,您可以通过简单地不使用生成的对应函数替换函数来省略开销。
换句话说,省略这些行并且没有开销:
for k, f in pairs (string) do
if type (f) == "function" then
string [k] = make_profile_func (k, f)
end -- if
end -- for
在代码中有一些小问题要使用用于生成配置文件的函数的非配置文件版本(否则会产生一些误导性的读取)。