Skip to content
This repository has been archived by the owner on Jan 2, 2021. It is now read-only.

Improve performance by caching conversion to NormalizedUri #384

Merged
merged 3 commits into from
Jan 28, 2020

Conversation

mpickering
Copy link
Contributor

Two changes in this patch make performance quite a lot better for all actions.

  1. Cache the conversion to NormalizedUri from NormalizedFilePath
  2. Use a hash map for the debouncer to take advantage of the fast hash instance of NormalizedUri.

The cached Hashable instance is in this PR: haskell/lsp#214

My benchmark which ran hover 1000 times went down from 259s to 37s including initialisation time. Hovering on large projects is not noticeably faster (1s vs < 0.1s).

Reviewer: @pepeiborra

Note: I removed the Eq/Ord instance from Pepe's original patch because they relied on the hash for comparing equality. There are some hotspots on the latest profile from

image

image

This conversion is quite expensive to repeat multiple times. Therefore
we cache it when creating a NormalizedFilePath so it's only computed
once.

Making this change causes a benchmark which calls hover 1000 times to go
down from 259s to 44s.
NormalizedUri is the primary key type for the debouncer which will have
a cached hash in the next haskell-lsp release.
@mpickering
Copy link
Contributor Author

Branch with the change which tracks the haskell-lsp is here - https://github.com/mpickering/ghcide/tree/perf-haskell-lsp

deriving (Show, Generic, Eq, Ord)

instance NFData NormalizedUriWrapper where
rnf = rwhnf
Copy link
Collaborator

Choose a reason for hiding this comment

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

That NFData instance isn't correct either. Can we just lose it?

@ndmitchell does Shake care about these NFData instances?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Nevermind, it is fine

@pepeiborra
Copy link
Collaborator

Looks good to me!

Copy link
Collaborator

@cocreature cocreature left a comment

Choose a reason for hiding this comment

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

Awesome, thank you so much for working on this!

--
-- This is one of the most performance critical parts of ghcide, do not
-- modify it without profiling.
data NormalizedFilePath = NormalizedFilePath NormalizedUriWrapper Int !FilePath
Copy link
Collaborator

Choose a reason for hiding this comment

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

Similar question as for the haskell-lsp PR. Should we make the first two fields or at least the hash strict and unpack it?

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 can see the argument for making the hash strict but not the NormalizedUriWrapper as that is quite expensive to compute if you never use it.

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 made the hash strict.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks!

@cocreature cocreature merged commit 7309062 into haskell:master Jan 28, 2020
@mpickering mpickering deleted the hover-performance branch January 28, 2020 18:24
pepeiborra pushed a commit to pepeiborra/ghcide that referenced this pull request Feb 1, 2020
* Cache conversion to NormalizedUri from NormalizedFilePath

This conversion is quite expensive to repeat multiple times. Therefore
we cache it when creating a NormalizedFilePath so it's only computed
once.

Making this change causes a benchmark which calls hover 1000 times to go
down from 259s to 44s.

* Use a HashMap rather than a Map for debouncer

NormalizedUri is the primary key type for the debouncer which will have
a cached hash in the next haskell-lsp release.

* NormalizedFilePath: Make the hash strict so it can be unpacked
pepeiborra pushed a commit to pepeiborra/ide that referenced this pull request Dec 29, 2020
…hcide#384)

* Cache conversion to NormalizedUri from NormalizedFilePath

This conversion is quite expensive to repeat multiple times. Therefore
we cache it when creating a NormalizedFilePath so it's only computed
once.

Making this change causes a benchmark which calls hover 1000 times to go
down from 259s to 44s.

* Use a HashMap rather than a Map for debouncer

NormalizedUri is the primary key type for the debouncer which will have
a cached hash in the next haskell-lsp release.

* NormalizedFilePath: Make the hash strict so it can be unpacked
pepeiborra pushed a commit to pepeiborra/ide that referenced this pull request Dec 29, 2020
…hcide#384)

* Cache conversion to NormalizedUri from NormalizedFilePath

This conversion is quite expensive to repeat multiple times. Therefore
we cache it when creating a NormalizedFilePath so it's only computed
once.

Making this change causes a benchmark which calls hover 1000 times to go
down from 259s to 44s.

* Use a HashMap rather than a Map for debouncer

NormalizedUri is the primary key type for the debouncer which will have
a cached hash in the next haskell-lsp release.

* NormalizedFilePath: Make the hash strict so it can be unpacked
pepeiborra pushed a commit to pepeiborra/ide that referenced this pull request Dec 29, 2020
…hcide#384)

* Cache conversion to NormalizedUri from NormalizedFilePath

This conversion is quite expensive to repeat multiple times. Therefore
we cache it when creating a NormalizedFilePath so it's only computed
once.

Making this change causes a benchmark which calls hover 1000 times to go
down from 259s to 44s.

* Use a HashMap rather than a Map for debouncer

NormalizedUri is the primary key type for the debouncer which will have
a cached hash in the next haskell-lsp release.

* NormalizedFilePath: Make the hash strict so it can be unpacked
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants