-
Notifications
You must be signed in to change notification settings - Fork 1
/
reqprof.lua
141 lines (117 loc) · 3 KB
/
reqprof.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
local class = require("class")
local deco = require("deco")
local reqprof = {}
reqprof.max_level = 10
reqprof.stats = {}
local enabled, target_enabled = false, false
function reqprof.enable()
target_enabled = true
end
function reqprof.disable()
target_enabled = false
end
local want_print
local getTime = love.timer.getTime
local level
local prev_time
local total_calls = 0
function reqprof.start()
enabled = target_enabled
if want_print then
reqprof._print()
want_print = false
end
reqprof.stats = {}
level = 0
local t = getTime()
if prev_time then
reqprof.stats.reqprof = {
name = "reqprof",
time = t - prev_time,
calls = total_calls,
nt_calls = 0,
}
end
prev_time = t
total_calls = 0
end
---@param a table
---@param b table
---@return boolean
local function sort_stats(a, b)
return a.time < b.time
end
function reqprof.print()
want_print = true
end
function reqprof._print()
if not enabled then
print("total calls: " .. total_calls)
end
local lname, lcalls, lnt_calls, ltime = #("function"), #("calls"), #("nt_calls"), #("time")
local stats_sorted = {}
for _, stat in pairs(reqprof.stats) do
table.insert(stats_sorted, stat)
lname = math.max(lname, #tostring(stat.name))
lcalls = math.max(lcalls, #tostring(stat.calls))
lnt_calls = math.max(lnt_calls, #tostring(stat.nt_calls))
ltime = math.max(ltime, #tostring(stat.time))
end
table.sort(stats_sorted, sort_stats)
io.write(("%" .. lcalls .. "s "):format("calls"))
io.write(("%" .. lnt_calls .. "s "):format("nt_calls"))
io.write("name")
io.write((" "):rep(lname - #("function") + 1))
io.write("time")
io.write("\n")
for _, stat in ipairs(stats_sorted) do
io.write(("%" .. lcalls .. "s "):format(stat.calls))
io.write(("%" .. lnt_calls .. "s "):format(stat.nt_calls))
io.write(stat.name)
io.write((" "):rep(lname - #stat.name + 1))
io.write(stat.time)
io.write("\n")
end
end
---@param f function
---@param name string
---@return function
function reqprof.decorate(f, name)
local function return_measured(t, stats, ...)
level = level - 1
stats[name].time = stats[name].time + getTime() - t
stats[name].calls = stats[name].calls + 1
return ...
end
return function(...)
total_calls = total_calls + 1
if not enabled then
return f(...)
end
local stats = reqprof.stats
stats[name] = stats[name] or {
name = name,
time = 0,
calls = 0,
nt_calls = 0,
}
if level >= reqprof.max_level then
stats[name].nt_calls = stats[name].nt_calls + 1
return f(...)
end
level = level + 1
local t = getTime()
return return_measured(t, stats, f(...))
end
end
---@class reqprof.ProfileDecorator: deco.FunctionDecorator
---@operator call: reqprof.ProfileDecorator
local ProfileDecorator = class(deco.FunctionDecorator)
reqprof.ProfileDecorator = ProfileDecorator
---@param func_name string
---@return string
function ProfileDecorator:func_end(func_name)
local func = func_name:gsub(":", ".")
return ([[? = require("reqprof").decorate(?, %q)]]):gsub("?", func):format(func_name)
end
return reqprof