Merge branch 'master' of darcs.haskell.org:/srv/darcs//packages/base
[packages/base.git] / GHC / Stats.hsc
1 {-# LANGUAGE Safe #-}
2 {-# LANGUAGE CPP #-}
3 {-# LANGUAGE ForeignFunctionInterface #-}
4 {-# LANGUAGE RecordWildCards #-}
5 {-# OPTIONS_GHC -funbox-strict-fields #-}
6
7 -----------------------------------------------------------------------------
8 -- | This module provides access to internal garbage collection and
9 -- memory usage statistics.  These statistics are not available unless
10 -- a program is run with the @-T@ RTS flag.
11 --
12 -- This module is GHC-only and should not be considered portable.
13 --
14 -----------------------------------------------------------------------------
15 module GHC.Stats
16     ( GCStats(..)
17     , getGCStats
18     , getGCStatsEnabled
19 ) where
20
21 import Control.Monad
22 import Data.Int
23 import GHC.IO.Exception
24 import Foreign.Marshal.Alloc
25 import Foreign.Storable
26 import Foreign.Ptr
27
28 #include "Rts.h"
29
30 foreign import ccall "getGCStats"        getGCStats_       :: Ptr () -> IO ()
31 foreign import ccall "getGCStatsEnabled" getGCStatsEnabled :: IO Bool
32
33 -- I'm probably violating a bucket of constraints here... oops.
34
35 -- | Global garbage collection and memory statistics.
36 data GCStats = GCStats
37     { bytesAllocated :: !Int64 -- ^ Total number of bytes allocated
38     , numGcs :: !Int64 -- ^ Number of garbage collections performed
39     , maxBytesUsed :: !Int64 -- ^ Maximum number of live bytes seen so far
40     , numByteUsageSamples :: !Int64 -- ^ Number of byte usage samples taken
41     -- | Sum of all byte usage samples, can be used with
42     -- 'numByteUsageSamples' to calculate averages with
43     -- arbitrary weighting (if you are sampling this record multiple
44     -- times).
45     , cumulativeBytesUsed :: !Int64
46     , bytesCopied :: !Int64 -- ^ Number of bytes copied during GC
47     , currentBytesUsed :: !Int64 -- ^ Current number of live bytes
48     , currentBytesSlop :: !Int64 -- ^ Current number of bytes lost to slop
49     , maxBytesSlop :: !Int64 -- ^ Maximum number of bytes lost to slop at any one time so far
50     , peakMegabytesAllocated :: !Int64 -- ^ Maximum number of megabytes allocated
51     -- | CPU time spent running mutator threads.  This does not include
52     -- any profiling overhead or initialization.
53     , mutatorCpuSeconds :: !Double
54     -- | Wall clock time spent running mutator threads.  This does not
55     -- include initialization.
56     , mutatorWallSeconds :: !Double
57     , gcCpuSeconds :: !Double -- ^ CPU time spent running GC
58     , gcWallSeconds :: !Double -- ^ Wall clock time spent running GC
59     , cpuSeconds :: !Double -- ^ Total CPU time elapsed since program start
60     , wallSeconds :: !Double -- ^ Total wall clock time elapsed since start
61     -- | Number of bytes copied during GC, minus space held by mutable
62     -- lists held by the capabilities.  Can be used with
63     -- 'parMaxBytesCopied' to determine how well parallel GC utilized
64     -- all cores.
65     , parTotBytesCopied :: !Int64
66     -- | Sum of number of bytes copied each GC by the most active GC
67     -- thread each GC.  The ratio of 'parTotBytesCopied' divided by
68     -- 'parMaxBytesCopied' approaches 1 for a maximally sequential
69     -- run and approaches the number of threads (set by the RTS flag
70     -- @-N@) for a maximally parallel run.
71     , parMaxBytesCopied :: !Int64
72     } deriving (Show, Read)
73
74     {-
75     , initCpuSeconds :: !Double
76     , initWallSeconds :: !Double
77     -}
78
79 -- | Retrieves garbage collection and memory statistics as of the last
80 -- garbage collection.  If you would like your statistics as recent as
81 -- possible, first run a 'System.Mem.performGC'.
82 getGCStats :: IO GCStats
83 getGCStats = do
84   statsEnabled <- getGCStatsEnabled
85   unless statsEnabled .  ioError $ IOError
86     Nothing
87     UnsupportedOperation
88     ""
89     "getGCStats: GC stats not enabled. Use `+RTS -T -RTS' to enable them."
90     Nothing
91     Nothing
92   allocaBytes (#size GCStats) $ \p -> do
93     getGCStats_ p
94     bytesAllocated <- (# peek GCStats, bytes_allocated) p
95     numGcs <- (# peek GCStats, num_gcs ) p
96     numByteUsageSamples <- (# peek GCStats, num_byte_usage_samples ) p
97     maxBytesUsed <- (# peek GCStats, max_bytes_used ) p
98     cumulativeBytesUsed <- (# peek GCStats, cumulative_bytes_used ) p
99     bytesCopied <- (# peek GCStats, bytes_copied ) p
100     currentBytesUsed <- (# peek GCStats, current_bytes_used ) p
101     currentBytesSlop <- (# peek GCStats, current_bytes_slop) p
102     maxBytesSlop <- (# peek GCStats, max_bytes_slop) p
103     peakMegabytesAllocated <- (# peek GCStats, peak_megabytes_allocated ) p
104     {-
105     initCpuSeconds <- (# peek GCStats, init_cpu_seconds) p
106     initWallSeconds <- (# peek GCStats, init_wall_seconds) p
107     -}
108     mutatorCpuSeconds <- (# peek GCStats, mutator_cpu_seconds) p
109     mutatorWallSeconds <- (# peek GCStats, mutator_wall_seconds) p
110     gcCpuSeconds <- (# peek GCStats, gc_cpu_seconds) p
111     gcWallSeconds <- (# peek GCStats, gc_wall_seconds) p
112     cpuSeconds <- (# peek GCStats, cpu_seconds) p
113     wallSeconds <- (# peek GCStats, wall_seconds) p
114     parTotBytesCopied <- (# peek GCStats, par_tot_bytes_copied) p
115     parMaxBytesCopied <- (# peek GCStats, par_max_bytes_copied) p
116     return GCStats { .. }
117
118 {-
119
120 -- Nontrivial to implement: TaskStats needs arbitrarily large
121 -- amounts of memory, spark stats wants to use SparkCounters
122 -- but that needs a new rts/ header.
123
124 data TaskStats = TaskStats
125     { taskMutCpuSeconds :: Int64
126     , taskMutWallSeconds :: Int64
127     , taskGcCpuSeconds :: Int64
128     , taskGcWallSeconds :: Int64
129     } deriving (Show, Read)
130
131 data SparkStats = SparkStats
132     { sparksCreated :: Int64
133     , sparksDud :: Int64
134     , sparksOverflowed :: Int64
135     , sparksConverted :: Int64
136     , sparksGcd :: Int64
137     , sparksFizzled :: Int64
138     } deriving (Show, Read)
139
140 -- We also could get per-generation stats, which requires a
141 -- non-constant but at runtime known about of memory.
142
143 -}