Closed timholy closed 4 years ago
Thank this looks fantastic!
With regards to the timings and how this translates to real world responsiveness - the copying of the SymbolServer.stdlibs
store is a once per session operation so this change will benefit the startup time for the language server. The intention is to fiddle with the SymbolServer storage objects' structure as little as possible so maintaining the recursive_copy
functions isn't an issue.
The following snippet would time the indexing of a package:
using SymbolServer
using Packages,You,Want,To,Index
env = SymbolServer.getenvtree() #This creates a tree of all modules within the current session, including submodules
@time SymbolServer.symbols(env) # index everything
@time SymbolServer.symbols(env, somemodule) # index a single module
For realistic timings I think you need to restart the Julia session between runs, though for checking the impact of changes it's probably fine to not. If I remember correctly a significant share of the total time is spent introspecting methods
Thanks for the great tips, @ZacLN! The next set of changes I made were orthogonal to these, so I put them in a separate PR (#160). As far as I am concerned this PR is all set, if you want it. (It probably doesn't affect performance in real-world usage all that significantly, esp. compared to #160, so whatever you choose will be fine with me.)
Definitely one to merge! Reductions in startup time are always worth double, right?
I decided to see if I could determine whether there was any way to speed up LanguageServer. I'm not sure how to run it in "real" circumstances, but as a proxy I decided to profile the various files in its tests. It turns out there was exactly one obvious bottleneck: calls to
deepcopy(SymbolServer.stdlibs)
.As a comment in this PR explains,
deepcopy
is safe and convenient but slow; its slowness comes from two factors:fieldnames(typeof(x))
rather than creating a hand-crafted version for each struct typeIf you don't need to worry about cycles, you can do a lot better by defining your own recursive copy function, and that is done in this PR. There is a downside, mainly that as you modify types it's important to remember to update your implementation of
recursive_copy
, and new types require methods of their own. But the advantage is improved performance. For instance, with this PR and if you make the single changein LanguageServer.jl, then I get these benchmarks on LanguageServer's tests (run after
test_communication
since the other tests seem to use its results):As you can see, these are nothing to sneeze at. I am not sure whether these will translate into similar gains in real-world circumstances; is there a simple way to trigger indexing on a specific package from the REPL? I'd be happy to take a poke at that and see if there are more performance gains to be had.