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

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