Skip to content

Perf: Improve performance of multithreaded --check and undefined-field diagnostic #2738

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* `NEW` Add postfix snippet for `unpack`
* `FIX` `diagnostics.severity` defaulting to "Warning" when run using `--check` [#2730](https://github.com/LuaLS/lua-language-server/issues/2730)
* `NEW` Add support for lambda style functions, `|paramList| expr` is syntactic sugar for `function(paramList) return expr end`
* `CHG` Improve performance of multithreaded `--check` and `undefined-field` diagnostic

## 3.9.3
`2024-6-11`
Expand Down
13 changes: 2 additions & 11 deletions script/cli/check_worker.lua
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,6 @@ local checkLevel = define.DiagnosticSeverity[CHECKLEVEL] or define.DiagnosticSev

util.enableCloseFunction()

-- Hash function used to distribute work.
local function hashString(str)
local hash = 0
for i = 1, #str do
hash = (hash * 37 & 0xFFFFFFFF) + str:byte(i, i)
end
return hash
end

local lastClock = os.clock()
local results = {}

Expand Down Expand Up @@ -109,9 +100,9 @@ xpcall(lclient.start, errorhandler, lclient, function (client)

local uris = files.getChildFiles(rootUri)
local max = #uris
table.sort(uris) -- sort file list to ensure the work distribution order across multiple threads
for i, uri in ipairs(uris) do
local hash = hashString(uri) % numThreads + 1
if hash == threadId then
if (i % numThreads + 1) == threadId then
files.open(uri)
diag.doDiagnostic(uri, true)
-- Print regularly but always print the last entry to ensure that logs written to files don't look incomplete.
Expand Down
2 changes: 1 addition & 1 deletion script/core/diagnostics/undefined-field.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ return function (uri, callback)
local function checkUndefinedField(src)
await.delay()

if #vm.getDefs(src) > 0 then
if vm.hasDef(src) then
return
end
local node = src.node
Expand Down
39 changes: 39 additions & 0 deletions script/vm/def.lua
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,42 @@ function vm.getDefs(source)

return results
end

local HAS_DEF_ERR = {} -- the error object for comparing
local function checkHasDef(checkFunc, source, pushResult)
local _, err = pcall(checkFunc, source, pushResult)
return err == HAS_DEF_ERR
end

---@param source parser.object
function vm.hasDef(source)
local mark = {}
local hasLocal
local function pushResult(src)
if src.type == 'local' then
if hasLocal then
return
end
hasLocal = true
if source.type ~= 'local'
and source.type ~= 'getlocal'
and source.type ~= 'setlocal'
and source.type ~= 'doc.cast.name' then
return
end
end
if not mark[src] then
mark[src] = true
if guide.isAssign(src)
or guide.isLiteral(src) then
-- break out on 1st result using error() with a unique error object
error(HAS_DEF_ERR)
end
end
end

return checkHasDef(searchBySimple, source, pushResult)
or checkHasDef(searchByLocalID, source, pushResult)
or checkHasDef(vm.compileByNodeChain, source, pushResult)
or checkHasDef(searchByNode, source, pushResult)
end
Loading