You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
180 lines
4.7 KiB
Lua
180 lines
4.7 KiB
Lua
local ss = require "snapshot"
|
|
local snapshot = ss.snapshot
|
|
local str2ud = ss.str2ud
|
|
|
|
local Root = str2ud("0")
|
|
local M = {}
|
|
|
|
local t2simple = {
|
|
table = "(T)",
|
|
userdata = "(U)",
|
|
-- ["function"] = "(L)",
|
|
thread = "(S)",
|
|
cfunction = "(C)",
|
|
string = "(A)",
|
|
}
|
|
|
|
local begin_s = nil
|
|
function M.start_snapshot()
|
|
begin_s = snapshot()
|
|
end
|
|
|
|
local function reshape_snapshot(s, full_snapshot)
|
|
local reshape = {}
|
|
local function add_reshape(k, v, is_new)
|
|
local t, pk, field = string.match(v, "^([^\n]+)\n%(?([%a%d]+)%)? : ([^\n]+)")
|
|
pk = pk == "nil" and "0" or pk
|
|
pk = str2ud(pk)
|
|
local tt, size = string.match(t, "([^%s]*).* {(%d+)}")
|
|
if not tt then
|
|
error(string.format("invalid snapshot value:%s", v))
|
|
end
|
|
t = tt
|
|
size = size and tonumber(size) or 0
|
|
local st = t2simple[t] or string.format("(L@%s)", t)
|
|
reshape[k] = {
|
|
t = t,
|
|
size = size,
|
|
st = st,
|
|
parent_key = pk,
|
|
field = field,
|
|
item = st .. field,
|
|
fullpath = nil,
|
|
is_new = is_new,
|
|
}
|
|
if not s[pk] and not reshape[pk] then
|
|
local pv = full_snapshot[pk]
|
|
if pv then
|
|
add_reshape(pk, pv, false)
|
|
end
|
|
end
|
|
end
|
|
|
|
for k, v in pairs(s) do
|
|
add_reshape(k, v, true)
|
|
end
|
|
|
|
local function gen_fullname()
|
|
for _, entry in pairs(reshape) do
|
|
if not entry.fullpath then
|
|
local list = {{
|
|
entry = entry,
|
|
item = entry.item,
|
|
}}
|
|
local map = {}
|
|
while true do
|
|
local pk = entry.parent_key
|
|
local pentry = reshape[pk]
|
|
if not pentry then
|
|
list[#list + 1] = pk == Root and "Root" or string.format("{%s}", pk)
|
|
break
|
|
elseif pentry.fullpath then
|
|
list[#list + 1] = pentry.fullpath
|
|
break
|
|
else
|
|
if map[pk] then
|
|
pentry.fullpath = pentry.item
|
|
list[#list + 1] = pentry.item
|
|
break
|
|
else
|
|
list[#list + 1] = {
|
|
entry = pentry,
|
|
item = pentry.item,
|
|
}
|
|
map[pk] = true
|
|
end
|
|
end
|
|
entry = pentry
|
|
end
|
|
|
|
local nlist = {}
|
|
local len = #list
|
|
for i = len, 1, -1 do
|
|
nlist[#nlist + 1] = list[i]
|
|
end
|
|
|
|
local spath = {}
|
|
for _, v in ipairs(nlist) do
|
|
if type(v) == "string" then
|
|
spath[#spath + 1] = v
|
|
else
|
|
spath[#spath + 1] = v.item
|
|
local fullpath = table.concat(spath, "->")
|
|
v.entry.fullpath = fullpath
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
gen_fullname()
|
|
|
|
local ret = {}
|
|
for _, v in pairs(reshape) do
|
|
if v.is_new then
|
|
ret[#ret + 1] = {
|
|
type = v.t,
|
|
path = v.fullpath,
|
|
v = v.v,
|
|
st = v.st,
|
|
size = v.size,
|
|
}
|
|
end
|
|
end
|
|
return ret
|
|
end
|
|
|
|
local function diff_snapshot(be_s, end_s)
|
|
local reshape
|
|
if not end_s then
|
|
reshape = reshape_snapshot(be_s, be_s)
|
|
else
|
|
local diff_s = {}
|
|
for k, v in pairs(end_s) do
|
|
if be_s[k] == nil then
|
|
diff_s[k] = v
|
|
end
|
|
end
|
|
reshape = reshape_snapshot(diff_s, end_s)
|
|
end
|
|
table.sort(reshape, function(a, b)
|
|
return a.size > b.size
|
|
end)
|
|
return reshape
|
|
end
|
|
|
|
local function dump_reshape(reshape, len)
|
|
local rlen = #reshape
|
|
len = len or rlen
|
|
if len < 0 or len > rlen then
|
|
len = rlen
|
|
end
|
|
|
|
local all_size = 0
|
|
local diff_data = {}
|
|
|
|
for i = 1, rlen do
|
|
local v = reshape[i]
|
|
all_size = all_size + v.size
|
|
if i <= len then
|
|
table.insert(diff_data, {
|
|
rank = i,
|
|
st = v.st,
|
|
path = v.path,
|
|
size = v.size / 1024,
|
|
})
|
|
end
|
|
end
|
|
return rlen, diff_data
|
|
end
|
|
|
|
function M.dstop_snapshot(len)
|
|
if not begin_s then
|
|
error("snapshot not begin")
|
|
end
|
|
local end_s = snapshot()
|
|
local reshape = diff_snapshot(end_s)
|
|
return dump_reshape(reshape, len)
|
|
end
|
|
|
|
return M
|