Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Terrible performance with singletonized maps #375

Open
treeowl opened this issue Dec 19, 2018 · 4 comments
Open

Terrible performance with singletonized maps #375

treeowl opened this issue Dec 19, 2018 · 4 comments

Comments

@treeowl
Copy link

treeowl commented Dec 19, 2018

Just for fun, I decided to try porting Data.Map to singletons. I know, that's crazy. Here's the code. It takes a while to compile that, but that doesn't bother me. What does bother me is that generating even a relatively small map takes an incredibly long time.

{-# language ScopedTypeVariables, TypeInType #-}
module TestSingMap where

import Data.Singletons
import qualified Data.Singletons.Prelude as P
import Data.Singletons.Prelude.Foldable
import SingMap

type Foo = FromList (P.Zip ((P.EnumFromTo 1 50)) (P.Replicate 50 "a"))
foo :: Sing Foo
foo = sing

type Bar = Smallest Foo

bar :: Sing Bar
bar = sing

I don't really know where things go sideways, but -ddump-tc-trace seems to show some truly enormous coercion signatures even when the list is cut from 50 elements down to 5.

@treeowl
Copy link
Author

treeowl commented Dec 19, 2018

It's not actually necessary to build any singletons to get sluggish performance either.

goo :: Bar :~: 'Just ('(1, "a"))
goo = Refl

will take a while too.

@RyanGlScott
Copy link
Collaborator

I'm not sure what you mean by "sluggish performance" here. Are you talking about the runtime performance? If so, then I'm not able to reproduce the issue, since the following:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
module Main where

import qualified Data.Singletons.Prelude as P
import Data.Singletons.Prelude.Foldable
import Data.Type.Equality
import SingMap

type Foo = FromList (P.Zip ((P.EnumFromTo 1 50)) (P.Replicate 50 "a"))
type Bar = Smallest Foo

goo :: Bar :~: 'Just ('(1, "a"))
goo = Refl
                                                                                                   
main :: IO ()                                                                                      
main = print goo

Runs quite quickly for me (after compiling):

$ time cabal new-run bug
Up to date
Refl

real    0m0.032s
user    0m0.030s
sys     0m0.000s

If you're talking about the compile times, then yes, that's likely to be quite slow. Unfortunately, I don't know of a way to mitigate this on singletons' end, as GHC's compilation of type families in general tends to be rather slow.

@treeowl
Copy link
Author

treeowl commented Dec 19, 2018

Compilation (even with -O0) is unusably slow for maps with a few hundred elements. I don't know enough about the underlying compiler performance problems to know whether there's likely to be a way to work around them for code like this, or even for this specific code.

@goldfirere
Copy link
Owner

I agree with Ryan on this. I think it's GHC's problem. It's quite common for GHC to produce quadratically-sized code for type-family heavy shenanigans. And because the code produced is quadratic, that means that every core pass, etc., is quadratic, too. There is a fix: (#8095)[https://ghc.haskell.org/trac/ghc/ticket/8095]. @bgamari was working on this and may have only a little bit further to go. Keeping open as I do think we should add this to our testsuite.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants