refactor: prepping for vim.loader

This commit is contained in:
Folke Lemaitre 2023-03-20 16:42:11 +01:00
parent 887eb75591
commit 690f9e88e2
No known key found for this signature in database
GPG Key ID: 41F8B1FBACAE2040
2 changed files with 62 additions and 57 deletions

View File

@ -26,32 +26,34 @@ local M = {}
---@field modname string Name of the module
---@field stat? uv_fs_t File stat of the module path
M.VERSION = 3
---@alias LoaderStats table<string, {total:number, time:number, [string]:number?}?>
M.path = vim.fn.stdpath("cache") .. "/luac"
M.enabled = false
---@type table<string, {total:number, time:number, [string]:number?}?>
M.stats = {
find = { total = 0, time = 0, not_found = 0 },
}
---@class Loader
---@field _rtp string[]
---@field _rtp_pure string[]
---@field _rtp_key string
local Loader = {
VERSION = 3,
---@type table<string, table<string,ModuleInfo>>
_indexed = {},
---@type table<string, string[]>
_topmods = {},
_loadfile = loadfile,
---@type LoaderStats
_stats = {
find = { total = 0, time = 0, not_found = 0 },
},
}
--- Tracks the time spent in a function
---@private
function M._track(stat, start)
M.stats[stat] = M.stats[stat] or { total = 0, time = 0 }
M.stats[stat].total = M.stats[stat].total + 1
M.stats[stat].time = M.stats[stat].time + uv.hrtime() - start
function Loader.track(stat, start)
Loader._stats[stat] = Loader._stats[stat] or { total = 0, time = 0 }
Loader._stats[stat].total = Loader._stats[stat].total + 1
Loader._stats[stat].time = Loader._stats[stat].time + uv.hrtime() - start
end
--- slightly faster/different version than vim.fs.normalize
@ -77,7 +79,7 @@ end
function Loader.get_rtp()
local start = uv.hrtime()
if vim.in_fast_event() then
M._track("get_rtp", start)
Loader.track("get_rtp", start)
return (Loader._rtp or {}), false
end
local updated = false
@ -94,7 +96,7 @@ function Loader.get_rtp()
updated = true
Loader._rtp_key = key
end
M._track("get_rtp", start)
Loader.track("get_rtp", start)
return Loader._rtp, updated
end
@ -115,7 +117,7 @@ function Loader.write(name, entry)
local cname = Loader.cache_file(name)
local f = assert(uv.fs_open(cname, "w", 438))
local header = {
M.VERSION,
Loader.VERSION,
entry.hash.size,
entry.hash.mtime.sec,
entry.hash.mtime.nsec,
@ -142,16 +144,16 @@ function Loader.read(name)
---@type integer[]|{[0]:integer}
local header = vim.split(data:sub(1, zero - 1), ",")
if tonumber(header[1]) ~= M.VERSION then
if tonumber(header[1]) ~= Loader.VERSION then
return
end
M._track("read", start)
Loader.track("read", start)
return {
hash = { size = tonumber(header[2]), mtime = { sec = tonumber(header[3]), nsec = tonumber(header[4]) } },
chunk = data:sub(zero + 1),
}
end
M._track("read", start)
Loader.track("read", start)
end
--- The `package.loaders` loader for lua files using the cache.
@ -163,10 +165,10 @@ function Loader.loader(modname)
local ret = M.find(modname)[1]
if ret then
local chunk, err = Loader.load(ret.modpath, { hash = ret.stat })
M._track("loader", start)
Loader.track("loader", start)
return chunk or error(err)
end
M._track("loader", start)
Loader.track("loader", start)
return "\ncache_loader: module " .. modname .. " not found"
end
@ -189,10 +191,10 @@ function Loader.loader_lib(modname)
local dash = modname:find("-", 1, true)
local funcname = dash and modname:sub(dash + 1) or modname
local chunk, err = package.loadlib(ret.modpath, "luaopen_" .. funcname:gsub("%.", "_"))
M._track("loader_lib", start)
Loader.track("loader_lib", start)
return chunk or error(err)
end
M._track("loader_lib", start)
Loader.track("loader_lib", start)
return "\ncache_loader_lib: module " .. modname .. " not found"
end
@ -209,7 +211,7 @@ function Loader.loadfile(filename, mode, env, hash)
filename = Loader.normalize(filename)
mode = nil -- ignore mode, since we byte-compile the lua source files
local chunk, err = Loader.load(filename, { mode = mode, env = env, hash = hash })
M._track("loadfile", start)
Loader.track("loadfile", start)
return chunk, err
end
@ -244,7 +246,7 @@ function Loader.load(modpath, opts)
if not hash then
-- trigger correct error
chunk, err = Loader._loadfile(modpath, opts.mode, opts.env)
M._track("load", start)
Loader.track("load", start)
return chunk, err
end
@ -254,7 +256,7 @@ function Loader.load(modpath, opts)
-- selene: allow(incorrect_standard_library_use)
chunk, err = load(entry.chunk --[[@as string]], "@" .. modpath, opts.mode, opts.env)
if not (err and err:find("cannot load incompatible bytecode", 1, true)) then
M._track("load", start)
Loader.track("load", start)
return chunk, err
end
end
@ -265,7 +267,7 @@ function Loader.load(modpath, opts)
entry.chunk = string.dump(chunk)
Loader.write(modpath, entry)
end
M._track("load", start)
Loader.track("load", start)
return chunk, err
end
@ -332,7 +334,7 @@ function M.find(modname, opts)
elseif Loader.lsmod(path)[topmod] then
for _, pattern in ipairs(patterns) do
local modpath = path .. pattern
M.stats.find.stat = (M.stats.find.stat or 0) + 1
Loader._stats.find.stat = (Loader._stats.find.stat or 0) + 1
local hash = uv.fs_stat(modpath)
if hash then
results[#results + 1] = { modpath = modpath, stat = hash, modname = modname }
@ -361,10 +363,10 @@ function M.find(modname, opts)
_find(opts.paths)
end
M._track("find", start)
Loader.track("find", start)
if #results == 0 then
-- module not found
M.stats.find.not_found = M.stats.find.not_found + 1
Loader._stats.find.not_found = Loader._stats.find.not_found + 1
end
return results
@ -474,48 +476,51 @@ function Loader.lsmod(path)
end
end
end
M._track("lsmod", start)
Loader.track("lsmod", start)
end
return Loader._indexed[path]
end
--- Debug function that wrapps all loaders and tracks stats
---@private
function M.profile_loaders()
function M._profile_loaders()
for l, loader in pairs(package.loaders) do
local loc = debug.getinfo(loader, "Sn").source:sub(2)
package.loaders[l] = function(modname)
local start = vim.loop.hrtime()
local ret = loader(modname)
M._track("loader " .. l .. ": " .. loc, start)
M._track("loader_all", start)
Loader.track("loader " .. l .. ": " .. loc, start)
Loader.track("loader_all", start)
return ret
end
end
end
--- Prints all cache stats
---@param opts? {print?:boolean}
---@return LoaderStats
---@private
function M.inspect()
function M._inspect(opts)
if opts and opts.print then
---@private
local function ms(nsec)
return math.floor(nsec / 1e6 * 1000 + 0.5) / 1000 .. "ms"
end
local chunks = {} ---@type string[][]
---@type string[]
local stats = vim.tbl_keys(M.stats)
local stats = vim.tbl_keys(Loader._stats)
table.sort(stats)
for _, stat in ipairs(stats) do
vim.list_extend(chunks, {
{ "\n" .. stat .. "\n", "Title" },
{ "* total: " },
{ tostring(M.stats[stat].total) .. "\n", "Number" },
{ tostring(Loader._stats[stat].total) .. "\n", "Number" },
{ "* time: " },
{ ms(M.stats[stat].time) .. "\n", "Bold" },
{ ms(Loader._stats[stat].time) .. "\n", "Bold" },
{ "* avg time: " },
{ ms(M.stats[stat].time / M.stats[stat].total) .. "\n", "Bold" },
{ ms(Loader._stats[stat].time / Loader._stats[stat].total) .. "\n", "Bold" },
})
for k, v in pairs(M.stats[stat]) do
for k, v in pairs(Loader._stats[stat]) do
if not vim.tbl_contains({ "time", "total" }, k) then
chunks[#chunks + 1] = { "* " .. k .. ":" .. string.rep(" ", 9 - #k) }
chunks[#chunks + 1] = { tostring(v) .. "\n", "Number" }
@ -524,7 +529,7 @@ function M.inspect()
end
vim.api.nvim_echo(chunks, true, {})
end
M._Cache = Loader
return Loader._stats
end
return M

View File

@ -675,7 +675,7 @@ function M:debug()
end)
self:nl()
Util.foreach(require("lazy.core.cache").stats, function(name, stats)
Util.foreach(require("lazy.core.cache")._inspect(), function(name, stats)
self:append(name, "LazyH2"):nl()
local props = {
{ "total", stats.total or 0, "Number" },