You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

170 lines
4.4 KiB

--[[
Profiler functions
LuaProfiler is desync unsafe so you cannot use it in multiplayer.
Prints summary to log file and to console every 5 seconds.
Example 1:
Profiler.start('test1')
...code...
Profiler.split('test1','chunk1') -- optional
...code...
Profiler.split('test1','chunk2') -- optional
...code...
Profiler.stop('test1')
Example 2:
Profiler.start('test2', table_size(items))
for _, item in pairs(items) do
...code...
end
Profiler.stop('test2')
Example 3:
Profiler.count('counter1')
]]--
local Profiler = {
enabled = false,
print_to_console = true
}
if is_debug_mode and Profiler.enabled then
local active_profilers = {}
local active_splits = {}
local active_counters = {}
-- LuaProfiler makes the game slower as more and more profilers are created,
-- thus we create a pool of profilers to mitigate the issue
local profilers_pool = {}
local profilers_used = {}
local function get_make_profiler()
local profiler
if table_size(profilers_pool) > 0 then
profiler = table.remove(profilers_pool)
profiler.reset()
else
profiler = game.create_profiler(true)
end
table.insert(profilers_used, profiler)
return profiler
end
local function recycle_profilers()
for _, profiler in pairs(profilers_used) do
table.insert(profilers_pool, profiler)
end
profilers_used = {}
end
local function dup_profiler(profiler)
local new_profiler = get_make_profiler()
new_profiler.reset()
new_profiler.stop()
new_profiler.add(profiler)
return new_profiler
end
function Profiler.start(name, unit_count)
if not active_profilers[name] then
active_profilers[name] = {
profiler = get_make_profiler(),
tick = game.tick,
count = 0
}
end
if unit_count == nil then unit_count = 1 end
active_profilers[name].count = active_profilers[name].count + unit_count
active_profilers[name].profiler.restart()
end
function Profiler.stop(name)
if active_profilers[name] then
if active_splits[name] then
Profiler.stop(active_splits[name])
active_splits[name] = nil
end
active_profilers[name].profiler.stop()
end
end
function Profiler.split(name, part)
if active_profilers[name] then
if active_splits[name] then
Profiler.stop(active_splits[name])
active_splits[name] = nil
end
if part then
local split_name = name .. "--" .. part
Profiler.start(split_name)
active_splits[name] = split_name
end
end
end
function Profiler.count(name, value)
if not active_counters[name] then
active_counters[name] = {
counter = 0,
tick = game.tick
}
end
if value == nil then value = 1 end
active_counters[name].counter = active_counters[name].counter + value
end
function Profiler.collect_print()
local results = {}
for name, entry in pairs(active_profilers) do
entry.profiler.stop()
if entry.count == 0 then
entry.profiler.divide(game.tick - entry.tick + 1)
results[name] = { "", "PerTick ", entry.profiler }
else
local per_tick_count = entry.count / (game.tick - entry.tick + 1)
local per_unit_profiler = dup_profiler(entry.profiler)
per_unit_profiler.divide(entry.count)
entry.profiler.divide(game.tick - entry.tick + 1)
results[name] = { "", "PerUnit (", per_tick_count, "/", entry.count, ") ", per_unit_profiler,
" / PerTick ", entry.profiler }
end
end
for name, entry in pairs(active_counters) do
local value = entry.counter / (game.tick - entry.tick + 1)
local key = results[name] and (name .. "-count") or name
results[key] = { "", "Count: ", value }
end
local log_fn = Profiler.print_to_console and Log.trace or Log.debug_log
-- sort the results
local keys = {}
for k in pairs(results) do table.insert(keys, k) end
table.sort(keys)
-- print
log_fn('---')
for _, name in pairs(keys) do
log_fn({ "", name, ": ", results[name]})
end
-- cleanup
active_profilers = {}
active_splits = {}
active_counters = {}
recycle_profilers()
end
Event.addListener("on_nth_tick_301", Profiler.collect_print) -- 5 seconds
else
Profiler.start = function() end
Profiler.stop = function() end
Profiler.split = function() end
Profiler.count = function() end
Profiler.collect_print = function() end
end
return Profiler