We've started to get reports that with Persistent 0.8, compile times
for the Model file can be very large, sometimes non-terminating. I've
just spent a fair bit of time investigating, and as far as I can tell,
the problem is *not* coming from our TH code. When I turn on
-ddump-splices, all of the generated code is output almost
immediately. This implies very strongly to me that the problem is
coming from GHC itself. We've also discovered that playing around with
optimization options can drastically change results, which fits into
this theory pretty well. Unfortunately, I haven't been able to create
a reproducible test case separated out from a scaffolding, which leads
me to believe this is being triggered from a combination of many
issues.
So the question is: what can we do? I see a few options:
1. Fix GHC. This will be difficult and time consuming, but we should
definitely try to do it.
2. Figure out what changes went into Persistent 0.7/0.8 to trigger the
problem, and revert it. This is not really an optimal solution, since
we're tying out hands with what features we can implement.
3. Ditch TH entirely, and instead use code generation.
I'm actually very much in favor of (3). Even if we weren't running
into problems right now, I think we'd want to explore this possibility
anyway, since it can make it much easier to debug code. I've
considered this possibility in the past for Shakespeare as well, but
that would be much more invasive.
Since this bug has currently held up my development of another
project, I'm going to get working on (3) immediately. If anyone has
input on this, please let me know.
Meanwhile, I don't think we should let this issue hold up the 0.10
release. This change is very orthogonal to the Yesod library, and will
only affect the scaffolding.
Michael
What happens if you split TH code in on module Model.Entity and the
rest on Model.Rest? If that doesn't help, what if you add
{-# GHC_OPTIONS -O0 #-}
to one of these files?
I'd love to test this on our project but we're already carrying quite
a burden in terms of maintenance because of the
Yesod-0.10-which-is-not-0.10 situation, so I won't be able to test
this until The-Real-True-Yesod-0.10 gets released today =).
Regarding (3), I wouldn't like having another preprocessor unless it
had a clear advantage over TH code.
Cheers!
--
Felipe.
No effect.
> I'd love to test this on our project but we're already carrying quite
> a burden in terms of maintenance because of the
> Yesod-0.10-which-is-not-0.10 situation, so I won't be able to test
> this until The-Real-True-Yesod-0.10 gets released today =).
I'm running the release scripts now. It should be available within the hour.
> Regarding (3), I wouldn't like having another preprocessor unless it
> had a clear advantage over TH code.
Well, the clear advantages of this approach would be:
* No performance issues
* Easy to inspect the generated code
The second point is why I've been wanting to do it for a while, the
first one is what's forcing my hand right now.
Michael
This seems to do the trick:
{-# OPTIONS_GHC -O0 -fmax-simplifier-iterations=0 #-}
Only the file with the TH code needs this.
Cheers,
--
Felipe.
Sorry, but that doesn't work. For some reason, when linking I get
unknown symbol `persistentzm0zi8zi0_DatabaseziPersistziEntityDef_DBName_info'
However,
{-# OPTIONS_GHC -O0 -fmax-simplifier-iterations=1 #-}
seems to work. Not as fast as the broken option, but better than nothing =).
Cheers,
--
Felipe.
Thank you! That seems to have let me build the file, though it was a
very long build. I still want to look into code generation as an
alternative to the TH, but at least there's no urgent need for it now.
Can anyone else who's been experiencing the long compile times confirm
that this helps the problem? If so, I think we should update the
scaffolding to include it.
Michael
BTW, you may put "-v3" on the options to see which phase is slow.
Cheers,
--
Felipe.
Is there some reasonable way to incorporate a code generation step in
packages built by Cabal(-install)? I seem to recall trying to find one
and failing miserably.
(This was some time ago, so things may have changed -- hopefully for the
better.)
Regards,
There's some ability to have a code formatter (I don't remember the
exact term for it), which might be the approach we take. On the other
hand, we already have `yesod build` which is tied in to `yesod devel`,
so it might be sufficient to go down that route.
Michael
Ah, yes, I vaguely recall GHC having support for a pragma to specify a
preprocessor (I think that was the term) for the file -- this
preprocessor could of course transform the file to something completely
different (Haskell source). I wonder if that would work for Hackage,
though -- as I recall, the preprocessor had to be an existing binary on
the system.
Anyway, if you discover an elegant and simple way to get this working
with Hackage and cabal-install, I'd love a blog post detailing the
solution :).
Keep up the good work,
B�r�ur
Cheers,
--
Felipe.
Unfortunately, the splices dumped by GHC are not properly formatted
Haskell code. I started doing what you mention, but it would take a
non-trivial amount of time to fix up the definitions spat out.
Michael
(Aside)
Ok, I was wondering about that. I was looking at the splices generated
by Persist.Quasi and was worried that it was using language extensions
that would take me weeks to figure out...
Thanks for your effort!
> I noticed that the migrateAll function (starting at line 972) seems
> to be very inefficient. We call 'migrate' for every datatype in the
> models file, but the first parameter of migrate (which is a
> [EntityDef]) is always identical, only the second parameter varies.
>
> So for testing purposes I abstracted out the first parameter of
> 'migrate' into a top-level definition and passed that into all calls
> of migrate. And now the file compiles fine, though it still takes
> about 40seconds.
Looks like a low hanging fruit, so I'm going to fix it right now.
Thanks!
--
Felipe.
Fixed on git master [1]. It's now possible to compile persistent-test
with -O =).
Cheers,
[1] https://github.com/yesodweb/persistent/commit/fded3a6a896854e09af2f28ea5d6f5d8a5929ad3
--
Felipe.
Actually, we can do even better on mkMigrate. Instead of repeating
all those boring definitions, now we just use "entityDef (undefined ::
Entity)" [2].
Cheers =), and sorry for the spam,
[2] https://github.com/yesodweb/persistent/commit/2ba16667d711bca821322cb60b24bb957f299ea7
--
Felipe.
Wow, that makes things *much* better. Any reason not to upload this to Hackage?
Michael
Yep: I forgot =).
Cheers,
--
Felipe.
For the slower kids who are still running yesod 0.10 from a week or so
ago? How, how, how do I get this?
--
Darrin
On which version of GHC does it work? As for me, it compiles with GHC
7.2.1, but with 7.4.1 it gives something like
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package array-0.4.0.0 ... linking ... done.
Loading package deepseq-1.3.0.0 ... linking ... done.
Loading package old-locale-1.0.0.4 ... linking ... done.
Loading package time-1.4 ... linking ... done.
Loading package containers-0.4.2.1 ... linking ... done.
Loading package bytestring-0.9.2.1 ... linking ... done.
Loading package text-0.11.1.12 ... linking ... done.
Loading package attoparsec-0.10.1.1 ... linking ... done.
Loading package blaze-builder-0.3.1.0 ... linking ... done.
Loading package dlist-0.5 ... linking ... done.
Loading package hashable-1.1.2.3 ... linking ... done.
Loading package transformers-0.2.2.0 ... linking ... done.
Loading package mtl-2.0.1.0 ... linking ... done.
Loading package syb-0.3.6 ... linking ... done.
Loading package pretty-1.1.1.0 ... linking ... done.
Loading package template-haskell ... linking ... done.
Loading package unordered-containers-0.1.4.6 ... linking ... done.
Loading package primitive-0.4.1 ... linking ... done.
Loading package vector-0.9.1 ... linking ... done.
Loading package aeson-0.6.0.0 ... linking ... done.
Loading package base-unicode-symbols-0.2.2.3 ... linking ... done.
Loading package transformers-base-0.4.1 ... linking ... done.
Loading package monad-control-0.3.1 ... linking ... done.
Loading package base64-bytestring-0.1.1.0 ... linking ... done.
Loading package blaze-html-0.4.3.1 ... linking ... done.
Loading package lifted-base-0.1.0.3 ... linking ... done.
Loading package conduit-0.2.1 ... linking ... done.
Loading package path-pieces-0.1.0 ... linking ... done.
Loading package stm-2.2.0.1 ... linking ... done.
Loading package resource-pool-0.2.1.0 ... linking ... done.
Loading package pool-conduit-0.0.0.1 ... linking ... done.
Loading package persistent-0.8.0 ... linking ... done.
Loading package persistent-template-0.8.1.1 ... linking ... done.
and stops while eating about 100% CPU and 150Mb RAM.
Both 7.2.1 and 7.4.1 run on Debian amd64, but 7.2.1 is run on my desktop
(Debian testing/unstable, 4GB RAM), while 7.4.1 is run on relatively
clean VM (Debian testing, 1GB RAM).
WBR, Ilya Portnov.
The improvement should work on all GHC versions, but that doesn't mean
that it completely solves the problem.
Could you try putting
{-# OPTIONS_GHC -v3 #-}
as the first line on the offending file in order to see where GHC is
spending time?
Cheers,
--
Felipe.
and stops...
WBR, Ilya Portnov.
So it seems that GHC 7.4 is not behaving the same away as GHC 7.0. I
was seeing the simplifier taking quite some time. Also, -v3 seems to
show less output info, but I don't know which output level would be
better.
--
Felipe.
Yes, on other systems I've seen that simplification took much time with
same code. I think, here problem is in the simplification phase too.
WBR, Ilya Portnov.
Types: http://paste.in.ua/3877/
Entities: http://paste.in.ua/3878/
WBR, Ilya Portnov.
Is there a fix in the works for GHC and/or Persistent? Looks like I
upgraded to GHC 7.4.1 just in time to preserve the slowness. :-)
(addDependentFile is worth it though.)
--
Darrin