diff options
Diffstat (limited to 'libraries/ghc-heap/tests')
-rw-r--r-- | libraries/ghc-heap/tests/TestUtils.hs | 7 | ||||
-rw-r--r-- | libraries/ghc-heap/tests/all.T | 15 | ||||
-rw-r--r-- | libraries/ghc-heap/tests/create_tso.c | 82 | ||||
-rw-r--r-- | libraries/ghc-heap/tests/create_tso.h | 19 | ||||
-rw-r--r-- | libraries/ghc-heap/tests/parse_tso_flags.hs | 17 | ||||
-rw-r--r-- | libraries/ghc-heap/tests/tso_and_stack_closures.hs | 167 |
6 files changed, 307 insertions, 0 deletions
diff --git a/libraries/ghc-heap/tests/TestUtils.hs b/libraries/ghc-heap/tests/TestUtils.hs new file mode 100644 index 0000000000..4f297cae3a --- /dev/null +++ b/libraries/ghc-heap/tests/TestUtils.hs @@ -0,0 +1,7 @@ +{-# LANGUAGE MagicHash #-} +module TestUtils where + +assertEqual :: (Show a, Eq a) => a -> a -> IO () +assertEqual a b + | a /= b = error (show a ++ " /= " ++ show b) + | otherwise = return () diff --git a/libraries/ghc-heap/tests/all.T b/libraries/ghc-heap/tests/all.T index 89e6f47ecb..fcafb9fa45 100644 --- a/libraries/ghc-heap/tests/all.T +++ b/libraries/ghc-heap/tests/all.T @@ -36,3 +36,18 @@ test('closure_size_noopt', ], compile_and_run, ['']) +test('tso_and_stack_closures', + [extra_files(['create_tso.c','create_tso.h','TestUtils.hs']), + only_ways(['profthreaded']), + ignore_stdout, + ignore_stderr + ], + multi_compile_and_run, ['tso_and_stack_closures', [('create_tso.c','')], '']) + +test('parse_tso_flags', + [extra_files(['TestUtils.hs']), + only_ways(['normal']), + ignore_stdout, + ignore_stderr + ], + compile_and_run, ['']) diff --git a/libraries/ghc-heap/tests/create_tso.c b/libraries/ghc-heap/tests/create_tso.c new file mode 100644 index 0000000000..4b00333197 --- /dev/null +++ b/libraries/ghc-heap/tests/create_tso.c @@ -0,0 +1,82 @@ +#include "Rts.h" +#include "RtsAPI.h" + +// Assumes the rts is paused +void unpack_closure + ( StgClosure * inClosure + , const StgInfoTable ** outInfoTablePtr + , int * outHeapRepSize // Size of outHeapRep (in bytes) + , StgWord ** outHeapRep // Array of words + , int * outPointersSize // Size of outPointers (in words) + , StgClosure *** outPointers // Array of all pointers of the TSO + ) +{ + *outInfoTablePtr = get_itbl(inClosure); + + // Copy TSO pointers. + StgWord closureSizeW = heap_view_closureSize(inClosure); + int closureSizeB = sizeof(StgWord) * closureSizeW; + StgClosure ** pointers = malloc(closureSizeB); + *outPointersSize = collect_pointers(inClosure, closureSizeW, pointers); + *outPointers = pointers; + + // Copy the heap rep. + StgWord * heapRep = malloc(closureSizeB); + for (int i = 0; i < closureSizeW; i++) + { + heapRep[i] = ((StgWord*)inClosure)[i]; + } + + *outHeapRepSize = closureSizeB; + *outHeapRep = heapRep; +} + +// Must be called from a safe FFI call. +void create_and_unpack_tso_and_stack + // TSO + ( StgTSO ** outTso + , const StgInfoTable ** outTsoInfoTablePtr + , int * outTsoHeapRepSize // Size of outHeapRep (in bytes) + , StgWord ** outTsoHeapRep // Array of words + , int * outTsoPointersSize // Size of outPointers (in words) + , StgClosure *** outTsoPointers // Array of all pointers of the TSO + // Stack + , StgTSO ** outStack + , const StgInfoTable ** outStackInfoTablePtr + , int * outStackHeapRepSize // Size of outHeapRep (in bytes) + , StgWord ** outStackHeapRep // Array of words + , int * outStackPointersSize // Size of outPointers (in words) + , StgClosure *** outStackPointers // Array of all pointers of the TSO + ) +{ + // Pause RTS + PauseToken * token = rts_pause(); + Capability * cap = pauseTokenCapability(token); + + // Create TSO/Stack + HaskellObj trueClosure = rts_mkBool(cap, 1); + *outTso = createGenThread(cap, 500U, trueClosure); + + // Unpack TSO + unpack_closure( + (StgClosure*)(*outTso), + outTsoInfoTablePtr, + outTsoHeapRepSize, + outTsoHeapRep, + outTsoPointersSize, + outTsoPointers); + + // Unpack STACK + StgClosure * outStackAsClosure = (*outTsoPointers)[2]; + *outStack = (StgTSO *)outStackAsClosure; + unpack_closure( + outStackAsClosure, + outStackInfoTablePtr, + outStackHeapRepSize, + outStackHeapRep, + outStackPointersSize, + outStackPointers); + + // Resume RTS + rts_resume(token); +} diff --git a/libraries/ghc-heap/tests/create_tso.h b/libraries/ghc-heap/tests/create_tso.h new file mode 100644 index 0000000000..1c24cc2e82 --- /dev/null +++ b/libraries/ghc-heap/tests/create_tso.h @@ -0,0 +1,19 @@ +#include "Rts.h" +#include "RtsAPI.h" + +void create_and_unpack_tso_and_stack + // TSO + ( StgTSO ** outTso + , const StgInfoTable ** outTsoInfoTablePtr + , int * outTsoHeapRepSize // Size of outHeapRep (in bytes) + , StgWord ** outTsoHeapRep // Array of words + , int * outTsoPointersSize // Size of outPointers (in words) + , StgClosure *** outTsoPointers // Array of all pointers of the TSO + // Stack + , StgTSO ** outStack + , const StgInfoTable ** outStackInfoTablePtr + , int * outStackHeapRepSize // Size of outHeapRep (in bytes) + , StgWord ** outStackHeapRep // Array of words + , int * outStackPointersSize // Size of outPointers (in words) + , StgClosure *** outStackPointers // Array of all pointers of the TSO + ); diff --git a/libraries/ghc-heap/tests/parse_tso_flags.hs b/libraries/ghc-heap/tests/parse_tso_flags.hs new file mode 100644 index 0000000000..51802a32be --- /dev/null +++ b/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 1] + 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] diff --git a/libraries/ghc-heap/tests/tso_and_stack_closures.hs b/libraries/ghc-heap/tests/tso_and_stack_closures.hs new file mode 100644 index 0000000000..42e871bb1f --- /dev/null +++ b/libraries/ghc-heap/tests/tso_and_stack_closures.hs @@ -0,0 +1,167 @@ +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE CPP #-} +{-# LANGUAGE ForeignFunctionInterface #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE MagicHash #-} +{-# LANGUAGE UnboxedTuples #-} + +import Control.Monad (forM_, unless) +import Data.List (find) +import Data.Word +import Foreign +import Foreign.C.Types +import GHC.IO ( IO(..) ) +import GHC.Exts +import GHC.Exts.Heap +import qualified GHC.Exts.Heap.FFIClosures as FFIClosures +import GHC.Word + +import TestUtils + +main :: IO () +main = do + (tso, stack) <- {-# SCC "MyCostCentre" #-} createAndUnpackTSOAndSTACKClosure + assertEqual (getClosureType tso) TSO + assertEqual (what_next tso) ThreadRunGHC + assertEqual (why_blocked tso) NotBlocked + assertEqual (saved_errno tso) 0 + forM_ (flags tso) $ \flag -> case flag of + TsoFlagsUnknownValue _ -> error $ "Unknown flag: " ++ show flag + _ | flag `elem` + [ TsoLocked + , TsoBlockx + , TsoStoppedOnBreakpoint + , TsoSqueezed + ] -> error $ "Unexpected flag: " ++ show flag + _ -> return () + + assertEqual (getClosureType stack) STACK + +#if defined(PROFILING) + let costCentre = ccs_cc <$> (cccs =<< prof tso) + 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 "tso_and_stack_closures.hs:23:48-80") + assertEqual (cc_is_caf myCostCentre) False + Nothing -> error $ "MyCostCentre not found in:\n" ++ unlines (cc_label <$> linkedCostCentres costCentre) +#endif + +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 + +getClosureType :: GenClosure b -> ClosureType +getClosureType = tipe . info + +type StgTso = Any +type StgStack = Any +data MBA a = MBA (MutableByteArray# a) +data BA = BA ByteArray# + +foreign import ccall safe "create_tso.h create_and_unpack_tso_and_stack" + c_create_and_unpack_tso_and_stack + :: Ptr (Ptr StgTso) + -> Ptr (Ptr StgInfoTable) + -> Ptr CInt + -> Ptr (Ptr Word8) + -> Ptr CInt + -> Ptr (Ptr (Ptr Any)) + -> Ptr (Ptr StgStack) + -> Ptr (Ptr StgInfoTable) + -> Ptr CInt + -> Ptr (Ptr Word8) + -> Ptr CInt + -> Ptr (Ptr (Ptr Any)) + -> IO () + +createAndUnpackTSOAndSTACKClosure + :: IO ( GenClosure (Ptr Any) + , GenClosure (Ptr Any) + ) +createAndUnpackTSOAndSTACKClosure = do + + alloca $ \ptrPtrTso -> do + alloca $ \ptrPtrTsoInfoTable -> do + alloca $ \ptrTsoHeapRepSize -> do + alloca $ \ptrPtrTsoHeapRep -> do + alloca $ \ptrTsoPointersSize -> do + alloca $ \ptrPtrPtrTsoPointers -> do + + alloca $ \ptrPtrStack -> do + alloca $ \ptrPtrStackInfoTable -> do + alloca $ \ptrStackHeapRepSize -> do + alloca $ \ptrPtrStackHeapRep -> do + alloca $ \ptrStackPointersSize -> do + alloca $ \ptrPtrPtrStackPointers -> do + + c_create_and_unpack_tso_and_stack + + ptrPtrTso + ptrPtrTsoInfoTable + ptrTsoHeapRepSize + ptrPtrTsoHeapRep + ptrTsoPointersSize + ptrPtrPtrTsoPointers + + ptrPtrStack + ptrPtrStackInfoTable + ptrStackHeapRepSize + ptrPtrStackHeapRep + ptrStackPointersSize + ptrPtrPtrStackPointers + + let fromHeapRep + ptrPtrClosureInfoTable + ptrClosureHeapRepSize + ptrPtrClosureHeapRep + ptrClosurePointersSize + ptrPtrPtrClosurePointers = do + ptrInfoTable :: Ptr StgInfoTable <- peek ptrPtrClosureInfoTable + + heapRepSize :: Int <- fromIntegral <$> peek ptrClosureHeapRepSize + let I# heapRepSize# = heapRepSize + ptrHeapRep :: Ptr Word8 <- peek ptrPtrClosureHeapRep + MBA mutHeapRepBA <- IO $ \s -> let + (# s', mba# #) = newByteArray# heapRepSize# s + in (# s', MBA mba# #) + forM_ [0..heapRepSize-1] $ \i@(I# i#) -> do + W8# w <- peekElemOff ptrHeapRep i + IO (\s -> (# writeWord8Array# mutHeapRepBA i# (extendWord8# w) s, () #)) + BA heapRep <- IO $ \s -> let + (# s', ba# #) = unsafeFreezeByteArray# mutHeapRepBA s + in (# s', BA ba# #) + + pointersSize :: Int <- fromIntegral <$> peek ptrClosurePointersSize + ptrPtrPointers :: Ptr (Ptr Any) <- peek ptrPtrPtrClosurePointers + ptrPtrPointers :: [Ptr Any] <- sequence + [ peekElemOff ptrPtrPointers i + | i <- [0..pointersSize-1] + ] + + getClosureDataFromHeapRep + heapRep + ptrInfoTable + ptrPtrPointers + + tso <- fromHeapRep + ptrPtrTsoInfoTable + ptrTsoHeapRepSize + ptrPtrTsoHeapRep + ptrTsoPointersSize + ptrPtrPtrTsoPointers + + stack <- fromHeapRep + ptrPtrStackInfoTable + ptrStackHeapRepSize + ptrPtrStackHeapRep + ptrStackPointersSize + ptrPtrPtrStackPointers + + return (tso, stack) |