diff options
author | Hans Hagen <pragma@wxs.nl> | 2021-05-19 18:48:15 +0200 |
---|---|---|
committer | Context Git Mirror Bot <phg@phi-gamma.net> | 2021-05-19 18:48:15 +0200 |
commit | f1772caf425af2fe9be87b788eae63559682d51a (patch) | |
tree | ce9a813989227bea7191db7a8f8bc87ad6d578dd /tex/context/base/mkxl/util-deb.lmt | |
parent | 330909ad62342ff873dc758b909968c66d0252a4 (diff) | |
download | context-f1772caf425af2fe9be87b788eae63559682d51a.tar.gz |
2021-05-19 18:21:00
Diffstat (limited to 'tex/context/base/mkxl/util-deb.lmt')
-rw-r--r-- | tex/context/base/mkxl/util-deb.lmt | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/tex/context/base/mkxl/util-deb.lmt b/tex/context/base/mkxl/util-deb.lmt new file mode 100644 index 000000000..0021b93b9 --- /dev/null +++ b/tex/context/base/mkxl/util-deb.lmt @@ -0,0 +1,371 @@ +if not modules then modules = { } end modules ['util-deb'] = { + version = 1.001, + comment = "companion to luat-lib.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- the <anonymous> tag is kind of generic and used for functions that are not +-- bound to a variable, like node.new, node.copy etc (contrary to for instance +-- node.has_attribute which is bound to a has_attribute local variable in mkiv) + +local type, next, tostring, tonumber = type, next, tostring, tonumber +local format, find, sub, gsub = string.format, string.find, string.sub, string.gsub +local insert, remove, sort = table.insert, table.remove, table.sort +local setmetatableindex = table.setmetatableindex + +utilities = utilities or { } +local debugger = utilities.debugger or { } +utilities.debugger = debugger + +local report = logs.reporter("debugger") + +local ticks = os.gettimeofday or os.clock +local seconds = function(n) return n or 0 end +local overhead = 0 +local dummycalls = 10*1000 +local nesting = 0 +local names = { } + +local function initialize() + ticks = lua.getpreciseticks + seconds = lua.getpreciseseconds + initialize = false +end + +setmetatableindex(names,function(t,name) + local v = setmetatableindex(function(t,source) + local v = setmetatableindex(function(t,line) + -- local v = { total = 0, count = 0, nesting = 0, ticks = 0 } + local v = { 0, 0, 0, 0 } + t[line] = v + return v + end) + t[source] = v + return v + end) + t[name] = v + return v +end) + +local getinfo = nil +local sethook = nil + +-- local function hook(where) +-- local f = getinfo(2,"nS") +-- if f then +-- local source = f.short_src +-- if not source then +-- return +-- end +-- local line = f.linedefined or 0 +-- local name = f.name +-- if not name then +-- local what = f.what +-- if what == "C" then +-- name = "<anonymous>" +-- else +-- name = f.namewhat or what or "<unknown>" +-- end +-- end +-- local data = names[name][source][line] +-- if where == "call" then +-- local nesting = data.nesting +-- if nesting == 0 then +-- data.count = data.count + 1 +-- insert(data,ticks()) +-- data.nesting = 1 +-- else +-- data.nesting = nesting + 1 +-- end +-- elseif where == "return" then +-- local nesting = data.nesting +-- if nesting == 1 then +-- local t = remove(data) +-- if t then +-- data.total = data.total + ticks() - t +-- end +-- data.nesting = 0 +-- else +-- data.nesting = nesting - 1 +-- end +-- end +-- end +-- end + +local getdebuginfo = lua.getdebuginfo + +-- local function hook(where) -- make two hooks +-- local name, source, line = getdebuginfo() +-- if name then +-- local data = names[name][source][line] +-- if where == "call" then +-- local nesting = data.nesting +-- if nesting == 0 then +-- data.count = data.count + 1 +-- -- insert(data,ticks()) +-- data.nesting = 1 +-- data.ticks = ticks() +-- else +-- data.nesting = nesting + 1 +-- end +-- elseif where == "return" then +-- local nesting = data.nesting +-- if nesting == 1 then +-- -- local t = remove(data) +-- local t = data.ticks +-- if t then +-- data.total = data.total + ticks() - t +-- end +-- data.nesting = 0 +-- elseif nesting > 0 then +-- data.nesting = nesting - 1 +-- end +-- elseif where == "tail call" then +-- local nesting = data.nesting +-- if nesting == 1 then +-- -- local t = remove(data) +-- local t = data.ticks +-- if t then +-- data.total = data.total + ticks() - t +-- end +-- data.nesting = 0 +-- elseif nesting > 0 then +-- data.nesting = nesting - 1 +-- end +-- end +-- end +-- end + +local function hook(where) -- make two hooks + local name, source, line = getdebuginfo() + if name then + local data = names[name][source][line] + if where == "call" then + local nesting = data[3] + if nesting == 0 then + data[2] = data[2] + 1 + data[3] = 1 + data[4] = ticks() + else + data[3] = nesting + 1 + end + -- elseif where == "return" then + else + local nesting = data[3] + if nesting == 1 then + local t = data[4] + if t then + data[1] = data[1] + ticks() - t + end + data[3] = 0 + elseif nesting > 0 then + data[3] = nesting - 1 + end + -- elseif where == "tail call" then + -- local nesting = data[3] + -- if nesting == 1 then + -- local t = data[4] + -- if t then + -- data[4] = data[4] + ticks() - t + -- end + -- data[3] = 0 + -- elseif nesting > 0 then + -- data[3] = nesting - 1 + -- end + end + end +end + +function debugger.showstats(printer,threshold) + local printer = printer or report + local calls = 0 + local functions = 0 + local dataset = { } + local length = 0 + local realtime = 0 + local totaltime = 0 + local threshold = threshold or 0 + for name, sources in next, names do + for source, lines in next, sources do + for line, data in next, lines do + -- local count = data.count + local count = data[2] + if count > threshold then + if #name > length then + length = #name + end + -- local total = data.total + local total = data[1] + local real = total + if real > 0 then + real = total - (count * overhead / dummycalls) + if real < 0 then + real = 0 + end + realtime = realtime + real + end + totaltime = totaltime + total + if line < 0 then + line = 0 + end + -- if name = "a" then + -- -- weird name + -- end + dataset[#dataset+1] = { real, total, count, name, source, line } + end + end + end + end + sort(dataset,function(a,b) + if a[1] == b[1] then + if a[2] == b[2] then + if a[3] == b[3] then + if a[4] == b[4] then + if a[5] == b[5] then + return a[6] < b[6] + else + return a[5] < b[5] + end + else + return a[4] < b[4] + end + else + return b[3] < a[3] + end + else + return b[2] < a[2] + end + else + return b[1] < a[1] + end + end) + if length > 50 then + length = 50 + end + local fmt = string.formatters["%4.9k s %3.3k %% %4.9k s %3.3k %% %8i # %-" .. length .. "s %4i %s"] + for i=1,#dataset do + local data = dataset[i] + local real = data[1] + local total = data[2] + local count = data[3] + local name = data[4] + local source = data[5] + local line = data[6] + calls = calls + count + functions = functions + 1 + name = gsub(name,"%s+"," ") + if #name > length then + name = sub(name,1,length) + end + printer(fmt(seconds(total),100*total/totaltime,seconds(real),100*real/realtime,count,name,line,source)) + end + printer("") + printer(format("functions : %i", functions)) + printer(format("calls : %i", calls)) + printer(format("overhead : %f", seconds(overhead/1000))) + + -- table.save("luatex-profile.lua",names) +end + +local function getdebug() + if sethook and getinfo then + return + end + if not debug then + local okay + okay, debug = pcall(require,"debug") + end + if type(debug) ~= "table" then + return + end + getinfo = debug.getinfo + sethook = debug.sethook + if type(getinfo) ~= "function" then + getinfo = nil + end + if type(sethook) ~= "function" then + sethook = nil + end +end + +function debugger.savestats(filename,threshold) + local f = io.open(filename,'w') + if f then + debugger.showstats(function(str) f:write(str,"\n") end,threshold) + f:close() + end +end + +function debugger.enable() + getdebug() + if sethook and getinfo and nesting == 0 then + running = true + if initialize then + initialize() + end + sethook(hook,"cr") +-- sethook(hook_c,"c") +-- sethook(hook_r,"r") + local function dummy() end + local t = ticks() + for i=1,dummycalls do + dummy() + end + overhead = ticks() - t + end + if nesting > 0 then + nesting = nesting + 1 + end +end + +function debugger.disable() + if nesting > 0 then + nesting = nesting - 1 + end + if sethook and getinfo and nesting == 0 then + sethook() + end +end + +-- debugger.enable() +-- +-- print(math.sin(1*.5)) +-- print(math.sin(1*.5)) +-- print(math.sin(1*.5)) +-- print(math.sin(1*.5)) +-- print(math.sin(1*.5)) +-- +-- debugger.disable() +-- +-- print("") +-- debugger.showstats() +-- print("") +-- debugger.showstats(print,3) +-- +-- from the lua book: + +local function showtraceback(rep) -- from lua site / adapted + getdebug() + if getinfo then + local level = 2 -- we don't want this function to be reported + local reporter = rep or report + while true do + local info = getinfo(level, "Sl") + if not info then + break + elseif info.what == "C" then + reporter("%2i : %s",level-1,"C function") + else + reporter("%2i : %s : %s",level-1,info.short_src,info.currentline) + end + level = level + 1 + end + end +end + +debugger.showtraceback = showtraceback +-- debug.showtraceback = showtraceback + +-- showtraceback() |