Andreas Klebinger pushed to branch wip/andreask/fix-prof-segv at Glasgow Haskell Compiler / GHC

Commits:

4 changed files:

Changes:

  • compiler/GHC/StgToCmm/Bind.hs
    ... ... @@ -587,9 +587,8 @@ closureCodeBody top_lvl bndr cl_info cc args@(arg0:_) body fv_details
    587 587
                     -- ticky after heap check to avoid double counting
    
    588 588
                     ; tickyEnterFun cl_info
    
    589 589
                     ; enterCostCentreFun cc
    
    590
    -                    (CmmMachOp (mo_wordSub platform)
    
    591
    -                         [ CmmReg (CmmLocal node) -- See [NodeReg clobbered with loopification]
    
    592
    -                         , mkIntExpr platform (toTargetInt (fromDynTag (funTag platform cl_info))) ])
    
    590
    +                    (cmmUntag platform (CmmReg (CmmLocal node))) -- See [NodeReg clobbered with loopification]
    
    591
    +
    
    593 592
                     ; fv_bindings <- mapM bind_fv fv_details
    
    594 593
                     -- Load free vars out of closure *after*
    
    595 594
                     -- heap check, to reduce live vars over check
    

  • rts/Apply.cmm
    ... ... @@ -99,12 +99,14 @@ again:
    99 99
         W_  info;
    
    100 100
         P_ untaggedfun;
    
    101 101
         W_ arity;
    
    102
    +    W_ closure_type;
    
    102 103
         // We must obey the correct heap object observation pattern in
    
    103 104
         // Note [Heap memory barriers] in SMP.h.
    
    104 105
         untaggedfun = UNTAG(fun);
    
    105 106
         info = %INFO_PTR(untaggedfun);
    
    107
    +    closure_type = TO_W_( %INFO_TYPE(%STD_INFO(info)) );
    
    106 108
         switch [INVALID_OBJECT .. N_CLOSURE_TYPES]
    
    107
    -        (TO_W_( %INFO_TYPE(%STD_INFO(info)) )) {
    
    109
    +        (closure_type) {
    
    108 110
             case
    
    109 111
                 IND,
    
    110 112
                 IND_STATIC:
    
    ... ... @@ -212,10 +214,19 @@ again:
    212 214
                 // We can't use the value of 'info' any more, because if
    
    213 215
                 // STK_CHK_GEN() did a GC then the closure we're looking
    
    214 216
                 // at may have changed, e.g. a THUNK_SELECTOR may have
    
    215
    -            // been evaluated by the GC.  So we reload the info
    
    216
    -            // pointer now.
    
    217
    +            // been evaluated by the GC.
    
    218
    +            // We always reload reload the info pointer now. And if
    
    219
    +            // the closure type changed we need to take a different case
    
    220
    +            // alt altogether so we retry from the start in that case.
    
    221
    +
    
    217 222
                 untaggedfun = UNTAG(fun);
    
    218 223
                 info = %INFO_PTR(untaggedfun);
    
    224
    +            if(closure_type != TO_W_( %INFO_TYPE(%STD_INFO(info)) ) )
    
    225
    +            {
    
    226
    +              // ccall printf("closure type changed! (%d, %d)\n"
    
    227
    +              //             , closure_type, TO_W_( %INFO_TYPE(%STD_INFO(info)) ));
    
    228
    +              goto again;
    
    229
    +            }
    
    219 230
     
    
    220 231
                 jump %ENTRY_CODE(info)
    
    221 232
                     (stg_restore_cccs_eval_info, CCCS)
    

  • testsuite/tests/rts/T27123.hs
    1
    +{-# OPTIONS_GHC -ddump-cmm -ddump-stg-final -ddump-to-file -dsuppress-ticks #-}
    
    2
    +{-# OPTIONS_GHC -fno-full-laziness -fno-worker-wrapper #-}
    
    3
    +{-# LANGUAGE MagicHash, UnboxedTuples #-}
    
    4
    +
    
    5
    +-- This test checks that the auto-apply code (stg_ap_0_fast, stg_ap_p) is robust
    
    6
    +-- against another thread or the GC evaluating a closure at the same time.
    
    7
    +
    
    8
    +module Main
    
    9
    +    -- (main)
    
    10
    +where
    
    11
    +
    
    12
    +import Control.Monad
    
    13
    +import Control.Concurrent
    
    14
    +import System.IO
    
    15
    +import GHC.Data.SmallArray
    
    16
    +import GHC.Exts
    
    17
    +import GHC.IO
    
    18
    +
    
    19
    +type Arr = SmallMutableArray RealWorld (Int->Int)
    
    20
    +
    
    21
    +io :: (State# RealWorld -> (# State# RealWorld, a #)) -> IO a
    
    22
    +io f = IO f
    
    23
    +
    
    24
    +io_ :: (State# RealWorld -> State# RealWorld ) -> IO ()
    
    25
    +io_ f = IO (\s -> case f s of s2 -> (# s2, () #))
    
    26
    +
    
    27
    +{-# NOINLINE readSmallArray #-}
    
    28
    +readSmallArray (SmallMutableArray arr) (I# idx) = IO $ \s -> case readSmallArray# arr idx s of
    
    29
    +    (# s2, r #) -> (# s2, r #)
    
    30
    +
    
    31
    +-- Continually overwrites the array with unevaluated thunks that will evaluated to
    
    32
    +-- a PAP under profiling.
    
    33
    +{-# NOINLINE mkThunks #-}
    
    34
    +mkThunks :: Arr -> IO ()
    
    35
    +mkThunks arr = do
    
    36
    +    forever $ do
    
    37
    +      yield
    
    38
    +      forM_ [0..100] $ \_j -> do
    
    39
    +        forM_ [0..5 :: Int] $ \i -> do
    
    40
    +            -- With profiling results in a thunk that will evaluate to a PAP capturing the SCC
    
    41
    +            let g = {-# SCC g #-} succ
    
    42
    +            io_ (writeSmallArray arr i g)
    
    43
    +
    
    44
    +-- Evaluate the array repeatedly in the given order.
    
    45
    +{-# NOINLINE evaluateThks #-}
    
    46
    +evaluateThks :: Arr -> [Int] -> IO ()
    
    47
    +evaluateThks arr idxs = do
    
    48
    +    forever $ do
    
    49
    +        yield
    
    50
    +        -- putStr "." >> hFlush stdout
    
    51
    +        forM [0..5000::Int] $ \j -> do
    
    52
    +            forM_ idxs $ \i -> do
    
    53
    +                !g <- readSmallArray arr i
    
    54
    +                seq (g i) (pure ())
    
    55
    +
    
    56
    +main :: IO ()
    
    57
    +main = do
    
    58
    +    -- We spawn three threads. Two are evaluating the thunks in the array in opposite directions
    
    59
    +    -- One thread is
    
    60
    +    arr <- io (newSmallArray 6 (id))
    
    61
    +    _ <- forkIO $ do
    
    62
    +        evaluateThks arr [0..5]
    
    63
    +    _ <- forkIO $ do
    
    64
    +        evaluateThks arr [5,4..0]
    
    65
    +    forkIO $ mkThunks arr
    
    66
    +    threadDelay 30_000_000

  • testsuite/tests/rts/all.T
    ... ... @@ -687,3 +687,5 @@ test('ClosureTable',
    687 687
          ['-debug -O0 ClosureTable_c.c -I{top}/../rts -I{top}/../rts/include'])
    
    688 688
     
    
    689 689
     test('resizeMutableByteArrayInPlace', [req_cmm, extra_ways(['optasm', 'sanity']), only_ways(['optasm', 'sanity'])], compile_and_run, [''])
    
    690
    +
    
    691
    +test('T27123', [extra_ways(['optasm', 'prof'])], compile_and_run, [''])
    \ No newline at end of file