diff --git a/libs/profile.lua b/libs/profile.lua deleted file mode 100644 index dc8bcc0..0000000 --- a/libs/profile.lua +++ /dev/null @@ -1,195 +0,0 @@ -local clock = os.clock - ---- Simple profiler written in Lua. --- @module profile --- @alias profile -local profile = {} - --- function labels -local _labeled = {} --- function definitions -local _defined = {} --- time of last call -local _tcalled = {} --- total execution time -local _telapsed = {} --- number of calls -local _ncalls = {} --- list of internal profiler functions -local _internal = {} - ---- This is an internal function. --- @tparam string event Event type --- @tparam number line Line number --- @tparam[opt] table info Debug info table -function profile.hooker(event, line, info) - info = info or debug.getinfo(2, "fnS") - local f = info.func - -- ignore the profiler itself - if _internal[f] or info.what ~= "Lua" then - return - end - -- get the function name if available - if info.name then - _labeled[f] = info.name - end - -- find the line definition - if not _defined[f] then - _defined[f] = info.short_src .. ":" .. info.linedefined - _ncalls[f] = 0 - _telapsed[f] = 0 - end - if _tcalled[f] then - local dt = clock() - _tcalled[f] - _telapsed[f] = _telapsed[f] + dt - _tcalled[f] = nil - end - if event == "tail call" then - local prev = debug.getinfo(3, "fnS") - profile.hooker("return", line, prev) - profile.hooker("call", line, info) - elseif event == "call" then - _tcalled[f] = clock() - else - _ncalls[f] = _ncalls[f] + 1 - end -end - ---- Sets a clock function to be used by the profiler. --- @tparam function func Clock function that returns a number -function profile.setclock(f) - assert(type(f) == "function", "clock must be a function") - clock = f -end - ---- Starts collecting data. -function profile.start() - if rawget(_G, "jit") then - jit.off() - jit.flush() - end - debug.sethook(profile.hooker, "cr") -end - ---- Stops collecting data. -function profile.stop() - debug.sethook() - for f in pairs(_tcalled) do - local dt = clock() - _tcalled[f] - _telapsed[f] = _telapsed[f] + dt - _tcalled[f] = nil - end - -- merge closures - local lookup = {} - for f, d in pairs(_defined) do - local id = (_labeled[f] or "?") .. d - local f2 = lookup[id] - if f2 then - _ncalls[f2] = _ncalls[f2] + (_ncalls[f] or 0) - _telapsed[f2] = _telapsed[f2] + (_telapsed[f] or 0) - _defined[f], _labeled[f] = nil, nil - _ncalls[f], _telapsed[f] = nil, nil - else - lookup[id] = f - end - end - collectgarbage("collect") -end - ---- Resets all collected data. -function profile.reset() - for f in pairs(_ncalls) do - _ncalls[f] = 0 - end - for f in pairs(_telapsed) do - _telapsed[f] = 0 - end - for f in pairs(_tcalled) do - _tcalled[f] = nil - end - collectgarbage("collect") -end - ---- This is an internal function. --- @tparam function a First function --- @tparam function b Second function --- @treturn boolean True if "a" should rank higher than "b" -function profile.comp(a, b) - local dt = _telapsed[b] - _telapsed[a] - if dt == 0 then - return _ncalls[b] < _ncalls[a] - end - return dt < 0 -end - ---- Generates a report of functions that have been called since the profile was started. --- Returns the report as a numeric table of rows containing the rank, function label, number of calls, total execution time and source code line number. --- @tparam[opt] number limit Maximum number of rows --- @treturn table Table of rows -function profile.query(limit) - local t = {} - for f, n in pairs(_ncalls) do - if n > 0 then - t[#t + 1] = f - end - end - table.sort(t, profile.comp) - if limit then - while #t > limit do - table.remove(t) - end - end - for i, f in ipairs(t) do - local dt = 0 - if _tcalled[f] then - dt = clock() - _tcalled[f] - end - t[i] = { i, _labeled[f] or "?", _ncalls[f], _telapsed[f] + dt, _defined[f] } - end - return t -end - -local cols = { 3, 29, 11, 24, 32 } - ---- Generates a text report of functions that have been called since the profile was started. --- Returns the report as a string that can be printed to the console. --- @tparam[opt] number limit Maximum number of rows --- @treturn string Text-based profiling report -function profile.report(n) - local out = {} - local report = profile.query(n) - for i, row in ipairs(report) do - for j = 1, 5 do - local s = row[j] - local l2 = cols[j] - s = tostring(s) - local l1 = s:len() - if l1 < l2 then - s = s .. (" "):rep(l2 - l1) - elseif l1 > l2 then - s = s:sub(l1 - l2 + 1, l1) - end - row[j] = s - end - out[i] = table.concat(row, " | ") - end - - local row = - " +-----+-------------------------------+-------------+--------------------------+----------------------------------+ \n" - local col = - " | # | Function | Calls | Time | Code | \n" - local sz = row .. col .. row - if #out > 0 then - sz = sz .. " | " .. table.concat(out, " | \n | ") .. " | \n" - end - return "\n" .. sz .. row -end - --- store all internal profiler functions -for _, v in pairs(profile) do - if type(v) == "function" then - _internal[v] = true - end -end - -return profile