Greetings, The attached patch is a two-step optimization: 1) Only call 'getType' 100,000,000 times instead of 600,000,000 times. 2) Greatly simplify the actual loop. Without this patch, compiling base-1.0.hl takes 19 minutes. With this patch, compile time is down to 11 minutes. Feedback would be greatly appreciated. -- Cheers, Lemmih
On Fri, Feb 15, 2008 at 03:34:59PM +0100, Lemmih wrote:
Greetings,
The attached patch is a two-step optimization: 1) Only call 'getType' 100,000,000 times instead of 600,000,000 times. 2) Greatly simplify the actual loop.
Without this patch, compiling base-1.0.hl takes 19 minutes. With this patch, compile time is down to 11 minutes. Feedback would be greatly appreciated.
thanks, Yeah, there is some questionable algorithmic stuff in the typechecker/optimizer. in particular I know System.Time hits some exponential behavior (I believe dealing with the large datatpe and its derived instances) I am not including the Maybe patch as I have a different one that reorganizes more of the libraries to help reduce the 'Prelude glut', the big mass of mutually recursive modules that include prelude. PS. could you send patches via 'darcs send'? that way my scripts will automatically be able to apply them. John -- John Meacham - ⑆repetae.net⑆john⑈
Actually what I really need to do to make issues like that maybe thing from coming up is allow derived instances to happen at a place other than where the type is delared. pulling in 'Read' to declare Bool just doesn't work that well. and I don't like all these manually written instances cluttering up the libraries.. perhaps a pragma.. like {-# DERIVE: Enum Bool #-}. or putting "deriving 'Read'" will just add a placeholder that will be expanded to a real derivation when the read class comes into scope. though, that is sort of hacky as I would have to fudge namespace resolution in deriving clauses. do other compilers do something clever here? it looks like ghc does what I do but with CPP tricks and basically writes out its own instances in full. John -- John Meacham - ⑆repetae.net⑆john⑈
John Meacham wrote:
Actually what I really need to do to make issues like that maybe thing from coming up is allow derived instances to happen at a place other than where the type is delared. pulling in 'Read' to declare Bool just doesn't work that well. and I don't like all these manually written instances cluttering up the libraries..
perhaps a pragma.. like {-# DERIVE: Enum Bool #-}. or putting "deriving 'Read'" will just add a placeholder that will be expanded to a real derivation when the read class comes into scope. though, that is sort of hacky as I would have to fudge namespace resolution in deriving clauses.
now that GHC has "standalone deriving" syntax, standalone deriving might be something to start from
do other compilers do something clever here? it looks like ghc does what I do but with CPP tricks and basically writes out its own instances in full.
John
On Fri, Feb 15, 2008 at 03:34:59PM +0100, Lemmih wrote:
The attached patch is a two-step optimization: 1) Only call 'getType' 100,000,000 times instead of 600,000,000 times. 2) Greatly simplify the actual loop.
Without this patch, compiling base-1.0.hl takes 19 minutes. With this patch, compile time is down to 11 minutes. Feedback would be greatly appreciated.
I am confused, what in the patch causes getType to be called less? As far as I can tell it is just replacing equality checks with 'isFoo' predicates. John -- John Meacham - ⑆repetae.net⑆john⑈
On Sat, Feb 16, 2008 at 12:45 AM, John Meacham
On Fri, Feb 15, 2008 at 03:34:59PM +0100, Lemmih wrote:
The attached patch is a two-step optimization: 1) Only call 'getType' 100,000,000 times instead of 600,000,000 times. 2) Greatly simplify the actual loop.
Without this patch, compiling base-1.0.hl takes 19 minutes. With this patch, compile time is down to 11 minutes. Feedback would be greatly appreciated.
I am confused, what in the patch causes getType to be called less? As far as I can tell it is just replacing equality checks with 'isFoo' predicates.
E.Values.isCheap checks whether its argument is atomic. The 'isAtomic' function is very expensive so I moved it down below the four static checks. -- Cheers, Lemmih
On Sat, Feb 16, 2008 at 12:52:30AM +0100, Lemmih wrote:
On Sat, Feb 16, 2008 at 12:45 AM, John Meacham
wrote: On Fri, Feb 15, 2008 at 03:34:59PM +0100, Lemmih wrote:
The attached patch is a two-step optimization: 1) Only call 'getType' 100,000,000 times instead of 600,000,000 times. 2) Greatly simplify the actual loop.
Without this patch, compiling base-1.0.hl takes 19 minutes. With this patch, compile time is down to 11 minutes. Feedback would be greatly appreciated.
I am confused, what in the patch causes getType to be called less? As far as I can tell it is just replacing equality checks with 'isFoo' predicates.
E.Values.isCheap checks whether its argument is atomic. The 'isAtomic' function is very expensive so I moved it down below the four static checks.
Ah, I see now. cool. there are probably other ones in there that can be moved around to improve speed. isAtomic was very cheap once upon a time.. but now the isFullyConst was added... It _may_ be possible to have isFullyConst only look one layer deep, since an invariant that is supposed to hold is that a constructor can only hold atomic arguments, hence any Literals under another one must be fully constant. However, I am not sure if that invarient is rigidly enforced through all compilation phases. like, there is a progression of transformations through normal forms, each one more strict than the last... hmm... perhaps a way to test would be for isAtomic only look a single layer deep but isFullyConst will do a full check. and isAtomic can do a 'isFullyConst' check only when -flint mode is enabled. We will probably have to go thorugh and change some isAtomics to isFullyConst depending on whether the code is known to be in normal form beforehand or not. John -- John Meacham - ⑆repetae.net⑆john⑈
On Feb 16, 2008 3:13 AM, John Meacham
On Sat, Feb 16, 2008 at 12:52:30AM +0100, Lemmih wrote:
On Sat, Feb 16, 2008 at 12:45 AM, John Meacham
wrote: On Fri, Feb 15, 2008 at 03:34:59PM +0100, Lemmih wrote:
The attached patch is a two-step optimization: 1) Only call 'getType' 100,000,000 times instead of 600,000,000 times. 2) Greatly simplify the actual loop.
Without this patch, compiling base-1.0.hl takes 19 minutes. With this patch, compile time is down to 11 minutes. Feedback would be greatly appreciated.
I am confused, what in the patch causes getType to be called less? As far as I can tell it is just replacing equality checks with 'isFoo' predicates.
E.Values.isCheap checks whether its argument is atomic. The 'isAtomic' function is very expensive so I moved it down below the four static checks.
Ah, I see now. cool. there are probably other ones in there that can be moved around to improve speed.
No, 'isAtomic'/'isCheap' takes less than a single percent right now. Optimizing it more will be a waste of time.
isAtomic was very cheap once upon a time.. but now the isFullyConst was added...
Actually, 'isFullyConst' is insignificant. It was 'getType', called multiple times from 'sortTypeLike' and 'sortKindLike', that took most of the CPU time.
It _may_ be possible to have isFullyConst only look one layer deep, since an invariant that is supposed to hold is that a constructor can only hold atomic arguments, hence any Literals under another one must be fully constant.
'isFullyConst' is deliciously fast. It plays right at GHC's strengths. It compiles to a finely tuned loop that performs essentially no allocations. The code is very pretty and easy to understand; let's keep it that way.
However, I am not sure if that invarient is rigidly enforced through all compilation phases. like, there is a progression of transformations through normal forms, each one more strict than the last... hmm...
perhaps a way to test would be for isAtomic only look a single layer deep but isFullyConst will do a full check. and isAtomic can do a 'isFullyConst' check only when -flint mode is enabled. We will probably have to go thorugh and change some isAtomics to isFullyConst depending on whether the code is known to be in normal form beforehand or not.
The functions 'isAtomic', 'isFullyConst' and 'getType' are ridiculously cheap right now. They only check constructors without doing any allocation. With GHC's pointer tagging, this is as fast as hand tuned C code. Our attention should be diverted elsewhere. About 60% of the CPU time when compiling the base library goes to garbage collecting. The majority of garbage is created when converting from IdMap to IdSet and from 'IdMap a' to 'IdMap (Maybe a)'. Fixing these issues should give at least a factor of 2 in performance increase. -- Cheers, Lemmih
On Feb 15, 2008 3:34 PM, Lemmih
Greetings,
The attached patch is a two-step optimization: 1) Only call 'getType' 100,000,000 times instead of 600,000,000 times. 2) Greatly simplify the actual loop.
Without this patch, compiling base-1.0.hl takes 19 minutes. With this patch, compile time is down to 11 minutes. Feedback would be greatly appreciated.
Greetings, The attached patch optimizes the allocation of new ids in substitutions. Without this patch, compiling base-1.0.hl takes 11 minutes (down from 19). With this patch, compile time is down to 6 minutes. Feedback would be greatly appreciated. -- Cheers, Lemmih
Hiya, This patch pushes compile time down below 5 minutes. -- Cheers, Lemmih
participants (3)
-
Isaac Dupree -
John Meacham -
Lemmih