#367: Infinite loops can hang Concurrent Haskell
------------------------------------------+---------------------------------
  Reporter:  simonpj                      |          Owner:  ezyang             
 
      Type:  bug                          |         Status:  new                
 
  Priority:  lowest                       |      Milestone:  _|_                
 
 Component:  Compiler                     |        Version:  6.4.1              
 
Resolution:  None                         |       Keywords:  scheduler 
allocation
        Os:  Unknown/Multiple             |   Architecture:  Unknown/Multiple   
 
   Failure:  Incorrect result at runtime  |     Difficulty:  Unknown            
 
  Testcase:                               |      Blockedby:                     
 
  Blocking:                               |        Related:                     
 
------------------------------------------+---------------------------------
Changes (by ezyang):

  * owner:  => ezyang


Comment:

 It turns out the stupid implementation is actually pretty fast.

 {{{diff --git a/compiler/codeGen/StgCmmHeap.hs
 b/compiler/codeGen/StgCmmHeap.hs
 index fb37391..a70d132 100644
 --- a/compiler/codeGen/StgCmmHeap.hs
 +++ b/compiler/codeGen/StgCmmHeap.hs
 @@ -557,15 +557,22 @@ do_checks checkStack alloc do_gc = do
      hp_oflo = CmmMachOp (mo_wordUGt dflags)
                          [CmmReg hpReg, CmmReg (CmmGlobal HpLim)]

 +    -- Yielding if HpLim == 0
 +    yielding = CmmMachOp (mo_wordEq dflags)
 +                        [CmmReg (CmmGlobal HpLim), CmmLit (zeroCLit
 dflags)]
 +
      alloc_n = mkAssign (CmmGlobal HpAlloc) alloc_lit
    gc_id <- newLabelC

    when checkStack $ do
       emit =<< mkCmmIfGoto sp_oflo gc_id

 -  when (alloc /= 0) $ do
 -     emitAssign hpReg bump_hp
 -     emit =<< mkCmmIfThen hp_oflo (alloc_n <*> mkBranch gc_id)
 +  if (alloc /= 0)
 +    then do
 +      emitAssign hpReg bump_hp
 +      emit =<< mkCmmIfThen hp_oflo (alloc_n <*> mkBranch gc_id)
 +    else do
 +      emit =<< mkCmmIfThen yielding (alloc_n <*> mkBranch gc_id)

    emitOutOfLine gc_id $
       do_gc -- this is expected to jump back somewhere
 }}}

 A totally unscientific benchmark on

 {{{
 module Main where

 import qualified Data.Vector as U

 main = U.sum (U.enumFromTo 1 (1000000000 :: Int)) `seq` return ()
 }}}

 yields this C--

 {{{
  Main.main1_entry()
          { [(c1Zm,
              Main.main1_info:
                  const 65539;
                  const 0;
                  const 15;),
             (c1Zn,
              block_c1Zn_info:
                  const 0;
                  const 32;)]
          }
      c1Zm:
          if (Sp - 12 < SpLim) goto c1Zv;
          if (HpLim == 0) goto c1Zu;
          I32[Sp - 8] = 0;
          I32[Sp - 12] = 1;
          I32[Sp - 4] = c1Zn;
          Sp = Sp - 12;
          jump Main.main_$s$wfoldlM'_loop_info; // []
      c1Zu:
          HpAlloc = 0;
          goto c1Zv;
      c1Zv:
          R1 = Main.main1_closure;
          jump stg_gc_fun; // [R1]
      c1Zn:
          if (HpLim == 0) goto c1ZC;
          R1 = GHC.Tuple.()_closure+1;
          Sp = Sp + 4;
          jump I32[Sp]; // [R1]
      c1ZC:
          HpAlloc = 0;
          R1 = R1;
          jump stg_gc_unbx_r1; // [R1]
 }}}

 which is only about 10% slower.

 Unfortunately, if you want to guarantee things don't hang, it's not enough
 to compile the untrusted code like this; all the other code needs to have
 this transformation applied too. So we should probably have a -yielding
 flag (like -threaded or -profiling) which allows us to compile "yielding"
 versions of all relevant code.  Unfortunately, the number of combinations
 of such flags exponentially increases...

-- 
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/367#comment:17>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler

_______________________________________________
Glasgow-haskell-bugs mailing list
Glasgow-haskell-bugs@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs

Reply via email to