Skip to content

A Plan for Making Rust Analyzer Faster #17491

Open
@davidbarsky

Description

@davidbarsky

Some background context:

  • For a while, I've been looking at and investigating rust-analyzer performance issues.
  • @Wilfred, @darichey, and I all work together, and our employer is paying us to improve rust-analyzer's performance over the next 6 months on a full-time basis. We've determined that rust-analyzer's current performance is the biggest issue faced by Rust programmers at our employer.
    • By listing these issues out, we're not attempting to "lick the cookie" or claim it—it's a lot of work for 3 people, and if anyone gets an issue before we do, please do it! Every rust-analyzer user would benefit with these things happening more quickly.

Anyways, here's non-exhaustive (but decently comprehensive!) list of things that we'd like to fix.

Non-Parallel, Single-Threaded Improvements

  • Rowan is slower than we'd like.
  • macro_rules! expansion is quadratic. This most visible with tt-munchers (discussion).
  • Switch from an LRU cache to a scan-resistant cache (LRU-K)
    • This may or not be impactful, but rust-analyzer implements a limited form of garbage collection in the form of an LRU cache. rust-analyzer also does a lot of scan-like operations, which is a classic pathological case for a naive LRU cache. Replacing the LRU cache with LRU-k (specifically, a scan-resistant cache) might help with how often the syntax tree cache is rebuilt (discussion on Zulip).
  • Switch the crate graph to a Salsa database.
    • Migrating the crate graph from an arena to a Salsa database would make the workspace reindexing that occurs after a user adds/removes a dependency to their project substantially faster and more incremental.
    • Crate IDs are not currently stable, as they are derived from cargo-metadata or a rust-project.json. Deriving the crate ID from the crate data itself (via Salsa’s interning infrastructure) will provide a stable ID (discussion on Zulip).
    • This is also necessary to properly support Cargo scripts.
  • During project loading, rust-analyzer repeatedly queries the project layout from rustc repeatedly, as there isn’t a clear end-state for project loading. Deferring this until the very end would likely help with loading large Rust workspaces.
    • I did some rough, back-of-napkin benchmarks: rust-analyzer spends 5 seconds waiting on rustc for every 100 crates it loads (established by printing Instant::elapsed::as_millis). Given that some Rust projects can easily have of over 1000 dependencies, it’s possible that people are waiting for nearly a minute.
  • Moving to Salsa 3.0 might reduce with how many allocations/Arc increments regularly occur because Salsa 3.0 hands references instead of cloned values.
    • I don’t know much of an impact this might have on the overall performance rust-analyzer, but if it does, it’d be because allocations/Arc increments/decrements would be smeared across the entire codebase.
    • From a best practices perspective, we should move to Salsa 3.0 regardless, especially if it doesn't regress rust-analyzer's performance.

Parallel Improvements

From a sequencing standpoint, most parallelism improvements in rust-analyzer should happen after single-threaded improvements occurs, as introducing parallelism without making single-core performance improvements simply papers over existing, resolvable performance issues—I believe it is better to have those improvements compound. Besides, for a large number of these changes below, are waiting on Salsa 3.0, as it will enable trivial parallel computation for all databases (salsa-rs/salsa#495) 1.

  • Parallelize autocomplete
  • Parallelize VFS loading
    • At the moment, the VFS loads all sources serially (Load files into the VFS in parallel on startup #17373). rust-analyzer should attempt to saturate disk IO, as I've observed that the disk throughput is substantially less than what I'd expect from rust-analyzer on an SSD. This work does not depend on Salsa 3.0.
    • As part of this work, we should redesign the VFS (Rethink our VFS abstraction #18948), with the most likely outcome being moving most or all of the VFS to live in new Salsa. The reason VFS is the way that it is, if I understand correctly, is that the VFS needs to assign file IDs—interning, effectively—but at the time, Salsa was not capable of doing so.

I'll add more items as they come up, but I figured I should combine the different discussion topics into a single location.

Footnotes

  1. The version of Salsa used by rust-analyzer todays requires getting a snapshot from the ParallelDatabase trait, and ParallelDatabase is only implemented on the RootDatabase. Similarly, parallel query dependencies are not legible to Salsa, which complicates the invalidation story.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-perfperformance issuesC-ArchitectureBig architectural things which we need to figure up-front (or suggestions for rewrites :0) )C-tracking-issueCategory: tracking issue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions