neovim/test/benchmark/deepcopy_spec.lua
Lewis Russell 3734519e3b feat(lua): add noref to deepcopy
Problem:

Currently `deepcopy` hashes every single tables it copies so it can be
reused. For tables of mostly unique items that are non recursive, this
hashing is unnecessarily expensive

Solution:

Port the `noref` argument from Vimscripts `deepcopy()`.

The below benchmark demonstrates the results for two extreme cases of
tables of different sizes. One table that uses the same table lots of
times and one with all unique tables.

| test                 | `noref=false` (ms) | `noref=true` (ms) |
| -------------------- | ------------------ | ----------------- |
| unique tables (50)   | 6.59               | 2.62              |
| shared tables (50)   | 3.24               | 6.40              |
| unique tables (2000) | 23381.48           | 2884.53           |
| shared tables (2000) | 3505.54            | 14038.80          |

The results are basically the inverse of each other where `noref` is
much more performance on tables with unique fields, and `not noref` is
more performant on tables that reuse fields.
2024-01-03 19:17:52 +00:00

59 lines
1.1 KiB
Lua

local N = 20
local function tcall(f, ...)
local ts = vim.uv.hrtime()
for _ = 1, N do
f(...)
end
return ((vim.uv.hrtime() - ts) / 1000000) / N
end
local function build_shared(n)
local t = {}
local a = {}
local b = {}
local c = {}
for _ = 1, n do
t[#t + 1] = {}
local tl = t[#t]
for _ = 1, n do
tl[#tl + 1] = a
tl[#tl + 1] = b
tl[#tl + 1] = c
end
end
return t
end
local function build_unique(n)
local t = {}
for _ = 1, n do
t[#t + 1] = {}
local tl = t[#t]
for _ = 1, n do
tl[#tl + 1] = {}
end
end
return t
end
describe('vim.deepcopy()', function()
local function run(name, n, noref)
it(string.format('%s entries=%d noref=%s', name, n, noref), function()
local t = name == 'shared' and build_shared(n) or build_unique(n)
local d = tcall(vim.deepcopy, t, noref)
print(string.format('%.2f ms', d))
end)
end
run('unique', 50, false)
run('unique', 50, true)
run('unique', 2000, false)
run('unique', 2000, true)
run('shared', 50, false)
run('shared', 50, true)
run('shared', 2000, false)
run('shared', 2000, true)
end)