Skip to content
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

perf(source): only filter up to 200 entries and dont use the cache #1574

Merged
merged 2 commits into from
May 16, 2023

Conversation

folke
Copy link
Contributor

@folke folke commented May 15, 2023

This PR changes the way get_entries works, but semantically it's still the same as before:

  • don't cache filtered entries. For Tailwindcss and others, this leads to lots of memory usage
  • always calculate filtered items on the fly, but stop once desired max_entries is reached
  • only re-calculate filtered entries when the context changes

@folke folke marked this pull request as draft May 15, 2023 15:06
@folke folke marked this pull request as ready for review May 15, 2023 16:15
end
end
end
self.cache:set({ 'get_entries', tostring(self.revision), ctx.cursor_before_line }, entries)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think get_entries cache will reduce the CPU cost. Why do you remove this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It leads to big memory issues with tailwind and probably others.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll see if I can incorporate the cache again in some other way that doesn't include all the memory overhead

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, nvim-cmp will save the all of caches for each user input. (f -> fo -> foo).
It can be helped for <BS> but I think we can avoid it (The <BS> use-case can be ignored).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just added caching back, but only if the filtered entries list is < max_item_count.
It's only then that we can re-use the cache, otherwise we might miss entries that could have matched, but were not included.

This also still fixes the memory issue since we won't store too big entry arrays in the cache

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this solution is actually optimal. When the entries are huge, we filter and break as soon as we have 200 matches.

As soon as we filter down to less than 200 matches, the cache is used and the big entries list no longer needs to be fully processed.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that this fix improves the performance.
It also makes sense that the current nvim-cmp is already an incorrect implementation, so there is no negative behavior.

However, I doubt that this approach is the right way.

That being said, I'm not planning any drastic improvements to nvim-cmp, so I agree with efficiency first.

end)()
if self.filtered.ctx and self.filtered.ctx.id == ctx.id then
return self.filtered.entries
end
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good. Thank you!

@yioneko
Copy link
Contributor

yioneko commented May 15, 2023

Just my little thought: current implantation of limiting entries without pre-sorting is wrong and leads to suboptimal result candidates and early break of filtering seems to conflict with this. In the theory, all the entires should be done with filtering to yield the best candidates. However, by early break we'd gain huge performance improvement because the current fuzzy matching implementation is not efficient enough for some extreme cases. This might be a choice between correctness and performance.

@folke
Copy link
Contributor Author

folke commented May 15, 2023

@yioneko the current cmp implementation already does pre-filtering and only sorts the resulting entries.

But I do agree, that it would be better to include your changes as well, so that we can remove that 200 limit.

Maybe you should also open a PR with your async changes?

@yioneko
Copy link
Contributor

yioneko commented May 15, 2023

@folke What I meant is that sorting should be done before limiting to preserve entries with higher expectation, and this actually conflict with early break of breaking by max_items_count. The current implementaion (not including this pr) is actually wrong.

Maybe you should also open a PR with your async changes?

My changes are pretty hacky and should not be considered for merging. Also I don't have much time to work on formalizing it currently. (Would like to if I have time, I also have some other ideas for optimization)

@hrsh7th
Copy link
Owner

hrsh7th commented May 16, 2023

@folke I can merge this for now. Do you have any work left to do?

@folke
Copy link
Contributor Author

folke commented May 16, 2023

Good to go!

I'll work on an async PR after this to further optimize the code.

@hrsh7th hrsh7th merged commit 768548b into hrsh7th:main May 16, 2023
@hrsh7th
Copy link
Owner

hrsh7th commented May 16, 2023

Thank you~!

@bluz71 bluz71 mentioned this pull request May 23, 2023
williamboman added a commit to williamboman/nvim-cmp that referenced this pull request May 26, 2023
…indow

* upstream/main: (31 commits)
  fix entry highlight in complete-menu (hrsh7th#1593)
  Remove max_item_count from source configuration
  feat: cmp async (hrsh7th#1583)
  ghost text inline (hrsh7th#1588)
  Fix demo video in README.md (hrsh7th#1585)
  docs: fix adjecent typo (hrsh7th#1577)
  docs: fix typos, add confirm.behavior example cfg (hrsh7th#1576)
  perf(source): only filter up to 200 entries and dont use the cache (hrsh7th#1574)
  fix(ghost_text): safely apply virtual_text highlight (hrsh7th#1563)
  Improve misc.merge
  Fix hrsh7th#897
  Added a modified=false to documentation buffer, so it can be removed without E89 errors (hrsh7th#1557)
  Fix hrsh7th#1556
  fix 1533, add regression test (hrsh7th#1558)
  Add `buftype=nofile` for entries_win and docs_win - reddit user mention this...
  Fix hrsh7th#1550
  Format with stylua
  Add test for hrsh7th#1552 Close hrsh7th#1552
  Revert hrsh7th#1534 temporaly
  fix typo (hrsh7th#1551)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants