1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-02-12 02:23:39 +08:00
SpaceVim/bundle/plenary.nvim/lua/plenary/benchmark/init.lua

127 lines
3.5 KiB
Lua
Raw Normal View History

2022-05-16 22:20:10 +08:00
local B = {}
local stat = require "plenary.benchmark.stat"
local get_stats = function(results)
local ret = {}
ret.max, ret.min = stat.maxmin(results)
ret.mean = stat.mean(results)
ret.median = stat.median(results)
ret.std = stat.std_dev(results)
return ret
end
local get_output = function(index, res, runs)
-- divine with a sutable one / 1e3, 1e6, 1e9
local time_types = { "ns", "μs", "ms" }
local get_leading = function(time)
time = math.floor(time)
local count = 0
repeat
time = math.floor(time / 10)
count = count + 1
until time <= 0
return count
end
local get_best_fmt = function(time)
for _, v in ipairs(time_types) do
if math.abs(time) < 1000.0 then
return string.format("%s%3.1f %s", string.rep(" ", 3 - get_leading(time)), time, v)
end
time = time / 1000.0
end
return string.format("%.1f %s", time, "s")
end
return string.format(
"Benchmark #%d: '%s'\n Time(mean ± σ): %s ± %s\n Range(min … max): %s … %s %d runs\n",
index,
res.name,
get_best_fmt(res.stats.mean),
get_best_fmt(res.stats.std),
get_best_fmt(res.stats.min),
get_best_fmt(res.stats.max),
runs
)
end
local get_summary = function(res)
if #res == 1 then
return ""
end
local fastest_mean = math.huge
local fastest_index = 1
for i, benchmark in ipairs(res) do
if benchmark.stats.mean < fastest_mean then
fastest_mean = benchmark.stats.mean
fastest_index = i
end
end
if fastest_mean == math.huge then
return ""
end
local output = {}
local fastest = res[fastest_index].stats
for i, benchmark in ipairs(res) do
if i ~= fastest_index then
local result = benchmark.stats
local ratio = result.mean / fastest.mean
-- // https://en.wikipedia.org/wiki/Propagation_of_uncertainty#Example_formulas
-- // Covariance asssumed to be 0, i.e. variables are assumed to be independent
local ratio_std = ratio
* math.sqrt(math.pow(result.std / result.mean, 2) + math.pow(fastest.std / fastest.mean, 2))
table.insert(output, string.format(" %.1f ± %.1f times faster than '%s'\n", ratio, ratio_std, benchmark.name))
end
end
return string.format("Summary\n '%s' ran\n%s", res[fastest_index].name, table.concat(output, ""))
end
---@class benchmark_run_opts
---@field warmup number @number of initial runs before starting to track time.
---@field runs number @number of runs to make
---@field fun table<array<string, function>> @functions to execute
---Benchmark a function
---@param name string @benchmark name
---@param opts benchmark_run_opts
local bench = function(name, opts)
vim.validate {
opts = { opts, "table" },
fun = { opts.fun, "table" },
}
opts.warmup = vim.F.if_nil(opts.warmup, 3)
opts.runs = vim.F.if_nil(opts.runs, 5)
opts.fun = type(opts.fun) == "function" and { opts.fun } or opts.fun
local output = { string.format("Benchmark Group: '%s' -----------------------\n", name) }
local res = {}
for i, fun in ipairs(opts.fun) do
res[i] = { name = fun[1], results = {} }
for _ = 1, opts.warmup do
fun[2]()
end
for j = 1, opts.runs do
local start = vim.loop.hrtime()
fun[2]()
res[i].results[j] = vim.loop.hrtime() - start
end
res[i].stats = get_stats(res[i].results)
table.insert(output, get_output(i, res[i], opts.runs))
end
print(string.format("%s\n%s", table.concat(output, ""), get_summary(res)))
return res
end
return bench