Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.
Sign upOptimise isReserved #46
Conversation
This function is called many thousands of times by ghcide and was a hotspot in profiling. This patch reduced time taken on one benchmark which called hover 1000 times from 259 seconds to 170 seconds.
This comment has been minimized.
This comment has been minimized.
fendor
commented
Jan 26, 2020
|
Maybe it makes sense to add this information as a comment? So that feature devs understand why this optimisation has been done? |
This comment has been minimized.
This comment has been minimized.
AndreasPK
commented
Jan 27, 2020
|
mpickering showed this patch off to me so I look at the code a bit.
Before this patch it compiled to this core: = \ (c1_abyn :: Char) ->
case GHC.List.elem
@ Char
ghc-prim-0.5.3:GHC.Classes.$fEqChar
c1_abyn
Network.URI.isAllowedInURI5
of {
False ->
GHC.List.elem
@ Char
ghc-prim-0.5.3:GHC.Classes.$fEqChar
c1_abyn
Network.URI.isAllowedInURI3;
True -> ghc-prim-0.5.3:GHC.Types.True
}essentially elem c foo || elem c bar With this patch isReserved compiles to this: Network.URI.$wisReserved
= \ (ww_sq86 :: ghc-prim-0.5.3:GHC.Prim.Char#) ->
case ww_sq86 of {
__DEFAULT -> ghc-prim-0.5.3:GHC.Types.False;
'!'# -> ghc-prim-0.5.3:GHC.Types.True;
'#'# -> ghc-prim-0.5.3:GHC.Types.True;
'$'# -> ghc-prim-0.5.3:GHC.Types.True;
'&'# -> ghc-prim-0.5.3:GHC.Types.True;
'\''# -> ghc-prim-0.5.3:GHC.Types.True;
'('# -> ghc-prim-0.5.3:GHC.Types.True;
')'# -> ghc-prim-0.5.3:GHC.Types.True;
'*'# -> ghc-prim-0.5.3:GHC.Types.True;
'+'# -> ghc-prim-0.5.3:GHC.Types.True;
','# -> ghc-prim-0.5.3:GHC.Types.True;
'/'# -> ghc-prim-0.5.3:GHC.Types.True;
':'# -> ghc-prim-0.5.3:GHC.Types.True;
';'# -> ghc-prim-0.5.3:GHC.Types.True;
'='# -> ghc-prim-0.5.3:GHC.Types.True;
'?'# -> ghc-prim-0.5.3:GHC.Types.True;
'@'# -> ghc-prim-0.5.3:GHC.Types.True;
'['# -> ghc-prim-0.5.3:GHC.Types.True;
']'# -> ghc-prim-0.5.3:GHC.Types.True
}The former has overhead of two function calls, and the actual checking loops. The later has no overhead + results in a binary search for the pattern match. As a result the later is about 10 times as fast in a simple benchmark like this: env (return "http://ex.it/foo/bar/baz/bap") $ \u1 ->
bench "u1" $ nf (map (isReserved)) u1,Currently processing one character like this takes somewhere between 100 and 150ns. After this patch it takes 10ns and 15ns. |
This comment has been minimized.
This comment has been minimized.
osa1
commented
Jan 27, 2020
|
Amazing.
Agreed, someone in a few months will look at this code and say "why not use |
| ',' -> True | ||
| ';' -> True | ||
| '=' -> True | ||
| _ -> False | ||
|
|
||
| subDelims :: URIParser String | ||
| subDelims = (:[]) <$> oneOf "!$&'()*+,;=" |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
osa1
commented
Jan 27, 2020
|
This may be a bug in |
This comment has been minimized.
This comment has been minimized.
|
It would be great if the compiler did the right thing for the |
mpickering commentedJan 26, 2020
This function is called many thousands of times by ghcide and was a
hotspot in profiling.
This patch reduced time taken on one benchmark which called hover 1000
times from 259 seconds to 170 seconds.
See digital-asset/ghcide#101