From 33c03c667a4e816b80a5ef687f619704106c566b Mon Sep 17 00:00:00 2001 From: John Drouhard Date: Thu, 23 Jan 2025 12:55:56 -0600 Subject: [PATCH] feat(stat): use cputime for all timing related functions --- lua/lazy/core/util.lua | 48 +++++++++++++++++++++++++++++++++++ lua/lazy/stats.lua | 54 +++------------------------------------- lua/lazy/view/render.lua | 6 ++--- 3 files changed, 55 insertions(+), 53 deletions(-) diff --git a/lua/lazy/core/util.lua b/lua/lazy/core/util.lua index 9db7f14..cbc2687 100644 --- a/lua/lazy/core/util.lua +++ b/lua/lazy/core/util.lua @@ -1,3 +1,5 @@ +local ffi = require("ffi") + ---@class LazyUtilCore local M = {} @@ -7,6 +9,52 @@ local M = {} M._profiles = { { name = "lazy" } } M.is_win = jit.os:find("Windows") +-- when true, startuptime is the accurate cputime for the Neovim process. (Linux & macOS) +-- this is more accurate than `nvim --startuptime`, and as such will be slightly higher +-- when false, startuptime is calculated based on a delta with a timestamp when lazy started. +M.real_cputime = false + +---@type ffi.namespace* +M.C = nil + +function M.cputime() + if M.C == nil then + pcall(function() + ffi.cdef([[ + typedef long time_t; + typedef int clockid_t; + typedef struct timespec { + time_t tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ + } nanotime; + int clock_gettime(clockid_t clk_id, struct timespec *tp); + ]]) + M.C = ffi.C + end) + end + + local function real() + local pnano = assert(ffi.new("nanotime[?]", 1)) + local CLOCK_PROCESS_CPUTIME_ID = jit.os == "OSX" and 12 or 2 + ffi.C.clock_gettime(CLOCK_PROCESS_CPUTIME_ID, pnano) + return tonumber(pnano[0].tv_sec) * 1e9 + tonumber(pnano[0].tv_nsec) + end + + local function fallback() + return (vim.uv.hrtime() - require("lazy")._start) + end + + local ok, ret = pcall(real) + if ok then + M.cputime = real + M.real_cputime = true + return ret + else + M.cputime = fallback + return fallback() + end +end + ---@param data (string|{[string]:string})? ---@param time number? function M.track(data, time) diff --git a/lua/lazy/stats.lua b/lua/lazy/stats.lua index 015a2be..115fbb5 100644 --- a/lua/lazy/stats.lua +++ b/lua/lazy/stats.lua @@ -1,74 +1,28 @@ -local ffi = require("ffi") - local M = {} ---@class LazyStats M._stats = { -- startuptime in milliseconds till UIEnter startuptime = 0, - -- when true, startuptime is the accurate cputime for the Neovim process. (Linux & macOS) - -- this is more accurate than `nvim --startuptime`, and as such will be slightly higher - -- when false, startuptime is calculated based on a delta with a timestamp when lazy started. - real_cputime = false, count = 0, -- total number of plugins loaded = 0, -- number of loaded plugins ---@type table times = {}, } ----@type ffi.namespace* -M.C = nil - function M.on_ui_enter() - M._stats.startuptime = M.track("UIEnter") - require("lazy.core.util").track({ start = "startuptime" }, M._stats.startuptime * 1e6) + local startuptime = M.track("UIEnter") + M._stats.startuptime = startuptime / 1e6 + require("lazy.core.util").track({ start = "startuptime" }, startuptime) vim.api.nvim_exec_autocmds("User", { pattern = "LazyVimStarted", modeline = false }) end function M.track(event) - local time = M.cputime() + local time = require("lazy.core.util").cputime() M._stats.times[event] = time return time end -function M.cputime() - if M.C == nil then - pcall(function() - ffi.cdef([[ - typedef long time_t; - typedef int clockid_t; - typedef struct timespec { - time_t tv_sec; /* seconds */ - long tv_nsec; /* nanoseconds */ - } nanotime; - int clock_gettime(clockid_t clk_id, struct timespec *tp); - ]]) - M.C = ffi.C - end) - end - - local function real() - local pnano = assert(ffi.new("nanotime[?]", 1)) - local CLOCK_PROCESS_CPUTIME_ID = jit.os == "OSX" and 12 or 2 - ffi.C.clock_gettime(CLOCK_PROCESS_CPUTIME_ID, pnano) - return tonumber(pnano[0].tv_sec) * 1e3 + tonumber(pnano[0].tv_nsec) / 1e6 - end - - local function fallback() - return (vim.uv.hrtime() - require("lazy")._start) / 1e6 - end - - local ok, ret = pcall(real) - if ok then - M.cputime = real - M._stats.real_cputime = true - return ret - else - M.cputime = fallback - return fallback() - end -end - function M.stats() M._stats.count = 0 M._stats.loaded = 0 diff --git a/lua/lazy/view/render.lua b/lua/lazy/view/render.lua index 8c49a1b..372c760 100644 --- a/lua/lazy/view/render.lua +++ b/lua/lazy/view/render.lua @@ -651,7 +651,7 @@ function M:profile() local stats = require("lazy.stats").stats() local ms = (math.floor(stats.startuptime * 100 + 0.5) / 100) self:append("Startuptime: ", "LazyH2"):append(ms .. "ms", "Number"):nl():nl() - if stats.real_cputime then + if Util.real_cputime then self:append("Based on the actual CPU time of the Neovim process till "):append("UIEnter", "LazySpecial") self:append("."):nl() self:append("This is more accurate than ") @@ -668,14 +668,14 @@ function M:profile() local times = {} for event, time in pairs(require("lazy.stats").stats().times) do - times[#times + 1] = { event, self:ms(time * 1e6), "Bold", time = time } + times[#times + 1] = { event, self:ms(time), "Bold", time = time } end table.sort(times, function(a, b) return a.time < b.time end) for p, prop in ipairs(times) do if p > 1 then - prop[2] = prop[2] .. " (+" .. self:ms((prop.time - times[p - 1].time) * 1e6) .. ")" + prop[2] = prop[2] .. " (+" .. self:ms(prop.time - times[p - 1].time) .. ")" end end self:props(times, { indent = 2 })