mirror of
https://github.com/neovim/neovim.git
synced 2024-12-20 11:15:14 -07:00
6b3399338f
Problem: Memory usage test may still fail on some systems.
Solution: Increase tolerance from 3% to 20%.
6b6f7aae4a
159 lines
4.7 KiB
Lua
159 lines
4.7 KiB
Lua
local helpers = require('test.functional.helpers')(after_each)
|
|
local clear = helpers.clear
|
|
local eval = helpers.eval
|
|
local eq = helpers.eq
|
|
local feed_command = helpers.feed_command
|
|
local iswin = helpers.iswin
|
|
local retry = helpers.retry
|
|
local ok = helpers.ok
|
|
local source = helpers.source
|
|
|
|
local monitor_memory_usage = {
|
|
memory_usage = function(self)
|
|
local handle
|
|
if iswin() then
|
|
handle = io.popen('wmic process where processid=' ..self.pid..' get WorkingSetSize')
|
|
else
|
|
handle = io.popen('ps -o rss= -p '..self.pid)
|
|
end
|
|
return tonumber(handle:read('*a'):match('%d+'))
|
|
end,
|
|
op = function(self)
|
|
retry(nil, 10000, function()
|
|
local val = self.memory_usage(self)
|
|
if self.max < val then
|
|
self.max = val
|
|
end
|
|
table.insert(self.hist, val)
|
|
ok(#self.hist > 20)
|
|
local result = {}
|
|
for key,value in ipairs(self.hist) do
|
|
if value ~= self.hist[key + 1] then
|
|
table.insert(result, value)
|
|
end
|
|
end
|
|
table.remove(self.hist, 1)
|
|
self.last = self.hist[#self.hist]
|
|
eq(#result, 1)
|
|
end)
|
|
end,
|
|
dump = function(self)
|
|
return 'max: '..self.max ..', last: '..self.last
|
|
end,
|
|
monitor_memory_usage = function(self, pid)
|
|
local obj = {
|
|
pid = pid,
|
|
max = 0,
|
|
last = 0,
|
|
hist = {},
|
|
}
|
|
setmetatable(obj, { __index = self })
|
|
obj:op()
|
|
return obj
|
|
end
|
|
}
|
|
setmetatable(monitor_memory_usage,
|
|
{__call = function(self, pid)
|
|
return monitor_memory_usage.monitor_memory_usage(self, pid)
|
|
end})
|
|
|
|
describe('memory usage', function()
|
|
local function check_result(tbl, status, result)
|
|
if not status then
|
|
print('')
|
|
for key, val in pairs(tbl) do
|
|
print(key, val:dump())
|
|
end
|
|
error(result)
|
|
end
|
|
end
|
|
|
|
local function isasan()
|
|
local version = eval('execute("version")')
|
|
return version:match('-fsanitize=[a-z,]*address')
|
|
end
|
|
|
|
before_each(clear)
|
|
|
|
--[[
|
|
Case: if a local variable captures a:000, funccall object will be free
|
|
just after it finishes.
|
|
]]--
|
|
it('function capture vargs', function()
|
|
if isasan() then
|
|
pending('ASAN build is difficult to estimate memory usage')
|
|
end
|
|
if iswin() and eval("executable('wmic')") == 0 then
|
|
pending('missing "wmic" command')
|
|
elseif eval("executable('ps')") == 0 then
|
|
pending('missing "ps" command')
|
|
end
|
|
|
|
local pid = eval('getpid()')
|
|
local before = monitor_memory_usage(pid)
|
|
source([[
|
|
func s:f(...)
|
|
let x = a:000
|
|
endfunc
|
|
for _ in range(10000)
|
|
call s:f(0)
|
|
endfor
|
|
]])
|
|
local after = monitor_memory_usage(pid)
|
|
-- Estimate the limit of max usage as 2x initial usage.
|
|
check_result({before=before, after=after}, pcall(ok, before.last < after.max))
|
|
check_result({before=before, after=after}, pcall(ok, before.last * 2 > after.max))
|
|
-- In this case, garbage collecting is not needed.
|
|
-- The value might fluctuate
|
|
-- a bit, allow for 3% tolerance.
|
|
local lower = after.last * 97 / 100
|
|
local upper = after.last * 103 / 100
|
|
check_result({before=before, after=after}, pcall(ok, lower < after.max))
|
|
check_result({before=before, after=after}, pcall(ok, after.max < upper))
|
|
end)
|
|
|
|
--[[
|
|
Case: if a local variable captures l: dict, funccall object will not be
|
|
free until garbage collector runs, but after that memory usage doesn't
|
|
increase so much even when rerun Xtest.vim since system memory caches.
|
|
]]--
|
|
it('function capture lvars', function()
|
|
if isasan() then
|
|
pending('ASAN build is difficult to estimate memory usage')
|
|
end
|
|
if iswin() and eval("executable('wmic')") == 0 then
|
|
pending('missing "wmic" command')
|
|
elseif eval("executable('ps')") == 0 then
|
|
pending('missing "ps" command')
|
|
end
|
|
|
|
local pid = eval('getpid()')
|
|
local before = monitor_memory_usage(pid)
|
|
local fname = source([[
|
|
if !exists('s:defined_func')
|
|
func s:f()
|
|
let x = l:
|
|
endfunc
|
|
endif
|
|
let s:defined_func = 1
|
|
for _ in range(10000)
|
|
call s:f()
|
|
endfor
|
|
]])
|
|
local after = monitor_memory_usage(pid)
|
|
for _ = 1, 3 do
|
|
feed_command('so '..fname)
|
|
end
|
|
local last = monitor_memory_usage(pid)
|
|
-- The usage may be a bit less than the last value, use 80%.
|
|
-- Allow for 20% tolerance at the upper limit. That's very permissive, but
|
|
-- otherwise the test fails sometimes.
|
|
local lower = before.last * 8 / 10
|
|
local upper = (after.max + (after.last - before.last)) * 12 / 10
|
|
check_result({before=before, after=after, last=last},
|
|
pcall(ok, lower < last.last))
|
|
check_result({before=before, after=after, last=last},
|
|
pcall(ok, last.last < upper))
|
|
end)
|
|
end)
|