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