[Git][ghc/ghc][wip/ghc-debug] 8 commits: Decode CostCentreStacks, CostCentres and InfoTables (#18405)
Sven Tennie
gitlab at gitlab.haskell.org
Sat Aug 22 12:26:52 UTC 2020
Sven Tennie pushed to branch wip/ghc-debug at Glasgow Haskell Compiler / GHC
Commits:
43194225 by Sven Tennie at 2020-08-22T13:48:33+02:00
Decode CostCentreStacks, CostCentres and InfoTables (#18405)
These are the data structures used by profiling, i.e. they are only
available when the RTS is used with `-prof`. Otherwise fetching them
results into `Nothing`.
To reduce unnecessary decoding, a state monad transformer is used to
provide caching for CostCentres.
Because the three types form a circular data structure, loop-breakers
are applied to prevent endless decoding loops.
- - - - -
e944ff9b by Sven Tennie at 2020-08-22T14:05:46+02:00
Use more precise types in tests (#18405)
Use `Ptr ()` instead of `Word` to communicate that addresses/pointers
are meant.
- - - - -
06e0567f by Sven Tennie at 2020-08-22T14:05:46+02:00
Introduce LiftedClosure (#18405)
This is a representation for closures that do not have a representation
in the Haskell language. I.e. things like StgTSOs.
- - - - -
80ade003 by Sven Tennie at 2020-08-22T14:05:46+02:00
Expect stack_marking starting from GHC 8.10 (#18405)
This field was introduced with GHC 8.10.
- - - - -
b8e3c5c8 by Sven Tennie at 2020-08-22T14:05:46+02:00
Add WhatNext, WhyBlocked and TsoFlags to TSO closure (#18405)
These constants can easily be decoded to sum types.
Additionally extract TestUtils with common test functions.
- - - - -
e30edec6 by Sven Tennie at 2020-08-22T14:05:46+02:00
END_TSO_QUEUE is not a closure type on it's own (#18405)
Indeed it's a CONSTR_NOCAF.
- - - - -
5ee63586 by Sven Tennie at 2020-08-22T14:05:46+02:00
Rename boundTaskExiting and getTask (#18405)
Both are directly related to myTask, which the new names now reflect.
- - - - -
929c5c33 by Sven Tennie at 2020-08-22T14:05:46+02:00
Mark unsafe accesses (#18405)
StgTSO and StgStack are very dynamic by nature. Accesses to outdated
pointers lead to segmentation faults or absolutely wrong results.
So, make sure (by naming) that the users nows about these facts.
The safe way to access these fields it to stop the RTS via RTS API.
- - - - -
24 changed files:
- compiler/GHC/ByteCode/Types.hs
- compiler/GHC/Runtime/Interpreter.hs
- includes/rts/Task.h
- libraries/ghc-heap/GHC/Exts/Heap.hs
- libraries/ghc-heap/GHC/Exts/Heap/Closures.hs
- libraries/ghc-heap/GHC/Exts/Heap/FFIClosures.hsc
- + libraries/ghc-heap/GHC/Exts/Heap/ProfInfo/PeekProfInfo_ProfilingDisabled.hsc
- + libraries/ghc-heap/GHC/Exts/Heap/ProfInfo/PeekProfInfo_ProfilingEnabled.hsc
- + libraries/ghc-heap/GHC/Exts/Heap/ProfInfo/Types.hs
- + libraries/ghc-heap/GHC/Exts/Heap/Ptr/Utils.hs
- libraries/ghc-heap/ghc-heap.cabal.in
- + libraries/ghc-heap/tests/TestUtils.hs
- libraries/ghc-heap/tests/all.T
- libraries/ghc-heap/tests/list_threads_and_misc_roots.hs
- + libraries/ghc-heap/tests/parse_tso_flags.hs
- + libraries/ghc-heap/tests/prof_info.hs
- libraries/ghc-heap/tests/tso_and_stack_closures.hs
- libraries/ghci/GHCi/Message.hs
- libraries/ghci/GHCi/Run.hs
- rts/RtsAPI.c
- rts/Schedule.c
- rts/Task.c
- rts/Task.h
- rts/sm/NonMoving.c
Changes:
=====================================
compiler/GHC/ByteCode/Types.hs
=====================================
@@ -36,7 +36,7 @@ import Data.ByteString (ByteString)
import Data.IntMap (IntMap)
import qualified Data.IntMap as IntMap
import Data.Maybe (catMaybes)
-import GHC.Exts.Heap
+import qualified GHC.Exts.Heap as Heap
import GHC.Stack.CCS
-- -----------------------------------------------------------------------------
@@ -71,7 +71,7 @@ type ItblEnv = NameEnv (Name, ItblPtr)
-- We need the Name in the range so we know which
-- elements to filter out when unloading a module
-newtype ItblPtr = ItblPtr (RemotePtr StgInfoTable)
+newtype ItblPtr = ItblPtr (RemotePtr Heap.StgInfoTable)
deriving (Show, NFData)
data UnlinkedBCO
=====================================
compiler/GHC/Runtime/Interpreter.hs
=====================================
@@ -94,7 +94,7 @@ import qualified Data.ByteString.Lazy as LB
import Data.Array ((!))
import Data.IORef
import Foreign hiding (void)
-import GHC.Exts.Heap
+import qualified GHC.Exts.Heap as Heap
import GHC.Stack.CCS (CostCentre,CostCentreStack)
import System.Exit
import GHC.IO.Handle.Types (Handle)
@@ -386,7 +386,7 @@ getBreakpointVar hsc_env ref ix =
mb <- iservCmd hsc_env (GetBreakpointVar apStack ix)
mapM (mkFinalizedHValue hsc_env) mb
-getClosure :: HscEnv -> ForeignHValue -> IO (GenClosure ForeignHValue)
+getClosure :: HscEnv -> ForeignHValue -> IO (Heap.GenClosure ForeignHValue)
getClosure hsc_env ref =
withForeignRef ref $ \hval -> do
mb <- iservCmd hsc_env (GetClosure hval)
=====================================
includes/rts/Task.h
=====================================
@@ -15,9 +15,9 @@
typedef struct Task_ Task;
-// Create a new Task for a bound thread. This Task must be released
-// by calling boundTaskExiting. The Task is cached in
-// thread-local storage and will remain even after boundTaskExiting()
+// Create a new Task for a bound thread. This Task must be released
+// by calling exitMyTask(). The Task is cached in
+// thread-local storage and will remain even after exitMyTask()
// has been called; to free the memory, see freeMyTask().
//
Task* newBoundTask (void);
@@ -25,11 +25,10 @@ Task* newBoundTask (void);
// Return the current OS thread's Task, which is created if it doesn't already
// exist. After you have finished using RTS APIs, you should call freeMyTask()
// to release this thread's Task.
-Task* getTask (void);
+Task* getMyTask (void);
-// The current task is a bound task that is exiting.
-//
-void boundTaskExiting (Task *task);
+// Exit myTask - This is the counterpart of newBoundTask().
+void exitMyTask (void);
// Free a Task if one was previously allocated by newBoundTask().
// This is not necessary unless the thread that called newBoundTask()
@@ -37,4 +36,3 @@ void boundTaskExiting (Task *task);
// functions.
//
void freeMyTask(void);
-
=====================================
libraries/ghc-heap/GHC/Exts/Heap.hs
=====================================
@@ -9,6 +9,7 @@
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE UnliftedFFITypes #-}
{-|
Module : GHC.Exts.Heap
@@ -23,9 +24,13 @@ values, i.e. to investigate sharing and lazy evaluation.
module GHC.Exts.Heap (
-- * Closure types
Closure
+ , LiftedClosure
, GenClosure(..)
, ClosureType(..)
, PrimType(..)
+ , WhatNext(..)
+ , WhyBlocked(..)
+ , TsoFlags(..)
, HasHeapRep(getClosureDataX)
, getClosureData
@@ -38,6 +43,12 @@ module GHC.Exts.Heap (
, peekItbl
, pokeItbl
+ -- * Cost Centre (profiling) types
+ , StgTSOProfInfo(..)
+ , IndexTable(..)
+ , CostCentre(..)
+ , CostCentreStack(..)
+
-- * Closure inspection
, getBoxedClosureData
, allClosures
@@ -52,9 +63,19 @@ import Prelude
import GHC.Exts.Heap.Closures
import GHC.Exts.Heap.ClosureTypes
import GHC.Exts.Heap.Constants
+import GHC.Exts.Heap.ProfInfo.Types
#if defined(PROFILING)
+import GHC.Exts.Heap.ProfInfo.PeekProfInfo_ProfilingEnabled
import GHC.Exts.Heap.InfoTableProf
#else
+-- This import makes PeekProfInfo_ProfilingEnabled available in make-based
+-- builds. See #15197 for details (even though the related patch didn't
+-- seem to fix the issue).
+-- GHC.Exts.Heap.Closures uses the same trick to include
+-- GHC.Exts.Heap.InfoTableProf into make-based builds.
+import GHC.Exts.Heap.ProfInfo.PeekProfInfo_ProfilingEnabled ()
+
+import GHC.Exts.Heap.ProfInfo.PeekProfInfo_ProfilingDisabled
import GHC.Exts.Heap.InfoTable
#endif
import GHC.Exts.Heap.Utils
@@ -71,12 +92,19 @@ import Foreign
#include "ghcconfig.h"
+-- | Some closures (e.g.TSOs) don't have corresponding types to represent them in Haskell.
+-- So when we have a pointer to such closure that we want to inspect, we `unsafeCoerce` it
+-- into the following `LiftedClosure` lifted type (could be any lifted type) so that the
+-- appropriate `instance HasHeapRep (a :: TYPE 'LiftedRep)` is used to decode the closure.
+data LiftedClosure
+
class HasHeapRep (a :: TYPE rep) where
-- | Decode a closure to it's heap representation ('GenClosure').
-- Inside a GHC context 'b' is usually a 'GHC.Exts.Heap.Closures.Box'
-- containing a thunk or an evaluated heap object. Outside it can be a
-- 'Word' for "raw" usage of pointers.
+
getClosureDataX ::
(forall c . c -> IO (Ptr StgInfoTable, [Word], [b]))
-- ^ Helper function to get info table, memory and pointers of the
@@ -166,6 +194,7 @@ getClosureData = getClosureDataX getClosureRaw
-- @collect_pointers()@ in @rts/Heap.c at .
--
-- For most use cases 'getClosureData' is an easier to use alternative.
+
getClosureX :: forall a b.
(forall c . c -> IO (Ptr StgInfoTable, [Word], [b]))
-- ^ Helper function to get info table, memory and pointers of the
@@ -325,16 +354,15 @@ getClosureX get_closure_raw x = do
allocaArray (length wds) (\ptr -> do
pokeArray ptr wds
- fields <- FFIClosures.peekTSOFields ptr
-
+ fields <- FFIClosures.peekTSOFields peekStgTSOProfInfo ptr
pure $ TSOClosure
{ info = itbl
- , _link = (pts !! 0)
- , global_link = (pts !! 1)
+ , unsafe_link = (pts !! 0)
+ , unsafe_global_link = (pts !! 1)
, tsoStack = (pts !! 2)
- , trec = (pts !! 3)
- , blocked_exceptions = (pts !! 4)
- , bq = (pts !! 5)
+ , unsafe_trec = (pts !! 3)
+ , unsafe_blocked_exceptions = (pts !! 4)
+ , unsafe_bq = (pts !! 5)
, what_next = FFIClosures.tso_what_next fields
, why_blocked = FFIClosures.tso_why_blocked fields
, flags = FFIClosures.tso_flags fields
@@ -343,6 +371,7 @@ getClosureX get_closure_raw x = do
, tso_dirty = FFIClosures.tso_dirty fields
, alloc_limit = FFIClosures.tso_alloc_limit fields
, tot_stack_size = FFIClosures.tso_tot_stack_size fields
+ , prof = FFIClosures.tso_prof fields
}
)
STACK -> do
@@ -359,8 +388,8 @@ getClosureX get_closure_raw x = do
{ info = itbl
, stack_size = FFIClosures.stack_size fields
, stack_dirty = FFIClosures.stack_dirty fields
- , stackPointer = (pts !! 0)
- , stack = FFIClosures.stack fields
+ , unsafeStackPointer = (pts !! 0)
+ , unsafeStack = FFIClosures.stack fields
#if __GLASGOW_HASKELL__ >= 811
, stack_marking = FFIClosures.stack_marking fields
#endif
=====================================
libraries/ghc-heap/GHC/Exts/Heap/Closures.hs
=====================================
@@ -12,6 +12,9 @@ module GHC.Exts.Heap.Closures (
Closure
, GenClosure(..)
, PrimType(..)
+ , WhatNext(..)
+ , WhyBlocked(..)
+ , TsoFlags(..)
, allClosures
#if __GLASGOW_HASKELL__ >= 809
-- The closureSize# primop is unsupported on earlier GHC releases but we
@@ -40,6 +43,8 @@ import GHC.Exts.Heap.InfoTable
import GHC.Exts.Heap.InfoTableProf ()
#endif
+import GHC.Exts.Heap.ProfInfo.Types
+
import Data.Bits
import Data.Int
import Data.Word
@@ -271,35 +276,42 @@ data GenClosure b
-- | Representation of StgTSO: A Thread State Object.
-- The values for 'what_next', 'why_blocked' and 'flags' are defined in
-- @Constants.h at .
+ -- Fields marked as @unsafe@ are backed by dynamic pointers and should only
+ -- be accessed when the garbage collector is stopped. Otherwise segmentation
+ -- faults may happen when an invalidated pointer is accessed.
| TSOClosure
{ info :: !StgInfoTable
-- pointers
- , _link :: !b
- , global_link :: !b
+ , unsafe_link :: !b
+ , unsafe_global_link :: !b
, tsoStack :: !b -- ^ stackobj from StgTSO
- , trec :: !b
- , blocked_exceptions :: !b
- , bq :: !b
+ , unsafe_trec :: !b
+ , unsafe_blocked_exceptions :: !b
+ , unsafe_bq :: !b
-- values
- , what_next :: Word16
- , why_blocked :: Word16
- , flags :: Word32
+ , what_next :: WhatNext
+ , why_blocked :: WhyBlocked
+ , flags :: [TsoFlags]
, threadId :: Word64
, saved_errno :: Word32
, tso_dirty:: Word32 -- ^ non-zero => dirty
, alloc_limit :: Int64
, tot_stack_size :: Word32
+ , prof :: Maybe StgTSOProfInfo
}
- -- Representation of StgStack: The 'tsoStack' of a 'TSOClosure'.
+ -- | Representation of StgStack: The 'tsoStack' of a 'TSOClosure'.
+ -- Fields marked as @unsafe@ are backed by dynamic pointers and should only
+ -- be accessed when the garbage collector is stopped. Otherwise segmentation
+ -- faults may happen when an invalidated pointer is accessed.
| StackClosure
{ info :: !StgInfoTable
, stack_size :: !Word32 -- ^ stack size in *words*
, stack_dirty :: !Word8 -- ^ non-zero => dirty
-#if __GLASGOW_HASKELL__ >= 811
+#if __GLASGOW_HASKELL__ >= 810
, stack_marking :: Word8
#endif
- , stackPointer :: !b -- ^ current stack pointer
- , stack :: [Word]
+ , unsafeStackPointer :: !b -- ^ current stack pointer
+ , unsafeStack :: [Word]
}
------------------------------------------------------------
@@ -366,6 +378,43 @@ data PrimType
| PDouble
deriving (Eq, Show, Generic)
+data WhatNext
+ = ThreadRunGHC
+ | ThreadInterpret
+ | ThreadKilled
+ | ThreadComplete
+ | WhatNextUnknownValue -- ^ Please report this as a bug
+ deriving (Eq, Show, Generic)
+
+data WhyBlocked
+ = NotBlocked
+ | BlockedOnMVar
+ | BlockedOnMVarRead
+ | BlockedOnBlackHole
+ | BlockedOnRead
+ | BlockedOnWrite
+ | BlockedOnDelay
+ | BlockedOnSTM
+ | BlockedOnDoProc
+ | BlockedOnCCall
+ | BlockedOnCCall_Interruptible
+ | BlockedOnMsgThrowTo
+ | ThreadMigrating
+ | BlockedOnIOCompletion
+ | WhyBlockedUnknownValue -- ^ Please report this as a bug
+ deriving (Eq, Show, Generic)
+
+data TsoFlags
+ = TsoLocked
+ | TsoBlockx
+ | TsoInterruptible
+ | TsoStoppedOnBreakpoint
+ | TsoMarked
+ | TsoSqueezed
+ | TsoAllocLimit
+ | TsoFlagsUnknownValue -- ^ Please report this as a bug
+ deriving (Eq, Show, Generic)
+
-- | For generic code, this function returns all referenced closures.
allClosures :: GenClosure b -> [b]
allClosures (ConstrClosure {..}) = ptrArgs
=====================================
libraries/ghc-heap/GHC/Exts/Heap/FFIClosures.hsc
=====================================
@@ -5,26 +5,28 @@ module GHC.Exts.Heap.FFIClosures where
import Prelude
import Foreign
-
--- TODO use sum type for what_next, why_blocked, flags?
+import GHC.Exts.Heap.ProfInfo.Types
+import GHC.Exts.Heap.Closures(WhatNext(..), WhyBlocked(..), TsoFlags(..))
data TSOFields = TSOFields {
- tso_what_next :: Word16,
- tso_why_blocked :: Word16,
- tso_flags :: Word32,
+ tso_what_next :: WhatNext,
+ tso_why_blocked :: WhyBlocked,
+ tso_flags :: [TsoFlags],
-- Unfortunately block_info is a union without clear discriminator.
-- block_info :: TDB,
tso_threadId :: Word64,
tso_saved_errno :: Word32,
tso_dirty:: Word32,
tso_alloc_limit :: Int64,
- tso_tot_stack_size :: Word32
--- TODO StgTSOProfInfo prof is optionally included, but looks very interesting.
+ tso_tot_stack_size :: Word32,
+ tso_prof :: Maybe StgTSOProfInfo
}
-- | Get non-pointer fields from @StgTSO_@ (@TSO.h@)
-peekTSOFields :: Ptr a -> IO TSOFields
-peekTSOFields ptr = do
+peekTSOFields :: (Ptr tsoPtr -> IO (Maybe StgTSOProfInfo))
+ -> Ptr tsoPtr
+ -> IO TSOFields
+peekTSOFields peekProfInfo ptr = do
what_next' <- (#peek struct StgTSO_, what_next) ptr
why_blocked' <- (#peek struct StgTSO_, why_blocked) ptr
flags' <- (#peek struct StgTSO_, flags) ptr
@@ -33,22 +35,69 @@ peekTSOFields ptr = do
dirty' <- (#peek struct StgTSO_, dirty) ptr
alloc_limit' <- (#peek struct StgTSO_, alloc_limit) ptr
tot_stack_size' <- (#peek struct StgTSO_, tot_stack_size) ptr
+ tso_prof' <- peekProfInfo ptr
return TSOFields {
- tso_what_next = what_next',
- tso_why_blocked = why_blocked',
- tso_flags = flags',
+ tso_what_next = parseWhatNext what_next',
+ tso_why_blocked = parseWhyBlocked why_blocked',
+ tso_flags = parseTsoFlags flags',
tso_threadId = threadId',
tso_saved_errno = saved_errno',
- tso_dirty= dirty',
+ tso_dirty = dirty',
tso_alloc_limit = alloc_limit',
- tso_tot_stack_size = tot_stack_size'
+ tso_tot_stack_size = tot_stack_size',
+ tso_prof = tso_prof'
}
+parseWhatNext :: Word16 -> WhatNext
+parseWhatNext w = case w of
+ (#const ThreadRunGHC) -> ThreadRunGHC
+ (#const ThreadInterpret) -> ThreadInterpret
+ (#const ThreadKilled) -> ThreadKilled
+ (#const ThreadComplete) -> ThreadComplete
+ _ -> WhatNextUnknownValue
+
+parseWhyBlocked :: Word16 -> WhyBlocked
+parseWhyBlocked w = case w of
+ (#const NotBlocked) -> NotBlocked
+ (#const BlockedOnMVar) -> BlockedOnMVar
+ (#const BlockedOnMVarRead) -> BlockedOnMVarRead
+ (#const BlockedOnBlackHole) -> BlockedOnBlackHole
+ (#const BlockedOnRead) -> BlockedOnRead
+ (#const BlockedOnWrite) -> BlockedOnWrite
+ (#const BlockedOnDelay) -> BlockedOnDelay
+ (#const BlockedOnSTM) -> BlockedOnSTM
+ (#const BlockedOnDoProc) -> BlockedOnDoProc
+ (#const BlockedOnCCall) -> BlockedOnCCall
+ (#const BlockedOnCCall_Interruptible) -> BlockedOnCCall_Interruptible
+ (#const BlockedOnMsgThrowTo) -> BlockedOnMsgThrowTo
+ (#const ThreadMigrating) -> ThreadMigrating
+#if __GLASGOW_HASKELL__ >= 810
+ (#const BlockedOnIOCompletion) -> BlockedOnIOCompletion
+#endif
+ _ -> WhyBlockedUnknownValue
+
+parseTsoFlags :: Word32 -> [TsoFlags]
+parseTsoFlags w | isSet (#const TSO_LOCKED) w = TsoLocked : parseTsoFlags (unset (#const TSO_LOCKED) w)
+ | isSet (#const TSO_BLOCKEX) w = TsoBlockx : parseTsoFlags (unset (#const TSO_BLOCKEX) w)
+ | isSet (#const TSO_INTERRUPTIBLE) w = TsoInterruptible : parseTsoFlags (unset (#const TSO_INTERRUPTIBLE) w)
+ | isSet (#const TSO_STOPPED_ON_BREAKPOINT) w = TsoStoppedOnBreakpoint : parseTsoFlags (unset (#const TSO_STOPPED_ON_BREAKPOINT) w)
+ | isSet (#const TSO_MARKED) w = TsoMarked : parseTsoFlags (unset (#const TSO_MARKED) w)
+ | isSet (#const TSO_SQUEEZED) w = TsoSqueezed : parseTsoFlags (unset (#const TSO_SQUEEZED) w)
+ | isSet (#const TSO_ALLOC_LIMIT) w = TsoAllocLimit : parseTsoFlags (unset (#const TSO_ALLOC_LIMIT) w)
+parseTsoFlags 0 = []
+parseTsoFlags _ = [TsoFlagsUnknownValue]
+
+isSet :: Word32 -> Word32 -> Bool
+isSet bitMask w = w .&. bitMask /= 0
+
+unset :: Word32 -> Word32 -> Word32
+unset bitMask w = w `xor` bitMask
+
data StackFields = StackFields {
stack_size :: Word32,
stack_dirty :: Word8,
-#if __GLASGOW_HASKELL__ >= 811
+#if __GLASGOW_HASKELL__ >= 810
stack_marking :: Word8,
#endif
stack :: [Word]
@@ -59,7 +108,7 @@ peekStackFields :: Ptr a -> IO StackFields
peekStackFields ptr = do
stack_size' <- (#peek struct StgStack_, stack_size) ptr ::IO Word32
dirty' <- (#peek struct StgStack_, dirty) ptr
-#if __GLASGOW_HASKELL__ >= 811
+#if __GLASGOW_HASKELL__ >= 810
marking' <- (#peek struct StgStack_, marking) ptr
#endif
@@ -69,7 +118,7 @@ peekStackFields ptr = do
return StackFields {
stack_size = stack_size',
stack_dirty = dirty',
-#if __GLASGOW_HASKELL__ >= 811
+#if __GLASGOW_HASKELL__ >= 810
stack_marking = marking',
#endif
stack = stack'
=====================================
libraries/ghc-heap/GHC/Exts/Heap/ProfInfo/PeekProfInfo_ProfilingDisabled.hsc
=====================================
@@ -0,0 +1,13 @@
+{-# LANGUAGE CPP, DeriveGeneric #-}
+module GHC.Exts.Heap.ProfInfo.PeekProfInfo_ProfilingDisabled(
+ peekStgTSOProfInfo
+) where
+
+import Prelude
+import Foreign
+import GHC.Exts.Heap.ProfInfo.Types
+
+-- | This implementation is used when PROFILING is undefined.
+-- It always returns 'Nothing', because there is no profiling info available.
+peekStgTSOProfInfo :: Ptr tsoPtr -> IO (Maybe StgTSOProfInfo)
+peekStgTSOProfInfo _ = return Nothing
=====================================
libraries/ghc-heap/GHC/Exts/Heap/ProfInfo/PeekProfInfo_ProfilingEnabled.hsc
=====================================
@@ -0,0 +1,168 @@
+{-# LANGUAGE CPP, DeriveGeneric #-}
+module GHC.Exts.Heap.ProfInfo.PeekProfInfo_ProfilingEnabled(
+ peekStgTSOProfInfo
+) where
+
+#if __GLASGOW_HASKELL__ >= 811
+
+-- Manually defining PROFILING gives the #peek and #poke macros an accurate
+-- representation of the C structures when hsc2hs runs. This is valid because
+-- a non-profiling build would use
+-- GHC.Exts.Heap.ProfInfo.PeekProfInfo_ProfilingDisabled.
+#define PROFILING
+
+#include "Rts.h"
+#undef BLOCK_SIZE
+#undef MBLOCK_SIZE
+#undef BLOCKS_PER_MBLOCK
+#include "DerivedConstants.h"
+
+import Prelude
+import Foreign
+
+import Foreign.C.String
+import GHC.Exts.Heap.ProfInfo.Types
+
+import Data.IntMap.Strict (IntMap)
+import qualified Data.IntMap.Strict as IntMap
+
+import Data.IntSet (IntSet)
+import qualified Data.IntSet as IntSet
+
+import Control.Monad.Trans.State
+import Control.Monad.IO.Class
+
+import GHC.Exts.Heap.Ptr.Utils
+
+-- Use Int based containers for pointers (addresses) for better performance.
+-- These will be queried a lot!
+type AddressSet = IntSet
+type AddressMap = IntMap
+
+data Cache = Cache {
+ ccCache :: AddressMap CostCentre
+}
+type DecoderMonad a = StateT Cache IO a
+
+peekStgTSOProfInfo :: Ptr a -> IO (Maybe StgTSOProfInfo)
+peekStgTSOProfInfo tsoPtr = do
+ cccs_ptr <- peekByteOff tsoPtr cccsOffset
+ cccs' <- evalStateT (peekCostCentreStack IntSet.empty cccs_ptr) $ Cache IntMap.empty
+
+ return $ Just StgTSOProfInfo {
+ cccs = cccs'
+ }
+
+cccsOffset :: Int
+cccsOffset = (#const OFFSET_StgTSO_cccs) + (#size StgHeader)
+
+peekCostCentreStack :: AddressSet -> Ptr costCentreStack -> DecoderMonad (Maybe CostCentreStack)
+peekCostCentreStack _ ptr | ptr == nullPtr = return Nothing
+peekCostCentreStack loopBreakers ptr | IntSet.member (ptrToInt ptr) loopBreakers = return Nothing
+peekCostCentreStack loopBreakers ptr = do
+ ccs_ccsID' <- liftIO $ (#peek struct CostCentreStack_, ccsID) ptr
+ ccs_cc_ptr <- liftIO $ (#peek struct CostCentreStack_, cc) ptr
+ ccs_cc' <- peekCostCentre ccs_cc_ptr
+ ccs_prevStack_ptr <- liftIO $ (#peek struct CostCentreStack_, prevStack) ptr
+ let loopBreakers' = (IntSet.insert ptrAsInt loopBreakers)
+ ccs_prevStack' <- peekCostCentreStack loopBreakers' ccs_prevStack_ptr
+ ccs_indexTable_ptr <- liftIO $ (#peek struct CostCentreStack_, indexTable) ptr
+ ccs_indexTable' <- peekIndexTable loopBreakers' ccs_indexTable_ptr
+ ccs_root_ptr <- liftIO $ (#peek struct CostCentreStack_, root) ptr
+ ccs_root' <- peekCostCentreStack loopBreakers' ccs_root_ptr
+ ccs_depth' <- liftIO $ (#peek struct CostCentreStack_, depth) ptr
+ ccs_scc_count' <- liftIO $ (#peek struct CostCentreStack_, scc_count) ptr
+ ccs_selected' <- liftIO $ (#peek struct CostCentreStack_, selected) ptr
+ ccs_time_ticks' <- liftIO $ (#peek struct CostCentreStack_, time_ticks) ptr
+ ccs_mem_alloc' <- liftIO $ (#peek struct CostCentreStack_, mem_alloc) ptr
+ ccs_inherited_alloc' <- liftIO $ (#peek struct CostCentreStack_, inherited_alloc) ptr
+ ccs_inherited_ticks' <- liftIO $ (#peek struct CostCentreStack_, inherited_ticks) ptr
+
+ return $ Just CostCentreStack {
+ ccs_ccsID = ccs_ccsID',
+ ccs_cc = ccs_cc',
+ ccs_prevStack = ccs_prevStack',
+ ccs_indexTable = ccs_indexTable',
+ ccs_root = ccs_root',
+ ccs_depth = ccs_depth',
+ ccs_scc_count = ccs_scc_count',
+ ccs_selected = ccs_selected',
+ ccs_time_ticks = ccs_time_ticks',
+ ccs_mem_alloc = ccs_mem_alloc',
+ ccs_inherited_alloc = ccs_inherited_alloc',
+ ccs_inherited_ticks = ccs_inherited_ticks'
+ }
+ where
+ ptrAsInt = ptrToInt ptr
+
+peekCostCentre :: Ptr costCentre -> DecoderMonad CostCentre
+peekCostCentre ptr = do
+ cache <- get
+ case IntMap.lookup ptrAsInt (ccCache cache) of
+ (Just a) -> return a
+ Nothing -> do
+ cc_ccID' <- liftIO $ (#peek struct CostCentre_, ccID) ptr
+ cc_label_ptr <- liftIO $ (#peek struct CostCentre_, label) ptr
+ cc_label' <- liftIO $ peekCString cc_label_ptr
+ cc_module_ptr <- liftIO $ (#peek struct CostCentre_, module) ptr
+ cc_module' <- liftIO $ peekCString cc_module_ptr
+ cc_srcloc_ptr <- liftIO $ (#peek struct CostCentre_, srcloc) ptr
+ cc_srcloc' <- liftIO $ do
+ if cc_srcloc_ptr == nullPtr then
+ return Nothing
+ else
+ fmap Just (peekCString cc_srcloc_ptr)
+ cc_mem_alloc' <- liftIO $ (#peek struct CostCentre_, mem_alloc) ptr
+ cc_time_ticks' <- liftIO $ (#peek struct CostCentre_, time_ticks) ptr
+ cc_is_caf' <- liftIO $ (#peek struct CostCentre_, is_caf) ptr
+ cc_link_ptr <- liftIO $ (#peek struct CostCentre_, link) ptr
+ cc_link' <- if cc_link_ptr == nullPtr then
+ return Nothing
+ else
+ fmap Just (peekCostCentre cc_link_ptr)
+
+ let result = CostCentre {
+ cc_ccID = cc_ccID',
+ cc_label = cc_label',
+ cc_module = cc_module',
+ cc_srcloc = cc_srcloc',
+ cc_mem_alloc = cc_mem_alloc',
+ cc_time_ticks = cc_time_ticks',
+ cc_is_caf = cc_is_caf',
+ cc_link = cc_link'
+ }
+
+ let updatedCCCache = IntMap.insert ptrAsInt result (ccCache cache)
+ put $ cache { ccCache = updatedCCCache }
+
+ return result
+ where
+ ptrAsInt = ptrToInt ptr
+
+peekIndexTable :: AddressSet -> Ptr indexTable -> DecoderMonad (Maybe IndexTable)
+peekIndexTable _ ptr | ptr == nullPtr = return Nothing
+peekIndexTable loopBreakers ptr = do
+ it_cc_ptr <- liftIO $ (#peek struct IndexTable_, cc) ptr
+ it_cc' <- peekCostCentre it_cc_ptr
+ it_ccs_ptr <- liftIO $ (#peek struct IndexTable_, ccs) ptr
+ it_ccs' <- peekCostCentreStack loopBreakers it_ccs_ptr
+ it_next_ptr <- liftIO $ (#peek struct IndexTable_, next) ptr
+ it_next' <- peekIndexTable loopBreakers it_next_ptr
+ it_back_edge' <- liftIO $ (#peek struct IndexTable_, back_edge) ptr
+
+ return $ Just IndexTable {
+ it_cc = it_cc',
+ it_ccs = it_ccs',
+ it_next = it_next',
+ it_back_edge = it_back_edge'
+ }
+
+#else
+import Prelude
+import Foreign
+
+import GHC.Exts.Heap.ProfInfo.Types
+
+peekStgTSOProfInfo :: Ptr a -> IO (Maybe StgTSOProfInfo)
+peekStgTSOProfInfo _ = return Nothing
+#endif
=====================================
libraries/ghc-heap/GHC/Exts/Heap/ProfInfo/Types.hs
=====================================
@@ -0,0 +1,44 @@
+{-# LANGUAGE DeriveGeneric #-}
+
+module GHC.Exts.Heap.ProfInfo.Types where
+
+import Prelude
+import Data.Word
+import GHC.Generics
+
+data StgTSOProfInfo = StgTSOProfInfo {
+ cccs :: Maybe CostCentreStack
+} deriving (Show, Generic)
+
+data CostCentreStack = CostCentreStack {
+ ccs_ccsID :: Int,
+ ccs_cc :: CostCentre,
+ ccs_prevStack :: Maybe CostCentreStack,
+ ccs_indexTable :: Maybe IndexTable,
+ ccs_root :: Maybe CostCentreStack,
+ ccs_depth :: Word,
+ ccs_scc_count :: Word64,
+ ccs_selected :: Word,
+ ccs_time_ticks :: Word,
+ ccs_mem_alloc :: Word64,
+ ccs_inherited_alloc :: Word64,
+ ccs_inherited_ticks :: Word
+} deriving (Show, Generic, Eq)
+
+data CostCentre = CostCentre {
+ cc_ccID :: Int,
+ cc_label :: String,
+ cc_module :: String,
+ cc_srcloc :: Maybe String,
+ cc_mem_alloc :: Word64,
+ cc_time_ticks :: Word,
+ cc_is_caf :: Bool,
+ cc_link :: Maybe CostCentre
+} deriving (Show, Generic, Eq)
+
+data IndexTable = IndexTable {
+ it_cc :: CostCentre,
+ it_ccs :: Maybe CostCentreStack,
+ it_next :: Maybe IndexTable,
+ it_back_edge :: Bool
+} deriving (Show, Generic, Eq)
=====================================
libraries/ghc-heap/GHC/Exts/Heap/Ptr/Utils.hs
=====================================
@@ -0,0 +1,11 @@
+{-# LANGUAGE CPP, DeriveGeneric, MagicHash #-}
+
+module GHC.Exts.Heap.Ptr.Utils where
+
+import Prelude
+import GHC.Ptr
+import GHC.Exts
+
+-- | casts a @Ptr@ to an @Int@
+ptrToInt :: Ptr a -> Int
+ptrToInt (Ptr a#) = I# (addr2Int# a#)
=====================================
libraries/ghc-heap/ghc-heap.cabal.in
=====================================
@@ -25,6 +25,8 @@ library
build-depends: base >= 4.9.0 && < 5.0
, ghc-prim > 0.2 && < 0.8
, rts == 1.0.*
+ , containers >= 0.6.2.1 && < 0.7
+ , transformers == 0.5.*
ghc-options: -Wall
cmm-sources: cbits/HeapPrim.cmm
@@ -40,3 +42,7 @@ library
GHC.Exts.Heap.InfoTableProf
GHC.Exts.Heap.Utils
GHC.Exts.Heap.FFIClosures
+ GHC.Exts.Heap.ProfInfo.Types
+ GHC.Exts.Heap.ProfInfo.PeekProfInfo_ProfilingEnabled
+ GHC.Exts.Heap.ProfInfo.PeekProfInfo_ProfilingDisabled
+ GHC.Exts.Heap.Ptr.Utils
=====================================
libraries/ghc-heap/tests/TestUtils.hs
=====================================
@@ -0,0 +1,20 @@
+{-# LANGUAGE MagicHash #-}
+module TestUtils where
+
+import GHC.Exts.Heap (getClosureData, LiftedClosure, Box, GenClosure)
+import Foreign (Ptr)
+import GHC.Exts (Ptr, Addr#, unsafeCoerce#)
+import GHC.Ptr (Ptr(Ptr))
+
+assertEqual :: (Show a, Eq a) => a -> a -> IO ()
+assertEqual a b
+ | a /= b = error (show a ++ " /= " ++ show b)
+ | otherwise = return ()
+
+createClosure :: Ptr () -> IO (GenClosure Box)
+createClosure tsoPtr = do
+ let addr = unpackAddr# tsoPtr
+ getClosureData ((unsafeCoerce# addr) :: LiftedClosure)
+
+unpackAddr# :: Ptr () -> Addr#
+unpackAddr# (Ptr addr) = addr
=====================================
libraries/ghc-heap/tests/all.T
=====================================
@@ -37,15 +37,32 @@ test('closure_size_noopt',
compile_and_run, [''])
test('tso_and_stack_closures',
- [extra_files(['create_tso.c','create_tso.h']),
+ [extra_files(['create_tso.c','create_tso.h', 'TestUtils.hs']),
ignore_stdout,
ignore_stderr
],
multi_compile_and_run, ['tso_and_stack_closures', [('create_tso.c','')], ''])
test('list_threads_and_misc_roots',
- [extra_files(['list_threads_and_misc_roots_c.c','list_threads_and_misc_roots_c.h']),
+ [extra_files(['list_threads_and_misc_roots_c.c','list_threads_and_misc_roots_c.h','TestUtils.hs']),
ignore_stdout,
ignore_stderr
],
multi_compile_and_run, ['list_threads_and_misc_roots', [('list_threads_and_misc_roots_c.c','')], '-threaded'])
+
+test('prof_info',
+ [extra_files(['create_tso.c','create_tso.h','TestUtils.hs']),
+ ignore_stdout,
+ ignore_stderr,
+ when(have_profiling(), extra_ways(['prof'])),
+ only_ways(prof_ways)
+ ],
+ multi_compile_and_run, ['prof_info', [('create_tso.c','')], '-prof'])
+
+test('parse_tso_flags',
+ [extra_files(['TestUtils.hs']),
+ only_ways(['normal']),
+ ignore_stdout,
+ ignore_stderr
+ ],
+ compile_and_run, [''])
=====================================
libraries/ghc-heap/tests/list_threads_and_misc_roots.hs
=====================================
@@ -7,11 +7,7 @@ import Control.Concurrent
import GHC.Exts.Heap
import GHC.Exts
-
--- Invent a type to bypass the type constraints of getClosureData.
--- Infact this will be a Word#, that is directly given to unpackClosure#
--- (which is a primop that expects a pointer to a closure).
-data FoolClosure
+import TestUtils
foreign import ccall safe "list_threads_and_misc_roots_c.h listThreadsAndMiscRoots"
listThreadsAndMiscRoots_c :: IO ()
@@ -20,13 +16,13 @@ foreign import ccall safe "list_threads_and_misc_roots_c.h getTSOCount"
getTSOCount_c :: IO Int
foreign import ccall safe "list_threads_and_misc_roots_c.h getTSOs"
- getTSOs_c :: IO (Ptr Word)
+ getTSOs_c :: IO (Ptr (Ptr ()))
foreign import ccall safe "list_threads_and_misc_roots_c.h getMiscRootsCount"
getMiscRootsCount_c :: IO Int
foreign import ccall safe "list_threads_and_misc_roots_c.h getMiscRoots"
- getMiscRoots_c :: IO (Ptr Word)
+ getMiscRoots_c :: IO (Ptr (Ptr ()))
main :: IO ()
main = do
@@ -50,19 +46,6 @@ main = do
return ()
-createClosure :: Word -> IO (GenClosure Box)
-createClosure tsoPtr = do
- let wPtr = unpackWord# tsoPtr
- getClosureData ((unsafeCoerce# wPtr) :: FoolClosure)
-
-unpackWord# :: Word -> Word#
-unpackWord# (W# w#) = w#
-
-assertEqual :: (Show a, Eq a) => a -> a -> IO ()
-assertEqual a b
- | a /= b = error (show a ++ " /= " ++ show b)
- | otherwise = return ()
-
assertIsClosureType :: ClosureType -> IO ()
assertIsClosureType t
| t `elem` enumerate = return ()
=====================================
libraries/ghc-heap/tests/parse_tso_flags.hs
=====================================
@@ -0,0 +1,17 @@
+import GHC.Exts.Heap.Closures
+import GHC.Exts.Heap.FFIClosures
+import TestUtils
+
+main :: IO()
+main = do
+ assertEqual (parseTsoFlags 0) []
+ assertEqual (parseTsoFlags 1) [TsoFlagsUnknownValue]
+ assertEqual (parseTsoFlags 2) [TsoLocked]
+ assertEqual (parseTsoFlags 4) [TsoBlockx]
+ assertEqual (parseTsoFlags 8) [TsoInterruptible]
+ assertEqual (parseTsoFlags 16) [TsoStoppedOnBreakpoint]
+ assertEqual (parseTsoFlags 64) [TsoMarked]
+ assertEqual (parseTsoFlags 128) [TsoSqueezed]
+ assertEqual (parseTsoFlags 256) [TsoAllocLimit]
+
+ assertEqual (parseTsoFlags 6) [TsoLocked, TsoBlockx]
=====================================
libraries/ghc-heap/tests/prof_info.hs
=====================================
@@ -0,0 +1,53 @@
+{-# LANGUAGE ForeignFunctionInterface, MagicHash, CPP, BangPatterns #-}
+
+import Prelude
+import Foreign
+import Foreign.C.Types
+import GHC.Exts.Heap
+import GHC.Exts
+import Data.Functor
+
+import GHC.Word
+import Data.List (find)
+
+import TestUtils
+
+#include "ghcconfig.h"
+#include "rts/Constants.h"
+
+foreign import ccall unsafe "create_tso.h create_tso"
+ c_create_tso:: IO (Ptr ())
+
+createTSOClosure :: IO (GenClosure Box)
+createTSOClosure = do
+ ptr <- {-# SCC "MyCostCentre" #-} c_create_tso
+ let addr = unpackAddr# ptr
+ getClosureData ((unsafeCoerce# addr) :: LiftedClosure)
+
+-- We can make some assumptions about the - otherwise dynamic - properties of
+-- StgTSO and StgStack, because a new, non-running TSO is created with
+-- create_tso() (create_tso.c).create_tso
+main :: IO ()
+main = do
+ tso <- createTSOClosure
+
+ let costCentre = prof tso >>= cccs <&> ccs_cc
+
+ case costCentre of
+ Nothing -> error $ "No CostCentre found in TSO: " ++ show tso
+ Just _ -> case findMyCostCentre (linkedCostCentres costCentre) of
+ Just myCostCentre -> do
+ assertEqual (cc_label myCostCentre) "MyCostCentre"
+ assertEqual (cc_module myCostCentre) "Main"
+ assertEqual (cc_srcloc myCostCentre) (Just "prof_info.hs:23:39-50")
+ assertEqual (cc_mem_alloc myCostCentre) 0
+ assertEqual (cc_time_ticks myCostCentre) 0
+ assertEqual (cc_is_caf myCostCentre) False
+ Nothing -> error "MyCostCentre not found!"
+
+linkedCostCentres :: Maybe CostCentre -> [CostCentre]
+linkedCostCentres Nothing = []
+linkedCostCentres (Just cc) = cc : linkedCostCentres (cc_link cc)
+
+findMyCostCentre:: [CostCentre] -> Maybe CostCentre
+findMyCostCentre ccs = find (\cc -> cc_label cc == "MyCostCentre") ccs
=====================================
libraries/ghc-heap/tests/tso_and_stack_closures.hs
=====================================
@@ -1,4 +1,4 @@
-{-# LANGUAGE ForeignFunctionInterface, MagicHash, CPP, BangPatterns #-}
+{-# LANGUAGE ForeignFunctionInterface, MagicHash, BangPatterns #-}
import Foreign
import Foreign.C.Types
@@ -7,16 +7,10 @@ import GHC.Exts
import GHC.Word
-#include "ghcconfig.h"
-#include "rts/Constants.h"
+import TestUtils
foreign import ccall unsafe "create_tso.h create_tso"
- c_create_tso:: IO Word
-
--- Invent a type to bypass the type constraints of getClosureData.
--- Infact this will be a Word#, that is directly given to unpackClosure#
--- (which is a primop that expects a pointer to a closure).
-data FoolStgTSO
+ c_create_tso:: IO (Ptr ())
-- We can make some assumptions about the - otherwise dynamic - properties of
-- StgTSO and StgStack, because a new, non-running TSO is created with
@@ -28,14 +22,13 @@ main = do
assertEqual (why_blocked tso) NotBlocked
assertEqual (saved_errno tso) 0
- print $ "tso : "++ show tso
-
-- The newly created TSO should be on the end of the run queue.
- let !_linkBox = _link tso
+ let !_linkBox = unsafe_link tso
_linkClosure <- getBoxedClosureData _linkBox
assertEqual (name _linkClosure) "END_TSO_QUEUE"
+ assertEqual (getClosureType _linkClosure) CONSTR_NOCAF
- let !global_linkBox = global_link tso
+ let !global_linkBox = unsafe_global_link tso
globalLinkClosure <- getBoxedClosureData global_linkBox
assertEqual (getClosureType globalLinkClosure) TSO
@@ -43,35 +36,26 @@ main = do
stackClosure <- getBoxedClosureData stackBox
assertEqual (getClosureType stackClosure) STACK
- let !stackPointerBox = stackPointer stackClosure
+ let !stackPointerBox = unsafeStackPointer stackClosure
stackPointerClosure <- getBoxedClosureData stackPointerBox
assertEqual (getClosureType stackPointerClosure) RET_SMALL
- let !trecBox = trec tso
+ let !trecBox = unsafe_trec tso
trecClosure <- getBoxedClosureData trecBox
assertEqual (name trecClosure) "NO_TREC"
- let !blockedExceptionsBox = blocked_exceptions tso
+ let !blockedExceptionsBox = unsafe_blocked_exceptions tso
blockedExceptionsClosure <- getBoxedClosureData blockedExceptionsBox
assertEqual (name blockedExceptionsClosure) "END_TSO_QUEUE"
- let !bqBox = bq tso
+ let !bqBox = unsafe_bq tso
bqClosure <- getBoxedClosureData bqBox
assertEqual (name bqClosure) "END_TSO_QUEUE"
createTSOClosure :: IO (GenClosure Box)
createTSOClosure = do
ptr <- c_create_tso
- let wPtr = unpackWord# ptr
- getClosureData ((unsafeCoerce# wPtr) :: FoolStgTSO)
-
-unpackWord# :: Word -> Word#
-unpackWord# (W# w#) = w#
-
-assertEqual :: (Show a, Eq a) => a -> a -> IO ()
-assertEqual a b
- | a /= b = error (show a ++ " /= " ++ show b)
- | otherwise = return ()
+ createClosure ptr
getClosureType :: GenClosure b -> ClosureType
getClosureType = tipe . info
=====================================
libraries/ghci/GHCi/Message.hs
=====================================
@@ -1,5 +1,6 @@
{-# LANGUAGE GADTs, DeriveGeneric, StandaloneDeriving, ScopedTypeVariables,
- GeneralizedNewtypeDeriving, ExistentialQuantification, RecordWildCards #-}
+ GeneralizedNewtypeDeriving, ExistentialQuantification, RecordWildCards,
+ CPP #-}
{-# OPTIONS_GHC -fno-warn-name-shadowing -fno-warn-orphans #-}
-- |
@@ -29,7 +30,7 @@ import GHCi.TH.Binary () -- For Binary instances
import GHCi.BreakArray
import GHC.LanguageExtensions
-import GHC.Exts.Heap
+import qualified GHC.Exts.Heap as Heap
import GHC.ForeignSrcLang
import GHC.Fingerprint
import Control.Concurrent
@@ -110,7 +111,7 @@ data Message a where
-> Int -- constr tag
-> Int -- pointer tag
-> ByteString -- constructor desccription
- -> Message (RemotePtr StgInfoTable)
+ -> Message (RemotePtr Heap.StgInfoTable)
-- | Evaluate a statement
EvalStmt
@@ -211,7 +212,7 @@ data Message a where
-- type reconstruction.
GetClosure
:: HValueRef
- -> Message (GenClosure HValueRef)
+ -> Message (Heap.GenClosure HValueRef)
-- | Evaluate something. This is used to support :force in GHCi.
Seq
@@ -449,10 +450,20 @@ instance Binary (FunPtr a) where
get = castPtrToFunPtr <$> get
-- Binary instances to support the GetClosure message
-instance Binary StgInfoTable
-instance Binary ClosureType
-instance Binary PrimType
-instance Binary a => Binary (GenClosure a)
+#if MIN_VERSION_ghc_heap(8,11,0)
+instance Binary Heap.StgTSOProfInfo
+instance Binary Heap.CostCentreStack
+instance Binary Heap.CostCentre
+instance Binary Heap.IndexTable
+instance Binary Heap.WhatNext
+instance Binary Heap.WhyBlocked
+instance Binary Heap.TsoFlags
+#endif
+
+instance Binary Heap.StgInfoTable
+instance Binary Heap.ClosureType
+instance Binary Heap.PrimType
+instance Binary a => Binary (Heap.GenClosure a)
data Msg = forall a . (Binary a, Show a) => Msg (Message a)
=====================================
libraries/ghci/GHCi/Run.hs
=====================================
@@ -32,7 +32,7 @@ import Data.Binary.Get
import Data.ByteString (ByteString)
import qualified Data.ByteString.Unsafe as B
import GHC.Exts
-import GHC.Exts.Heap
+import qualified GHC.Exts.Heap as Heap
import GHC.Stack
import Foreign hiding (void)
import Foreign.C
@@ -93,8 +93,8 @@ run m = case m of
toRemotePtr <$> mkConInfoTable tc ptrs nptrs tag ptrtag desc
StartTH -> startTH
GetClosure ref -> do
- clos <- getClosureData =<< localRef ref
- mapM (\(Box x) -> mkRemoteRef (HValue x)) clos
+ clos <- Heap.getClosureData =<< localRef ref
+ mapM (\(Heap.Box x) -> mkRemoteRef (HValue x)) clos
Seq ref -> doSeq ref
ResumeSeq ref -> resumeSeq ref
_other -> error "GHCi.Run.run"
=====================================
rts/RtsAPI.c
=====================================
@@ -621,21 +621,21 @@ rts_unlock (Capability *cap)
task = cap->running_task;
ASSERT_FULL_CAPABILITY_INVARIANTS(cap,task);
- // Now release the Capability. With the capability released, GC
- // may happen. NB. does not try to put the current Task on the
+ // Now release the Capability. With the capability released, GC
+ // may happen. NB. does not try to put the current Task on the
// worker queue.
- // NB. keep cap->lock held while we call boundTaskExiting(). This
+ // NB. keep cap->lock held while we call exitMyTask(). This
// is necessary during shutdown, where we want the invariant that
// after shutdownCapability(), all the Tasks associated with the
- // Capability have completed their shutdown too. Otherwise we
- // could have boundTaskExiting()/workerTaskStop() running at some
+ // Capability have completed their shutdown too. Otherwise we
+ // could have exitMyTask()/workerTaskStop() running at some
// random point in the future, which causes problems for
// freeTaskManager().
ACQUIRE_LOCK(&cap->lock);
releaseCapability_(cap,false);
// Finally, we can release the Task to the free list.
- boundTaskExiting(task);
+ exitMyTask();
RELEASE_LOCK(&cap->lock);
if (task->incall == NULL) {
@@ -794,7 +794,7 @@ void rts_done (void)
void hs_try_putmvar (/* in */ int capability,
/* in */ HsStablePtr mvar)
{
- Task *task = getTask();
+ Task *task = getMyTask();
Capability *cap;
Capability *task_old_cap USED_IF_THREADS;
=====================================
rts/Schedule.c
=====================================
@@ -2082,7 +2082,7 @@ forkProcess(HsStablePtr *entry
RELEASE_LOCK(&capabilities[i]->lock);
}
- boundTaskExiting(task);
+ exitMyTask();
// just return the pid
return pid;
@@ -2762,7 +2762,7 @@ exitScheduler (bool wait_foreign USED_IF_THREADS)
// debugBelch("n_failed_trygrab_idles = %d, n_idle_caps = %d\n",
// n_failed_trygrab_idles, n_idle_caps);
- boundTaskExiting(task);
+ exitMyTask();
}
void
@@ -2821,7 +2821,7 @@ performGC_(bool force_major)
waitForCapability(&cap,task);
scheduleDoGC(&cap,task,force_major,false);
releaseCapability(cap);
- boundTaskExiting(task);
+ exitMyTask();
}
void
=====================================
rts/Task.c
=====================================
@@ -116,7 +116,7 @@ freeTaskManager (void)
return tasksRunning;
}
-Task* getTask (void)
+Task* getMyTask (void)
{
Task *task;
@@ -304,7 +304,7 @@ newBoundTask (void)
stg_exit(EXIT_FAILURE);
}
- task = getTask();
+ task = getMyTask();
task->stopped = false;
@@ -315,13 +315,12 @@ newBoundTask (void)
}
void
-boundTaskExiting (Task *task)
+exitMyTask (void)
{
+ Task* task = myTask();
#if defined(THREADED_RTS)
ASSERT(osThreadId() == task->id);
#endif
- ASSERT(myTask() == task);
-
endInCall(task);
// Set task->stopped, but only if this is the last call (#4850).
@@ -522,7 +521,7 @@ void rts_setInCallCapability (
int preferred_capability,
int affinity USED_IF_THREADS)
{
- Task *task = getTask();
+ Task *task = getMyTask();
task->preferred_capability = preferred_capability;
#if defined(THREADED_RTS)
@@ -539,7 +538,7 @@ void rts_pinThreadToNumaNode (
{
#if defined(THREADED_RTS)
if (RtsFlags.GcFlags.numa) {
- Task *task = getTask();
+ Task *task = getMyTask();
task->node = capNoToNumaNode(node);
if (!DEBUG_IS_ON || !RtsFlags.DebugFlags.numa) { // faking NUMA
setThreadNode(numa_map[task->node]);
=====================================
rts/Task.h
=====================================
@@ -150,7 +150,7 @@ typedef struct Task_ {
bool worker; // == true if this is a worker Task
bool stopped; // == true between newBoundTask and
- // boundTaskExiting, or in a worker Task.
+ // exitMyTask, or in a worker Task.
// So that we can detect when a finalizer illegally calls back into Haskell
bool running_finalizers;
=====================================
rts/sm/NonMoving.c
=====================================
@@ -1215,7 +1215,7 @@ static void nonmovingMark_(MarkQueue *mark_queue, StgWeak **dead_weaks, StgTSO *
#if defined(THREADED_RTS)
finish:
- boundTaskExiting(task);
+ exitMyTask();
// We are done...
mark_thread = 0;
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/d92c67f01bdd1da6f6f8ecebd5365aed3d62dab5...929c5c33f842a96a75fac7779730c920c139276c
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/d92c67f01bdd1da6f6f8ecebd5365aed3d62dab5...929c5c33f842a96a75fac7779730c920c139276c
You're receiving this email because of your account on gitlab.haskell.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20200822/457a56b3/attachment-0001.html>
More information about the ghc-commits
mailing list