#2252: Extreme performance degradation on minor code change
----------------------+-----------------------------------------------------
 Reporter:  simona    |          Owner:                
     Type:  bug       |         Status:  new           
 Priority:  normal    |      Milestone:                
Component:  Compiler  |        Version:  6.8.2         
 Severity:  normal    |     Resolution:                
 Keywords:            |     Difficulty:  Unknown       
 Testcase:            |   Architecture:  x86_64 (amd64)
       Os:  Linux     |  
----------------------+-----------------------------------------------------
Comment (by simonpj):

 You made a mistake in the new `GoodPerform.hs`; you wrote
 {{{
   replicateM_ 1000 $ do
     --res1 <- fixpoint initial bottom bottom vn 1
     --unless (res1 `subset` res1) $ putStrLn "something's wrong"
     res2 <- fixpoint initial bottom bottom vn 1
     unless (res2 `subset` res2) $ putStrLn "something's wrong"
 }}}
 but you meant to use two calls to `replicateM_`, didn't you?

 Anyway I know what's going on.  Here is the crucial fragment of the two
 forms, after desguaring:
 {{{
 Bad:
   replicateM_ 1000 (f 10 >>= (\res1 -> f 20 >>= (\res2 -> return ())))

 Good:
   replicateM_ 1000 (f 10) >> replicateM_ 1000 (f 20)
 }}}
 The `f` is the `fixpoint` function; the `10` and `20` are the constant
 args to those two calls.  Just look at it!  The key point is that in both
 cases, the subexpression `(f 10)` is outside any lambdas, and hence is
 executed just once.  It's just as I said, although obscured by clutter:
 the computation is unaffected by IO state, so there is no need for it to
 be repeated each time.

 Furthermore, in the `good` case, the call `(f 20)` is '''also#'' outside
 any lambdas, and ''hence is computed only once''. But in the `bad` case,
 the call `(f 20)` is inside the `(\ res1 -> ...)` abstraction, and so is
 computed once for each call of the (\res1...); that is 1000 times.

 So that's why there's the big difference.  It is a little puzzling, but it
 becomes much clearer when you desugar the do-notation.

 The moral, as often, is that if you put a constant expression inside a
 loop, GHC will often compute it just once.  But this occurs much more
 often in benchmarks than in real programs

 Simon

-- 
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/2252#comment:7>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
_______________________________________________
Glasgow-haskell-bugs mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs

Reply via email to