-
Notifications
You must be signed in to change notification settings - Fork 1
/
mem_stats.lua
195 lines (179 loc) · 3.87 KB
/
mem_stats.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
local MAX_QUEUE = 1000000
local InfoList
local ValueInfo
local ValueCount
local getupvalue = debug.getupvalue
local getinfo = debug.getinfo
local getlocal = debug.getlocal
local pairs = pairs
local type = type
local function CheckValue(key, value, parent)
local typ = type(value)
if (typ~="table" and typ~="function" and typ~="thread") or ValueInfo[value] or ValueCount>=MAX_QUEUE then
return
end
ValueCount = ValueCount + 1
local info = {
index = ValueCount,
parent = parent,
key = key,
value = value,
}
ValueInfo[value] = info
InfoList[ValueCount] = info
end
local function CheckAll()
InfoList = {}
ValueInfo = {}
ValueCount = 0
ValueInfo[InfoList] = true
ValueInfo[ValueInfo] = true
CheckValue("_G", _G, nil)
local i = 1
while i<=ValueCount do
local info = InfoList[i]
local value = info.value
local typ = type(value)
i = i + 1
local count = 1
if typ=="table" then
for k, v in pairs(value) do
count = count + 1
CheckValue(k, k, info)
CheckValue(k, v, info)
end
elseif typ=="function" then
for j = 1, 100 do
local k, v = getupvalue(value, j)
if not k then
break
end
count = count + 1
CheckValue(k, v, info)
end
else -- thread
for n = 1, 100 do
local f = getinfo(value, n, "n")
if f then
count = count + 1
for m = 1, 100 do
local k, v = getlocal(value, n, m)
if not k then
break
end
count = count + 1
CheckValue((f.name or "function").. "():" .. k, v, info)
end
end
end
end
info.count = count
local parent = info.parent
while parent do
parent.count = parent.count + count
parent = parent.parent
end
end
end
local function ChildList(info)
local value = info.value
local typ = type(value)
local list = {}
local function append(v)
local inf = ValueInfo[v]
if inf and inf.parent==info then
table.insert(list, inf)
end
end
if typ=="table" then
for k, v in pairs(value) do
append(k)
append(v)
end
elseif typ=="function" then
for j = 1, 100 do
local k, v = getupvalue(value, j)
if not k then
break
end
append(v)
end
else -- thread
for n = 1, 100 do
local f = getinfo(value, n, "n")
if f then
for m = 1, 100 do
local k, v = getlocal(value, n, m)
if not k then
break
end
append(v)
end
end
end
end
table.sort(list, function(a, b) return a.count > b.count end)
return list
end
local MaxLevel
local MinCount
local RestCount
local TotalCount
local function PCT(c, t)
return string.format("%.1f%%", c * 100 / t)
end
local function DoShow(info, level)
for i, inf in ipairs(ChildList(info)) do
if inf.count<=MinCount then
break
end
print(inf.index, string.format("%-30s", string.rep(".", level - 1) .. inf.key),
inf.count, PCT(inf.count, info.count), PCT(inf.count, TotalCount), tostring(inf.value))
RestCount = RestCount - 1
if RestCount<=0 then
print("...")
return false
end
if level<MaxLevel then
DoShow(inf, level + 1)
if RestCount<=0 then
break
end
end
end
end
local M ={}
function M.List(index, level, percent, count)
if not TotalCount then
CheckAll()
if ValueCount>=MAX_QUEUE then
print("more then MAX_QUEUE!", MAX_QUEUE)
end
TotalCount = InfoList[1].count
end
local info = assert(InfoList[index or 1])
local path = tostring(info.key)
local parent = info.parent
while parent do
path = tostring(parent.key) .. "." .. path
parent = parent.parent
end
print("path:", path)
print("index:", info.index)
print("PCT.T:", PCT(info.count, TotalCount))
print("value:", tostring(info.value))
print()
print("index", string.format("%-30s", "key"), "count", "PCT.P", "PCT.T", "value")
MaxLevel = level or 3
MinCount = percent and (percent * TotalCount // 100) or 0
RestCount = count or 100
DoShow(info, 1)
print()
end
function M.Clear()
InfoList = nil
ValueInfo = nil
ValueCount = nil
TotalCount = nil
end
return M