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
Poor performance with Treesitter highlighting on deep if-else in c #24965
Comments
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
Most time is spent processing patch for profilingdiff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua
index 496193c6e..a24d022d3 100644
--- a/runtime/lua/vim/treesitter/highlighter.lua
+++ b/runtime/lua/vim/treesitter/highlighter.lua
@@ -315,6 +315,7 @@ function TSHighlighter._on_spell_nav(_, _, buf, srow, _, erow, _)
end
end
+local start
---@private
---@param _win integer
---@param buf integer
@@ -335,6 +336,8 @@ api.nvim_set_decoration_provider(ns, {
on_win = TSHighlighter._on_win,
on_line = TSHighlighter._on_line,
_on_spell_nav = TSHighlighter._on_spell_nav,
+ on_start = function() start = vim.uv.hrtime() end,
+ on_end = function() print('redrawn', (vim.uv.hrtime() - start) / 1000000, vim.treesitter.query.times()) end
})
return TSHighlighter
diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua
index 8cbbffcd6..0f0a04a00 100644
--- a/runtime/lua/vim/treesitter/query.lua
+++ b/runtime/lua/vim/treesitter/query.lua
@@ -407,6 +407,29 @@ local predicate_handlers = {
-- As we provide lua-match? also expose vim-match?
predicate_handlers['vim-match?'] = predicate_handlers['match?']
+local times = {} ---@type table<string, number>
+for k, f in pairs(predicate_handlers) do
+ times[k] = 0
+ predicate_handlers[k] = function(...)
+ local start = vim.uv.hrtime()
+ local ret = { f(...) }
+ times[k] = times[k] + (vim.uv.hrtime() - start) / 1000000
+ return unpack(ret)
+ end
+end
+
+function M.times()
+ local all_zeros = true
+ local result = vim.inspect(times)
+ for k, _ in pairs(times) do
+ if times[k] > 0 then all_zeros = false end
+ times[k] = 0
+ end
+ if not all_zeros then
+ return result
+ end
+end
+
---@class TSMetadata
---@field range? Range
---@field conceal? string time spent while redrawing (in ms)
The treesitter c grammar parses neovim/runtime/lua/vim/treesitter/query.lua Lines 385 to 390 in e46f5aa
I think there should be some limit on the distance or time. |
Yes, A distance limit is unacceptable, since some functionality (other than highlighting) may rely on a correct global parse. A general time limit is already planned and should cover this as well: #22420 |
I think that patch in the current form doesn't fix this issue. Those predicates are called during
It wouldn't too difficult to add the timeout logic to treessiter highlighter's decoration provider, but I think per-query distance limit (e.g., adding "limit" parameter to
|
Concretely, how would that look for the C queries here? (It's always better to design an API around concrete use cases instead of generic hypotheticals ;)) |
The problematic query for the OP's example is this neovim/runtime/queries/c/highlights.scm Lines 206 to 208 in e46f5aa
I was thinking of something like this - (#has-ancestor? @function.builtin attribute_specifier))
+ (#has-ancestor-within? 20 @function.builtin attribute_specifier)) Since |
Yes, but what concretely would be the limit value? Is this something fixed by the actual query, or just some sort of "I don't expect that most cases will need more than 20..." (There's a big difference between an objectively correct value and a fudge factor that needs to be tuned.)
Adding yet another variant is a hard "no" from me, I'm afraid. If we cannot support this with the current predicate, If |
For that example, I meant the latter. For something objectively correct, we would need an interface that takes a general predicate on the path to ancestor. This is relatively simple in some cases.
I don't know if such "per-node" predicates are sufficient for other cases. But in any case, I think distance limit is good enough even if it can't be totally correct since the worst thing that could happen is just some hightlight going slightly off.
Or we can make
I think that should be fine. In fact that's how |
In which case, wouldn't it be better to just handle this in the predicate handler itself? If we only want to guard against unbounded recursion, we can treat this as a global limit (possibly tunable, similarly to |
Sounds good. I'll try it later when I have time. |
I made a prototype that decreases the time to
from
by adding a function to tree-sitter.
This can be decreased to n if treesitter exposes a function to get node's parents in reverse order. |
Very nice! Would you care making a PR to tree-sitter? |
Yes |
Problem
Editing or moving close to the last line of a very long if-elseif-elseif-else structure takes about ~1 second per action to perform.
Steps to reproduce
Open a file with the content below. Move to the bottom with
G
. notice how it takes a long time.File content:
Expected behavior
Fast and rapid movement and editing
Neovim version (nvim -v)
NVIM v0.10.0-dev-994+g670c7609c-dirty
Vim (not Nvim) behaves the same?
no
Operating system/version
Ubuntu 22.04
Terminal name/version
wezterm version: 20230820-104238-6c7aa815
$TERM environment variable
xterm-256color
Installation
build from repo
The text was updated successfully, but these errors were encountered: