Closed findleyr closed 2 years ago
Change https://golang.org/cl/312689 mentions this issue: internal/lsp/cache: preallocate internal maps when cloning snapshots
Working on unnecessary URI.Filename() usage in snapshot reduction
Change https://golang.org/cl/312809 mentions this issue: internal/lsp/cache: improve snapshot clone perfomance
Extending this more generally to didChange handling, as snapshot.clone is only one of the problems. There is some other stuff in e.g. didModifyFiles that's quite slow.
@justplesh thanks very much for your contribution, and interest. Right now we're still trying to figure out the best path forward for some of these optimizations. Hopefully we'll have a better sense of what needs to be prioritized next week. If you'd like, we can keep you in mind for anything that is relatively self-contained.
@findleyr Sure, please mention me or assign any lsp issue that I may work on. I'll be happy to work on it on some +- regular basis.
@findleyr will we merge my PR then or will we wait for some more fundamental approach?
@justplesh we can proceed with your CL; it should be an improvement.
Change https://golang.org/cl/317292 mentions this issue: internal/lsp/regtest: add a benchmark for didChange
Change https://golang.org/cl/317410 mentions this issue: internal/lsp: memoize allKnownSubdirs instead of recomputing
We will probably focus next on:
URI.Filename() is a huge source of unnecessary cost; almost all URI manipulations could be done directly with the URI string rather than converting to file paths (which involves URI parsing).
I spent some time analyzing our didChange performance last night. I've come to the opinion that using a map datastructure that is optimized for cloning is really just working around the lack of modularity in the snapshot. I think we should instead try to:
I think doing these three things will take a huge chunk of CPU (and complexity) out of clone. There are still more optimizations to be had.
I'm currently working on this, and think I'll be able to significantly reduce the cost via the following two changes:
These two improvements take care of the majority of change processing CPU time; there are other improvements to be made, but they are all of second-order.
Change https://golang.org/cl/340735 mentions this issue: internal/lsp/cache: derive workspace packages from metadata
Change https://golang.org/cl/340853 mentions this issue: internal/lsp/cache: only clone metadata if something changed
Change https://golang.org/cl/340852 mentions this issue: internal/lsp/cache: use metadataGraph.Clone in snapshot.clone
Change https://golang.org/cl/340855 mentions this issue: internal/lsp/cache: delete checkSnapshotLocked
Change https://golang.org/cl/340730 mentions this issue: internal/lsp/cache: move metadata fields to a new metadataGraph type
Change https://golang.org/cl/340854 mentions this issue: internal/lsp/cache: don't walk URIs to invalidate metadata
Change https://go.dev/cl/410697 mentions this issue: internal/lsp/cache: two minor optimizations
Change https://go.dev/cl/410176 mentions this issue: internal/lsp/cache: optimize Snapshot.clone
Change https://go.dev/cl/340851 mentions this issue: internal/lsp/cache: build a new metadata graph on load
Change https://go.dev/cl/411554 mentions this issue: internal/lsp/cache: use persistent map for storing gofiles in the snapshot
Change https://go.dev/cl/413657 mentions this issue: internal/lsp/cache: persist known subdirs
Change https://go.dev/cl/413654 mentions this issue: internal/lsp/cache: use persistent map for storing files in the snapshot
Change https://go.dev/cl/413655 mentions this issue: internal/lsp/cache: use persistent map for storing packages in the snapshot
I'm going to tentatively mark this issue as complete. There's more we can do here (and in fact, more CLs still pending), but we've largely succeeded :tada:
The benchmark I use for didChange latency (typing in Kubernetes) has already decreased from ~55ms->1.5ms. Since repositories significantly larger than Kubernetes are going to bump up against other limitations of gopls, I think we can reasonably say that didChange processing time is no longer a major issue.
(for record keeping we can continue to submit CLs against this issue, even though I am closing it now).
Recent profiling has shown that, particularly on large codebases, snapshot cloning can significantly impact gopls' responsiveness.
Snapshot cloning is not optimized: there are lots of opportunities for performance improvement. For example:
Not sure which of these we'll do. Filing this as an umbrella issue to track improving performance.
CC @heschi @stamblerre