{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE UnliftedFFITypes #-}
module Cardano.Prelude.GHC.Heap.Size (
CountFailure(..)
, PerformGC(..)
, computeHeapSize
, computeHeapSize'
, computeHeapSizeWorkList
) where
import Cardano.Prelude.Base hiding (Any)
import Foreign.C.Types
import Foreign.Marshal.Alloc
import Foreign.StablePtr
import Foreign.Storable
import GHC.Exts.Heap.ClosureTypes (ClosureType)
import GHC.Prim
import GHC.Types
import System.Mem (performMajorGC)
cNO_FAILURE, cWORK_LIST_FULL, cVISITED_FULL, cOUT_OF_MEMORY, cUNSUPPORTED_CLOSURE :: CUInt
cNO_FAILURE :: CUInt
cNO_FAILURE = CUInt
0
cWORK_LIST_FULL :: CUInt
cWORK_LIST_FULL = CUInt
1
cVISITED_FULL :: CUInt
cVISITED_FULL = CUInt
2
cOUT_OF_MEMORY :: CUInt
cOUT_OF_MEMORY = CUInt
3
cUNSUPPORTED_CLOSURE :: CUInt
cUNSUPPORTED_CLOSURE = CUInt
4
data CountFailure =
WorkListFull
| VisitedFull
| OutOfMemory
| UnsupportedClosure ClosureType
deriving (Int -> CountFailure -> ShowS
[CountFailure] -> ShowS
CountFailure -> String
(Int -> CountFailure -> ShowS)
-> (CountFailure -> String)
-> ([CountFailure] -> ShowS)
-> Show CountFailure
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [CountFailure] -> ShowS
$cshowList :: [CountFailure] -> ShowS
show :: CountFailure -> String
$cshow :: CountFailure -> String
showsPrec :: Int -> CountFailure -> ShowS
$cshowsPrec :: Int -> CountFailure -> ShowS
Show, CountFailure -> CountFailure -> Bool
(CountFailure -> CountFailure -> Bool)
-> (CountFailure -> CountFailure -> Bool) -> Eq CountFailure
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: CountFailure -> CountFailure -> Bool
$c/= :: CountFailure -> CountFailure -> Bool
== :: CountFailure -> CountFailure -> Bool
$c== :: CountFailure -> CountFailure -> Bool
Eq)
toCountFailure :: CUInt -> Maybe CountFailure
toCountFailure :: CUInt -> Maybe CountFailure
toCountFailure CUInt
n
| CUInt
n CUInt -> CUInt -> Bool
forall a. Eq a => a -> a -> Bool
== CUInt
cNO_FAILURE = Maybe CountFailure
forall a. Maybe a
Nothing
| CUInt
n CUInt -> CUInt -> Bool
forall a. Eq a => a -> a -> Bool
== CUInt
cWORK_LIST_FULL = CountFailure -> Maybe CountFailure
forall a. a -> Maybe a
Just (CountFailure -> Maybe CountFailure)
-> CountFailure -> Maybe CountFailure
forall a b. (a -> b) -> a -> b
$ CountFailure
WorkListFull
| CUInt
n CUInt -> CUInt -> Bool
forall a. Eq a => a -> a -> Bool
== CUInt
cVISITED_FULL = CountFailure -> Maybe CountFailure
forall a. a -> Maybe a
Just (CountFailure -> Maybe CountFailure)
-> CountFailure -> Maybe CountFailure
forall a b. (a -> b) -> a -> b
$ CountFailure
VisitedFull
| CUInt
n CUInt -> CUInt -> Bool
forall a. Eq a => a -> a -> Bool
== CUInt
cOUT_OF_MEMORY = CountFailure -> Maybe CountFailure
forall a. a -> Maybe a
Just (CountFailure -> Maybe CountFailure)
-> CountFailure -> Maybe CountFailure
forall a b. (a -> b) -> a -> b
$ CountFailure
OutOfMemory
| CUInt
n CUInt -> CUInt -> Bool
forall a. Ord a => a -> a -> Bool
>= CUInt
cUNSUPPORTED_CLOSURE = CountFailure -> Maybe CountFailure
forall a. a -> Maybe a
Just (CountFailure -> Maybe CountFailure)
-> CountFailure -> Maybe CountFailure
forall a b. (a -> b) -> a -> b
$ ClosureType -> CountFailure
UnsupportedClosure ClosureType
typ
| Bool
otherwise = Text -> Maybe CountFailure
forall a. HasCallStack => Text -> a
panic Text
"getCountFailure: impossible"
where
typ :: ClosureType
typ :: ClosureType
typ = Int -> ClosureType
forall a. Enum a => Int -> a
toEnum (CUInt -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CUInt
n CUInt -> CUInt -> CUInt
forall a. Num a => a -> a -> a
- CUInt
cUNSUPPORTED_CLOSURE))
foreign import ccall unsafe "hs_cardanoprelude_closureSize"
closureSize_ :: CUInt -> CUInt -> CUInt -> Ptr CUInt -> StablePtr a -> IO CULong
data PerformGC =
FirstPerformGC
| DontPerformGC
closureSize :: PerformGC -> CUInt -> CUInt -> CUInt -> Ptr CUInt -> a -> IO CULong
closureSize :: PerformGC -> CUInt -> CUInt -> CUInt -> Ptr CUInt -> a -> IO CULong
closureSize PerformGC
performGC
CUInt
workListCapacity
CUInt
visitedInitCapacity
CUInt
visitedMaxCapacity
Ptr CUInt
err
a
a
= do
case PerformGC
performGC of
PerformGC
FirstPerformGC -> IO ()
performMajorGC
PerformGC
DontPerformGC -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
IO (StablePtr a)
-> (StablePtr a -> IO ())
-> (StablePtr a -> IO CULong)
-> IO CULong
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket (a -> IO (StablePtr a)
forall a. a -> IO (StablePtr a)
newStablePtr a
a) StablePtr a -> IO ()
forall a. StablePtr a -> IO ()
freeStablePtr ((StablePtr a -> IO CULong) -> IO CULong)
-> (StablePtr a -> IO CULong) -> IO CULong
forall a b. (a -> b) -> a -> b
$ \StablePtr a
stablePtr ->
CUInt -> CUInt -> CUInt -> Ptr CUInt -> StablePtr a -> IO CULong
forall a.
CUInt -> CUInt -> CUInt -> Ptr CUInt -> StablePtr a -> IO CULong
closureSize_ CUInt
workListCapacity
CUInt
visitedInitCapacity
CUInt
visitedMaxCapacity
Ptr CUInt
err
StablePtr a
stablePtr
computeHeapSize' :: PerformGC
-> Word
-> Word
-> Word
-> a -> IO (Either CountFailure Word64)
computeHeapSize' :: PerformGC
-> Word -> Word -> Word -> a -> IO (Either CountFailure Word64)
computeHeapSize' PerformGC
performGC
Word
workListCapacity
Word
visitedInitCapacity
Word
visitedMaxCapacity
a
a
= do
(Ptr CUInt -> IO (Either CountFailure Word64))
-> IO (Either CountFailure Word64)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CUInt -> IO (Either CountFailure Word64))
-> IO (Either CountFailure Word64))
-> (Ptr CUInt -> IO (Either CountFailure Word64))
-> IO (Either CountFailure Word64)
forall a b. (a -> b) -> a -> b
$ \(Ptr CUInt
err :: Ptr CUInt) -> do
CULong
size <- PerformGC -> CUInt -> CUInt -> CUInt -> Ptr CUInt -> a -> IO CULong
forall a.
PerformGC -> CUInt -> CUInt -> CUInt -> Ptr CUInt -> a -> IO CULong
closureSize PerformGC
performGC
CUInt
workListCapacity'
CUInt
visitedInitCapacity'
CUInt
visitedMaxCapacity'
Ptr CUInt
err
a
a
Maybe CountFailure
mFailure <- CUInt -> Maybe CountFailure
toCountFailure (CUInt -> Maybe CountFailure)
-> IO CUInt -> IO (Maybe CountFailure)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ptr CUInt -> IO CUInt
forall a. Storable a => Ptr a -> IO a
peek Ptr CUInt
err
Either CountFailure Word64 -> IO (Either CountFailure Word64)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either CountFailure Word64 -> IO (Either CountFailure Word64))
-> Either CountFailure Word64 -> IO (Either CountFailure Word64)
forall a b. (a -> b) -> a -> b
$ case Maybe CountFailure
mFailure of
Just CountFailure
failure -> CountFailure -> Either CountFailure Word64
forall a b. a -> Either a b
Left CountFailure
failure
Maybe CountFailure
Nothing -> Word64 -> Either CountFailure Word64
forall a b. b -> Either a b
Right (CULong -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral CULong
size)
where
workListCapacity', visitedInitCapacity', visitedMaxCapacity' :: CUInt
workListCapacity' :: CUInt
workListCapacity' = Word -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word
workListCapacity
visitedInitCapacity' :: CUInt
visitedInitCapacity' = Word -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word
visitedInitCapacity
visitedMaxCapacity' :: CUInt
visitedMaxCapacity' = Word -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word
visitedMaxCapacity
computeHeapSize :: a -> IO (Either CountFailure Word64)
computeHeapSize :: a -> IO (Either CountFailure Word64)
computeHeapSize =
PerformGC
-> Word -> Word -> Word -> a -> IO (Either CountFailure Word64)
forall a.
PerformGC
-> Word -> Word -> Word -> a -> IO (Either CountFailure Word64)
computeHeapSize' PerformGC
DontPerformGC
Word
workListCapacity
Word
visitedInitCapacity
Word
visitedMaxCapacity
where
workListCapacity, visitedInitCapacity, visitedMaxCapacity :: Word
workListCapacity :: Word
workListCapacity = Word
10 Word -> Word -> Word
forall a. Num a => a -> a -> a
* Word
1000
visitedInitCapacity :: Word
visitedInitCapacity = Word
250 Word -> Word -> Word
forall a. Num a => a -> a -> a
* Word
1000
visitedMaxCapacity :: Word
visitedMaxCapacity = Word
16 Word -> Word -> Word
forall a. Num a => a -> a -> a
* Word
1000 Word -> Word -> Word
forall a. Num a => a -> a -> a
* Word
1000
computeHeapSizeWorkList :: a -> Word64
computeHeapSizeWorkList :: a -> Word64
computeHeapSizeWorkList a
a =
[Word64] -> Word64
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum ([Word64] -> Word64) -> [Word64] -> Word64
forall a b. (a -> b) -> a -> b
$ Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int# -> Int
I# (Array# Any -> Int#
forall a. Array# a -> Int#
sizeofArray# Array# Any
ptrs))
Word64 -> [Word64] -> [Word64]
forall a. a -> [a] -> [a]
: ((Any, Word64) -> Word64) -> [(Any, Word64)] -> [Word64]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map (Any, Word64) -> Word64
nested ([(Any, Word64)] -> Int# -> [(Any, Word64)]
collect [] Int#
0#)
where
ptrs :: Array# Any
!(# Addr#
_addr, ByteArray#
_raw, Array# Any
ptrs #) = a -> (# Addr#, ByteArray#, Array# Any #)
forall a b. a -> (# Addr#, ByteArray#, Array# b #)
unpackClosure# a
a
nested :: (Any, Word64) -> Word64
nested :: (Any, Word64) -> Word64
nested (Any
p, Word64
n) = Any -> Word64
forall a. a -> Word64
computeHeapSizeWorkList Any
p Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ Word64
n
collect :: [(Any, Word64)] -> Int# -> [(Any, Word64)]
collect :: [(Any, Word64)] -> Int# -> [(Any, Word64)]
collect [(Any, Word64)]
acc Int#
ix =
case Int#
ix Int# -> Int# -> Int#
<# Array# Any -> Int#
forall a. Array# a -> Int#
sizeofArray# Array# Any
ptrs of
Int#
0# -> [(Any, Word64)]
acc
Int#
_ -> let n :: Word64
!n :: Word64
n = Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int# -> Int
I# (Array# Any -> Int#
forall a. Array# a -> Int#
sizeofArray# Array# Any
ptrs Int# -> Int# -> Int#
-# (Int#
ix Int# -> Int# -> Int#
+# Int#
1#)))
in case Array# Any -> Int# -> (# Any #)
forall a. Array# a -> Int# -> (# a #)
indexArray# Array# Any
ptrs Int#
ix of
(# Any
p #) -> [(Any, Word64)] -> Int# -> [(Any, Word64)]
collect ((Any
p, Word64
n) (Any, Word64) -> [(Any, Word64)] -> [(Any, Word64)]
forall a. a -> [a] -> [a]
: [(Any, Word64)]
acc) (Int#
ix Int# -> Int# -> Int#
+# Int#
1#)