-
Notifications
You must be signed in to change notification settings - Fork 395
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
Use caching for foldlevels to improve fold calculation performance #3054
Conversation
Works for me, it's a lot snappier as for larger files this is a question of seconds. One could think about retaining I tested with a larger Tex file and function! TestFoldingSpeed()
let start_time = reltime()
normal! zMzX
let elapsed_time = reltimestr(reltime(start_time))
echomsg "Folding took: " . elapsed_time
endfunction sped up from |
Yes, I was unsure about this. The docs claim it is less efficient to pass the line number as an argument, but I'm not sure if that's really true or significant.
Well, I've tested this more thoroughly, and I think you might be wrong. I made the following test file set nocompatible
" Use path to VimTeX here!
set runtimepath^=../..
filetype plugin on
function! Report()
let l:sum = 0
let l:max = 0
for [l:key, l:value] in items(g:time_per_lnum)
let l:sum += l:value
if l:value > l:max
let l:max = l:value
endif
endfor
echo 'Number: ' .. len(g:time_per_lnum)
echo 'Sum: ' .. l:sum
echo 'Max: ' .. l:max
echo 'Avg: ' .. l:sum/len(g:time_per_lnum)
echo 'Repeats: ' .. len(g:repeats_per_lnum)
endfunction
let g:time_per_lnum = {}
let g:repeats_per_lnum = {}
function! FoldLevel()
let start_time = reltime()
let l:res = vimtex#fold#level(v:lnum)
let elapsed_time = reltimefloat(reltime(start_time))
if has_key(g:time_per_lnum, v:lnum)
let g:repeats_per_lnum[v:lnum] = get(g:repeats_per_lnum, v:lnum, 0) + 1
endif
let g:time_per_lnum[v:lnum] = elapsed_time
return l:res
endfunction
let g:vimtex_cache_root = "."
let g:vimtex_cache_persistent = v:false
setlocal foldmethod=expr
setlocal foldexpr=FoldLevel()
setlocal foldtext=vimtex#fold#text()
nnoremap <space>tt :<c-u>call Report()<cr>
silent edit LARGE_FILE.tex On a file
With the current
When I move somewhere and start typing in the Notice, though, that the current |
Or, to summarize: Vim and neovim already has a mechanism for caching fold calculations. My understanding is that the idea presented here with using the I will be glad to be proven wrong, but I would also be surprised. Notice, though: |
I've added the fold timing measure script to the repo, for convenience: https://github.com/lervag/vimtex/blob/perf/folding/test/perf-folding/measure.vim |
Well, I am surprised as well. Only loading a Lua file (see the referred PR) with folding enabled took ages in Vim without caching. On my old laptop, your large file loads in a few seconds with the performance branch, but takes felt a minute on the standard branch. In numbers:
vs
I tested on Vim though. |
I guess you meant "takes like a minute"?
This is indeed very strange. Are you testing with the minimal configuration file or did you copy the test code into your full config? On my end, I get comparable timings with both Vim and neovim. I'm on Arch Linux with neovim nightly and Vim 9.1.866. It seems like my test code is useful, though, as it did capture the very long load time... if I were to be able to reproduce, I might figure out what is going on. |
Yes, I guess I wanted to write takes what felt like a minute (but was a bit less). I ran it with Comparing your results
the current method does not seem clearly faster, there's always an error margin.
But does not the very simple function! TestFoldingSpeed()
let start_time = reltime()
normal! zMzX
let elapsed_time = reltimestr(reltime(start_time))
echomsg "Folding took: " . elapsed_time
endfunction also at least capture the time for recomputation of folds
This is great as it shows that my issue vim/vim#16184 to implement this natively in Vim is already resolved. Where this is documented at
Of course, everyone can have a different interpretation of
This shows mastery of Looking at the source (let me take Vim's, as Neovim's uses Treesitter), there's // src/vim.h (line 1851)
# define MAXLNUM LONG_MAX // maximum (invalid) line number used in /* src/fold.c (lines 1216-1223) */
checkupdate(win_T *wp)
{
if (!wp->w_foldinvalid)
return;
foldUpdate(wp, (linenr_T)1, (linenr_T)MAXLNUM); // will update all
wp->w_foldinvalid = FALSE;
} called by
on updating folds; at least in Vim no check for changed lines springs to my eye, but this was just a hasty grep. |
Oh, no, I think it should work as expected. But you will probably need to force pull. That is, I force pushed the branch a couple of times. So do
Well, that's clearly not a significant difference.
No, not really.
It is wrong because, as I said, we want to inspect the cost of recomputing folds when there actually was a change that requires recomputing anything. Users should not need to do
I think this is not a recent change, but how
Yes; when you open a file, the expression is evaluated for every line. But this does not actually say it is evaluated for every line every time.
This part of the docs partly explain how the
No, Neovim uses more or less the same source for the If you want, I can try to study the source code to show how this built-in cache works. To be honest, I'm not very well versed in C or C++, so it'll be challenging for me. But I am quite certain I'm right here.
Yes, I think you are looking at the wrong parts here. That said, you claim that you have an example/situation where the present feature in |
Nothing is needed, it's comes down to user preference.
I checked above
I cannot infer this from the help. We are reading it differently. I rather read this as another warning
that one should not try to compute the fold level of a line by using those of other lines.
What you explain sounds very sensible (and would have designed it that way), and that's why I'm surprised that something like this doesn't seem to happen. I couldn't see it in the Vim source, but what brought me here was rather that the simple Lua foldexpr (converted from Lua to vimscript in vim/vim#16151) was too slow to load on larger files, say https://github.com/skywind3000/z.lua/blob/1.8.13/z.lua before caching was added.
Proving wrong is the best way to resolve open questions on the internet |
I don't think you need
I'm not trying to be annoying here, but: how did you measure this? If you still insist on using
Well, perhaps I need to read the source code to show you what I mean then. But first, let me try one more time. My understanding, both from reading the docs and from having spent a lot of time writing
I claim that my measure.vim file proves this. If you use the same
Well, in the version of the Lua foldexpr before you added the cache (based on this diff), the calculations are done by actually iterating every single line every time. That's very inefficient! And the cache you've implemented here will be a huge improvement, because even if you do refresh by recomputing the folds on each line everytime you make a change, it is still much better than it would be. But now we are not discussing the Lua foldlevel function. Let's focus on VimTeX and its foldlevel function. I won't mind improving it, but I am claiming that the current PR will lead to a worse experience. As a proof of this:
On my end, this lags a lot! While on the Further, the startuptime on the The only scenario where Now, you say "Proving wrong is the best way to resolve open questions on the internet", and I agree. I've tried to do exactly that. |
I thought about that while writing, but it doesn't close other folds so helps not as much locating the global position inside a long buffer. But you already give the remedy
I never gave it much thought, as the slight lag on hitting Funnily my muscle memory navigating folds has been tied to This explains our complimentary experiences. It used to be that the recomputation of folds slowed down insert mode by recomputing them on every changed character (also in TeX files).
I can confirm this, so yes, that's an efficient Pulling and resetting hard to latest master b8bb79b and perf/folding 79e78ee the results of
Hats off! I am not sure whether similar improvements can be made to |
Great, I'm glad to see we are reaching a common understanding here.
Yes, I do remember that I started using Fastfold at some time and that it really did feel necessary. I no longer use it, and I don't know when it stopped being unnecessary. But it would not be surprising if there were updates to Vim and neovim that somehow did improve the fold experience in a way that rendered Fastfold less relevant.
Good, thanks. I've actually put a lot of work in figuring out how to make it relatively efficient. But, as is also clear from the present issue: on huge files, there is still a toll e.g. on startup time and it can take on the order of a second to load a file just for the folding. It's not great, but I don't know how to improve that much more. Still, most files I work on are not nearly as large and for just commonly large files it is not a big problem.
If you have And just to be clear: sometimes you might want to do
Thanks; and yes, indeed, I think that observation is quite correct. Although, it is really not trivial to write perfomant
I've never really liked syntax based folding; the times I've used it I've often found myself thinking it is not so robust. But to be fair, I don't think I ever actually wrote syntax rules that also specify folding rules. I think I found that using Ok, it's been a relatively long discussion here. But if I understand correctly we are now in agreement that this PR should not be merged. Right? |
Yes, closing it is fine (as well as vim/vim#16184 (comment)). I am now skipping What would make sense though could be to document your shared knowledge at |
👍
Yes, I guess that's a good idea. I don't think we really need much, except perhaps rewording a few of the paragraphs that cause confusion? Like for instance, we could qualify the sentence that says "... every line" to indicate that this is only relevant when initializing (or recomputing) folds. I'll be happy to review and contribute, especially if you write a first version! |
Here we go |
Should resolve #3049.
One thing, though: How can I properly test that this indeed performs better than before?
@Konfekt Do you have any suggestion for how to more precisely test performance for folding?