diff options
Diffstat (limited to 'libraries/base/GHC/Stats.hsc')
| -rw-r--r-- | libraries/base/GHC/Stats.hsc | 260 |
1 files changed, 201 insertions, 59 deletions
diff --git a/libraries/base/GHC/Stats.hsc b/libraries/base/GHC/Stats.hsc index a8b43efc8a..ab4012da08 100644 --- a/libraries/base/GHC/Stats.hsc +++ b/libraries/base/GHC/Stats.hsc @@ -13,14 +13,25 @@ -- @since 4.5.0.0 ----------------------------------------------------------------------------- module GHC.Stats - ( GCStats(..) + ( + -- * Runtime statistics + RTSStats(..), GCDetails(..) + , getRTSStats + , getRTSStatsEnabled + + -- * DEPRECATED, don't use + , GCStats(..) , getGCStats , getGCStatsEnabled ) where +import Control.Applicative import Control.Monad import Data.Int +import Data.Word import GHC.Base +import GHC.Num (Num(..)) +import GHC.Real (quot, fromIntegral, (/)) import GHC.Read ( Read ) import GHC.Show ( Show ) import GHC.IO.Exception @@ -30,12 +41,163 @@ import Foreign.Ptr #include "Rts.h" -foreign import ccall "getGCStats" getGCStats_ :: Ptr () -> IO () +foreign import ccall "getRTSStats" getRTSStats_ :: Ptr () -> IO () -- | Returns whether GC stats have been enabled (with @+RTS -T@, for example). -- --- @since 4.6.0.0 -foreign import ccall "getGCStatsEnabled" getGCStatsEnabled :: IO Bool +-- @since 4.9.0.0 +foreign import ccall "getRTSStatsEnabled" getRTSStatsEnabled :: IO Bool + +-- +-- | Statistics about runtime activity since the start of the +-- program. This is a mirror of the C @struct RTSStats@ in @RtsAPI.h@ +-- +-- @since 4.9.0.0 +-- +data RTSStats = RTSStats { + -- ----------------------------------- + -- Cumulative stats about memory use + + -- | Total number of GCs + gcs :: Word32 + -- | Total number of major (oldest generation) GCs + , major_gcs :: Word32 + -- | Total bytes allocated + , allocated_bytes :: Word64 + -- | Maximum live data (including large objects + compact regions) + , max_live_bytes :: Word64 + -- | Maximum live data in large objects + , max_large_objects_bytes :: Word64 + -- | Maximum live data in compact regions + , max_compact_bytes :: Word64 + -- | Maximum slop + , max_slop_bytes :: Word64 + -- | Maximum memory in use by the RTS + , max_mem_in_use_bytes :: Word64 + -- | Sum of live bytes across all major GCs. Divided by major_gcs + -- gives the average live data over the lifetime of the program. + , cumulative_live_bytes :: Word64 + -- | Sum of copied_bytes across all GCs + , copied_bytes :: Word64 + -- | Sum of copied_bytes across all parallel GCs + , par_copied_bytes :: Word64 + -- | Sum of par_max_copied_bytes across all parallel GCs + , cumulative_par_max_copied_bytes :: Word64 + + -- ----------------------------------- + -- Cumulative stats about time use + -- (we use signed values here because due to inacuracies in timers + -- the values can occasionally go slightly negative) + + -- | Total CPU time used by the mutator + , mutator_cpu_ns :: RtsTime + -- | Total elapsed time used by the mutator + , mutator_elapsed_ns :: RtsTime + -- | Total CPU time used by the GC + , gc_cpu_ns :: RtsTime + -- | Total elapsed time used by the GC + , gc_elapsed_ns :: RtsTime + -- | Total CPU time (at the previous GC) + , cpu_ns :: RtsTime + -- | Total elapsed time (at the previous GC) + , elapsed_ns :: RtsTime + + -- | Details about the most recent GC + , gc :: GCDetails + } + +-- +-- | Statistics about a single GC. This is a mirror of the C @struct +-- GCDetails@ in @RtsAPI.h@, with the field prefixed with @gc_@ to +-- avoid collisions with 'RTSStats'. +-- +data GCDetails = GCDetails { + -- | The generation number of this GC + gcdetails_gen :: Word32 + -- | Number of threads used in this GC + , gcdetails_threads :: Word32 + -- | Number of bytes allocated since the previous GC + , gcdetails_allocated_bytes :: Word64 + -- | Total amount of live data in the heap (incliudes large + compact data) + , gcdetails_live_bytes :: Word64 + -- | Total amount of live data in large objects + , gcdetails_large_objects_bytes :: Word64 + -- | Total amount of live data in compact regions + , gcdetails_compact_bytes :: Word64 + -- | Total amount of slop (wasted memory) + , gcdetails_slop_bytes :: Word64 + -- | Total amount of memory in use by the RTS + , gcdetails_mem_in_use_bytes :: Word64 + -- | Total amount of data copied during this GC + , gcdetails_copied_bytes :: Word64 + -- | In parallel GC, the max amount of data copied by any one thread + , gcdetails_par_max_copied_bytes :: Word64 + -- | The time elapsed during synchronisation before GC + , gcdetails_sync_elapsed_ns :: RtsTime + -- | The CPU time used during GC itself + , gcdetails_cpu_ns :: RtsTime + -- | The time elapsed during GC itself + , gcdetails_elapsed_ns :: RtsTime + } + + +type RtsTime = Int64 + +-- @since 4.9.0.0 +-- +getRTSStats :: IO RTSStats +getRTSStats = do + statsEnabled <- getGCStatsEnabled + unless statsEnabled . ioError $ IOError + Nothing + UnsupportedOperation + "" + "getGCStats: GC stats not enabled. Use `+RTS -T -RTS' to enable them." + Nothing + Nothing + allocaBytes (#size RTSStats) $ \p -> do + getRTSStats_ p + gcs <- (# peek RTSStats, gcs) p + major_gcs <- (# peek RTSStats, major_gcs) p + allocated_bytes <- (# peek RTSStats, allocated_bytes) p + max_live_bytes <- (# peek RTSStats, max_live_bytes) p + max_large_objects_bytes <- (# peek RTSStats, max_large_objects_bytes) p + max_compact_bytes <- (# peek RTSStats, max_compact_bytes) p + max_slop_bytes <- (# peek RTSStats, max_slop_bytes) p + max_mem_in_use_bytes <- (# peek RTSStats, max_mem_in_use_bytes) p + cumulative_live_bytes <- (# peek RTSStats, cumulative_live_bytes) p + copied_bytes <- (# peek RTSStats, copied_bytes) p + par_copied_bytes <- (# peek RTSStats, par_copied_bytes) p + cumulative_par_max_copied_bytes <- + (# peek RTSStats, cumulative_par_max_copied_bytes) p + mutator_cpu_ns <- (# peek RTSStats, mutator_cpu_ns) p + mutator_elapsed_ns <- (# peek RTSStats, mutator_elapsed_ns) p + gc_cpu_ns <- (# peek RTSStats, gc_cpu_ns) p + gc_elapsed_ns <- (# peek RTSStats, gc_elapsed_ns) p + cpu_ns <- (# peek RTSStats, cpu_ns) p + elapsed_ns <- (# peek RTSStats, elapsed_ns) p + let pgc = (# ptr RTSStats, gc) p + gc <- do + gcdetails_gen <- (# peek GCDetails, gen) pgc + gcdetails_threads <- (# peek GCDetails, threads) pgc + gcdetails_allocated_bytes <- (# peek GCDetails, allocated_bytes) pgc + gcdetails_live_bytes <- (# peek GCDetails, live_bytes) pgc + gcdetails_large_objects_bytes <- + (# peek GCDetails, large_objects_bytes) pgc + gcdetails_compact_bytes <- (# peek GCDetails, compact_bytes) pgc + gcdetails_slop_bytes <- (# peek GCDetails, slop_bytes) pgc + gcdetails_mem_in_use_bytes <- (# peek GCDetails, mem_in_use_bytes) pgc + gcdetails_copied_bytes <- (# peek GCDetails, copied_bytes) pgc + gcdetails_par_max_copied_bytes <- + (# peek GCDetails, par_max_copied_bytes) pgc + gcdetails_sync_elapsed_ns <- (# peek GCDetails, sync_elapsed_ns) pgc + gcdetails_cpu_ns <- (# peek GCDetails, cpu_ns) pgc + gcdetails_elapsed_ns <- (# peek GCDetails, elapsed_ns) pgc + return GCDetails{..} + return RTSStats{..} + +-- ----------------------------------------------------------------------------- +-- DEPRECATED API -- I'm probably violating a bucket of constraints here... oops. @@ -44,6 +206,7 @@ foreign import ccall "getGCStatsEnabled" getGCStatsEnabled :: IO Bool -- the program started. -- -- @since 4.5.0.0 +{-# DEPRECATED GCStats "Use RTSStats instead. This will be removed in GHC 8.4.1" #-} data GCStats = GCStats { -- | Total number of bytes allocated bytesAllocated :: !Int64 @@ -100,16 +263,13 @@ data GCStats = GCStats , parMaxBytesCopied :: !Int64 } deriving (Show, Read) - {- - , initCpuSeconds :: !Double - , initWallSeconds :: !Double - -} - -- | Retrieves garbage collection and memory statistics as of the last -- garbage collection. If you would like your statistics as recent as -- possible, first run a 'System.Mem.performGC'. -- -- @since 4.5.0.0 +{-# DEPRECATED getGCStats + "Use getRTSStats instead. This will be removed in GHC 8.4.1" #-} getGCStats :: IO GCStats getGCStats = do statsEnabled <- getGCStatsEnabled @@ -120,56 +280,38 @@ getGCStats = do "getGCStats: GC stats not enabled. Use `+RTS -T -RTS' to enable them." Nothing Nothing - allocaBytes (#size GCStats) $ \p -> do - getGCStats_ p - bytesAllocated <- (# peek GCStats, bytes_allocated) p - numGcs <- (# peek GCStats, num_gcs ) p - numByteUsageSamples <- (# peek GCStats, num_byte_usage_samples ) p - maxBytesUsed <- (# peek GCStats, max_bytes_used ) p - cumulativeBytesUsed <- (# peek GCStats, cumulative_bytes_used ) p - bytesCopied <- (# peek GCStats, bytes_copied ) p - currentBytesUsed <- (# peek GCStats, current_bytes_used ) p - currentBytesSlop <- (# peek GCStats, current_bytes_slop) p - maxBytesSlop <- (# peek GCStats, max_bytes_slop) p - peakMegabytesAllocated <- (# peek GCStats, peak_megabytes_allocated ) p - mblocksAllocated <- (# peek GCStats, mblocks_allocated) p - {- - initCpuSeconds <- (# peek GCStats, init_cpu_seconds) p - initWallSeconds <- (# peek GCStats, init_wall_seconds) p - -} - mutatorCpuSeconds <- (# peek GCStats, mutator_cpu_seconds) p - mutatorWallSeconds <- (# peek GCStats, mutator_wall_seconds) p - gcCpuSeconds <- (# peek GCStats, gc_cpu_seconds) p - gcWallSeconds <- (# peek GCStats, gc_wall_seconds) p - cpuSeconds <- (# peek GCStats, cpu_seconds) p - wallSeconds <- (# peek GCStats, wall_seconds) p - parTotBytesCopied <- (# peek GCStats, par_tot_bytes_copied) p - parMaxBytesCopied <- (# peek GCStats, par_max_bytes_copied) p + allocaBytes (#size RTSStats) $ \p -> do + getRTSStats_ p + bytesAllocated <- (# peek RTSStats, allocated_bytes) p + numGcs <- (# peek RTSStats, gcs ) p + numByteUsageSamples <- (# peek RTSStats, major_gcs ) p + maxBytesUsed <- (# peek RTSStats, max_live_bytes ) p + cumulativeBytesUsed <- (# peek RTSStats, cumulative_live_bytes ) p + bytesCopied <- (# peek RTSStats, copied_bytes ) p + currentBytesUsed <- (# peek RTSStats, gc.live_bytes ) p + currentBytesSlop <- (# peek RTSStats, gc.slop_bytes) p + maxBytesSlop <- (# peek RTSStats, max_slop_bytes) p + peakMegabytesAllocated <- do + bytes <- (# peek RTSStats, max_mem_in_use_bytes ) p + return (bytes `quot` (1024*1024)) + mblocksAllocated <- do + bytes <- (# peek RTSStats, gc.mem_in_use_bytes) p + return (bytes `quot` (1024*1024)) + mutatorCpuSeconds <- nsToSecs <$> (# peek RTSStats, mutator_cpu_ns) p + mutatorWallSeconds <- + nsToSecs <$> (# peek RTSStats, mutator_elapsed_ns) p + gcCpuSeconds <- nsToSecs <$> (# peek RTSStats, gc_cpu_ns) p + gcWallSeconds <- nsToSecs <$> (# peek RTSStats, gc_elapsed_ns) p + cpuSeconds <- nsToSecs <$> (# peek RTSStats, cpu_ns) p + wallSeconds <- nsToSecs <$> (# peek RTSStats, elapsed_ns) p + parTotBytesCopied <- (# peek RTSStats, par_copied_bytes) p + parMaxBytesCopied <- (# peek RTSStats, cumulative_par_max_copied_bytes) p return GCStats { .. } -{- - --- Nontrivial to implement: TaskStats needs arbitrarily large --- amounts of memory, spark stats wants to use SparkCounters --- but that needs a new rts/ header. - -data TaskStats = TaskStats - { taskMutCpuSeconds :: Int64 - , taskMutWallSeconds :: Int64 - , taskGcCpuSeconds :: Int64 - , taskGcWallSeconds :: Int64 - } deriving (Show, Read) - -data SparkStats = SparkStats - { sparksCreated :: Int64 - , sparksDud :: Int64 - , sparksOverflowed :: Int64 - , sparksConverted :: Int64 - , sparksGcd :: Int64 - , sparksFizzled :: Int64 - } deriving (Show, Read) - --- We also could get per-generation stats, which requires a --- non-constant but at runtime known about of memory. +nsToSecs :: Int64 -> Double +nsToSecs ns = fromIntegral ns / (# const TIME_RESOLUTION) --} +{-# DEPRECATED getGCStatsEnabled + "use getRTSStatsEnabled instead. This will be removed in GHC 8.4.1" #-} +getGCStatsEnabled :: IO Bool +getGCStatsEnabled = getRTSStatsEnabled |
