Fix Work Balance computation in RTS stats
[ghc.git] / libraries / base / GHC / Stats.hsc
1 {-# LANGUAGE Trustworthy #-}
2 {-# LANGUAGE NoImplicitPrelude #-}
3 {-# LANGUAGE RecordWildCards #-}
4 {-# OPTIONS_GHC -funbox-strict-fields #-}
5
6 -----------------------------------------------------------------------------
7 -- | This module provides access to internal garbage collection and
8 -- memory usage statistics.  These statistics are not available unless
9 -- a program is run with the @-T@ RTS flag.
10 --
11 -- This module is GHC-only and should not be considered portable.
12 --
13 -- @since 4.5.0.0
14 -----------------------------------------------------------------------------
15 module GHC.Stats
16     (
17     -- * Runtime statistics
18       RTSStats(..), GCDetails(..), RtsTime
19     , getRTSStats
20     , getRTSStatsEnabled
21
22     -- * DEPRECATED, don't use
23     , GCStats(..)
24     , getGCStats
25     , getGCStatsEnabled
26 ) where
27
28 import Control.Applicative
29 import Control.Monad
30 import Data.Int
31 import Data.Word
32 import GHC.Base
33 import GHC.Num (Num(..))
34 import GHC.Real (quot, fromIntegral, (/))
35 import GHC.Read ( Read )
36 import GHC.Show ( Show )
37 import GHC.IO.Exception
38 import Foreign.Marshal.Alloc
39 import Foreign.Storable
40 import Foreign.Ptr
41
42 #include "Rts.h"
43
44 foreign import ccall "getRTSStats" getRTSStats_ :: Ptr () -> IO ()
45
46 -- | Returns whether GC stats have been enabled (with @+RTS -T@, for example).
47 --
48 -- @since 4.9.0.0
49 foreign import ccall "getRTSStatsEnabled" getRTSStatsEnabled :: IO Bool
50
51 --
52 -- | Statistics about runtime activity since the start of the
53 -- program.  This is a mirror of the C @struct RTSStats@ in @RtsAPI.h@
54 --
55 -- @since 4.9.0.0
56 --
57 data RTSStats = RTSStats {
58   -- -----------------------------------
59   -- Cumulative stats about memory use
60
61     -- | Total number of GCs
62     gcs :: Word32
63     -- | Total number of major (oldest generation) GCs
64   , major_gcs :: Word32
65     -- | Total bytes allocated
66   , allocated_bytes :: Word64
67     -- | Maximum live data (including large objects + compact regions)
68   , max_live_bytes :: Word64
69     -- | Maximum live data in large objects
70   , max_large_objects_bytes :: Word64
71     -- | Maximum live data in compact regions
72   , max_compact_bytes :: Word64
73     -- | Maximum slop
74   , max_slop_bytes :: Word64
75     -- | Maximum memory in use by the RTS
76   , max_mem_in_use_bytes :: Word64
77     -- | Sum of live bytes across all major GCs.  Divided by major_gcs
78     -- gives the average live data over the lifetime of the program.
79   , cumulative_live_bytes :: Word64
80     -- | Sum of copied_bytes across all GCs
81   , copied_bytes :: Word64
82     -- | Sum of copied_bytes across all parallel GCs
83   , par_copied_bytes :: Word64
84     -- | Sum of par_max_copied_bytes across all parallel GCs. Deprecated.
85   , cumulative_par_max_copied_bytes :: Word64
86     -- | Sum of par_balanced_copied bytes across all parallel GCs
87   , cumulative_par_balanced_copied_bytes :: Word64
88
89   -- -----------------------------------
90   -- Cumulative stats about time use
91   -- (we use signed values here because due to inaccuracies in timers
92   -- the values can occasionally go slightly negative)
93
94     -- | Total CPU time used by the mutator
95   , mutator_cpu_ns :: RtsTime
96     -- | Total elapsed time used by the mutator
97   , mutator_elapsed_ns :: RtsTime
98     -- | Total CPU time used by the GC
99   , gc_cpu_ns :: RtsTime
100     -- | Total elapsed time used by the GC
101   , gc_elapsed_ns :: RtsTime
102     -- | Total CPU time (at the previous GC)
103   , cpu_ns :: RtsTime
104     -- | Total elapsed time (at the previous GC)
105   , elapsed_ns :: RtsTime
106
107     -- | Details about the most recent GC
108   , gc :: GCDetails
109   } deriving (Read, Show)
110
111 --
112 -- | Statistics about a single GC.  This is a mirror of the C @struct
113 --   GCDetails@ in @RtsAPI.h@, with the field prefixed with @gc_@ to
114 --   avoid collisions with 'RTSStats'.
115 --
116 data GCDetails = GCDetails {
117     -- | The generation number of this GC
118     gcdetails_gen :: Word32
119     -- | Number of threads used in this GC
120   , gcdetails_threads :: Word32
121     -- | Number of bytes allocated since the previous GC
122   , gcdetails_allocated_bytes :: Word64
123     -- | Total amount of live data in the heap (incliudes large + compact data)
124   , gcdetails_live_bytes :: Word64
125     -- | Total amount of live data in large objects
126   , gcdetails_large_objects_bytes :: Word64
127     -- | Total amount of live data in compact regions
128   , gcdetails_compact_bytes :: Word64
129     -- | Total amount of slop (wasted memory)
130   , gcdetails_slop_bytes :: Word64
131     -- | Total amount of memory in use by the RTS
132   , gcdetails_mem_in_use_bytes :: Word64
133     -- | Total amount of data copied during this GC
134   , gcdetails_copied_bytes :: Word64
135     -- | In parallel GC, the max amount of data copied by any one thread.
136     -- Deprecated.
137   , gcdetails_par_max_copied_bytes :: Word64
138     -- | In parallel GC, the amount of balanced data copied by all threads
139   , gcdetails_par_balanced_copied_bytes :: Word64
140     -- | The time elapsed during synchronisation before GC
141   , gcdetails_sync_elapsed_ns :: RtsTime
142     -- | The CPU time used during GC itself
143   , gcdetails_cpu_ns :: RtsTime
144     -- | The time elapsed during GC itself
145   , gcdetails_elapsed_ns :: RtsTime
146   } deriving (Read, Show)
147
148 -- | Time values from the RTS, using a fixed resolution of nanoseconds.
149 type RtsTime = Int64
150
151 -- @since 4.9.0.0
152 --
153 getRTSStats :: IO RTSStats
154 getRTSStats = do
155   statsEnabled <- getGCStatsEnabled
156   unless statsEnabled .  ioError $ IOError
157     Nothing
158     UnsupportedOperation
159     ""
160     "getGCStats: GC stats not enabled. Use `+RTS -T -RTS' to enable them."
161     Nothing
162     Nothing
163   allocaBytes (#size RTSStats) $ \p -> do
164     getRTSStats_ p
165     gcs <- (# peek RTSStats, gcs) p
166     major_gcs <- (# peek RTSStats, major_gcs) p
167     allocated_bytes <- (# peek RTSStats, allocated_bytes) p
168     max_live_bytes <- (# peek RTSStats, max_live_bytes) p
169     max_large_objects_bytes <- (# peek RTSStats, max_large_objects_bytes) p
170     max_compact_bytes <- (# peek RTSStats, max_compact_bytes) p
171     max_slop_bytes <- (# peek RTSStats, max_slop_bytes) p
172     max_mem_in_use_bytes <- (# peek RTSStats, max_mem_in_use_bytes) p
173     cumulative_live_bytes <- (# peek RTSStats, cumulative_live_bytes) p
174     copied_bytes <- (# peek RTSStats, copied_bytes) p
175     par_copied_bytes <- (# peek RTSStats, par_copied_bytes) p
176     cumulative_par_max_copied_bytes <-
177       (# peek RTSStats, cumulative_par_max_copied_bytes) p
178     cumulative_par_balanced_copied_bytes <-
179       (# peek RTSStats, cumulative_par_balanced_copied_bytes) p
180     mutator_cpu_ns <- (# peek RTSStats, mutator_cpu_ns) p
181     mutator_elapsed_ns <- (# peek RTSStats, mutator_elapsed_ns) p
182     gc_cpu_ns <- (# peek RTSStats, gc_cpu_ns) p
183     gc_elapsed_ns <- (# peek RTSStats, gc_elapsed_ns) p
184     cpu_ns <- (# peek RTSStats, cpu_ns) p
185     elapsed_ns <- (# peek RTSStats, elapsed_ns) p
186     let pgc = (# ptr RTSStats, gc) p
187     gc <- do
188       gcdetails_gen <- (# peek GCDetails, gen) pgc
189       gcdetails_threads <- (# peek GCDetails, threads) pgc
190       gcdetails_allocated_bytes <- (# peek GCDetails, allocated_bytes) pgc
191       gcdetails_live_bytes <- (# peek GCDetails, live_bytes) pgc
192       gcdetails_large_objects_bytes <-
193         (# peek GCDetails, large_objects_bytes) pgc
194       gcdetails_compact_bytes <- (# peek GCDetails, compact_bytes) pgc
195       gcdetails_slop_bytes <- (# peek GCDetails, slop_bytes) pgc
196       gcdetails_mem_in_use_bytes <- (# peek GCDetails, mem_in_use_bytes) pgc
197       gcdetails_copied_bytes <- (# peek GCDetails, copied_bytes) pgc
198       gcdetails_par_max_copied_bytes <-
199         (# peek GCDetails, par_max_copied_bytes) pgc
200       gcdetails_par_balanced_copied_bytes <-
201         (# peek GCDetails, par_balanced_copied_bytes) pgc
202       gcdetails_sync_elapsed_ns <- (# peek GCDetails, sync_elapsed_ns) pgc
203       gcdetails_cpu_ns <- (# peek GCDetails, cpu_ns) pgc
204       gcdetails_elapsed_ns <- (# peek GCDetails, elapsed_ns) pgc
205       return GCDetails{..}
206     return RTSStats{..}
207
208 -- -----------------------------------------------------------------------------
209 -- DEPRECATED API
210
211 -- I'm probably violating a bucket of constraints here... oops.
212
213 -- | Statistics about memory usage and the garbage collector. Apart from
214 -- 'currentBytesUsed' and 'currentBytesSlop' all are cumulative values since
215 -- the program started.
216 --
217 -- @since 4.5.0.0
218 {-# DEPRECATED GCStats "Use RTSStats instead.  This will be removed in GHC 8.4.1" #-}
219 data GCStats = GCStats
220     { -- | Total number of bytes allocated
221     bytesAllocated :: !Int64
222     -- | Number of garbage collections performed (any generation, major and
223     -- minor)
224     , numGcs :: !Int64
225     -- | Maximum number of live bytes seen so far
226     , maxBytesUsed :: !Int64
227     -- | Number of byte usage samples taken, or equivalently
228     -- the number of major GCs performed.
229     , numByteUsageSamples :: !Int64
230     -- | Sum of all byte usage samples, can be used with
231     -- 'numByteUsageSamples' to calculate averages with
232     -- arbitrary weighting (if you are sampling this record multiple
233     -- times).
234     , cumulativeBytesUsed :: !Int64
235     -- | Number of bytes copied during GC
236     , bytesCopied :: !Int64
237     -- | Number of live bytes at the end of the last major GC
238     , currentBytesUsed :: !Int64
239     -- | Current number of bytes lost to slop
240     , currentBytesSlop :: !Int64
241     -- | Maximum number of bytes lost to slop at any one time so far
242     , maxBytesSlop :: !Int64
243     -- | Maximum number of megabytes allocated
244     , peakMegabytesAllocated :: !Int64
245     -- | CPU time spent running mutator threads.  This does not include
246     -- any profiling overhead or initialization.
247     , mblocksAllocated :: !Int64 -- ^ Number of allocated megablocks
248     , mutatorCpuSeconds :: !Double
249
250     -- | Wall clock time spent running mutator threads.  This does not
251     -- include initialization.
252     , mutatorWallSeconds :: !Double
253     -- | CPU time spent running GC
254     , gcCpuSeconds :: !Double
255     -- | Wall clock time spent running GC
256     , gcWallSeconds :: !Double
257     -- | Total CPU time elapsed since program start
258     , cpuSeconds :: !Double
259     -- | Total wall clock time elapsed since start
260     , wallSeconds :: !Double
261     -- | Number of bytes copied during GC, minus space held by mutable
262     -- lists held by the capabilities.  Can be used with
263     -- 'parMaxBytesCopied' to determine how well parallel GC utilized
264     -- all cores.
265     , parTotBytesCopied :: !Int64
266
267     -- | Sum of number of bytes copied each GC by the most active GC
268     -- thread each GC.  The ratio of 'parTotBytesCopied' divided by
269     -- 'parMaxBytesCopied' approaches 1 for a maximally sequential
270     -- run and approaches the number of threads (set by the RTS flag
271     -- @-N@) for a maximally parallel run. This is included for
272     -- backwards compatibility; to compute work balance use
273     -- `parBalancedBytesCopied`.
274     , parMaxBytesCopied :: !Int64
275
276     -- | Sum of number of balanced bytes copied on each thread of each GC.
277     -- Balanced bytes are those up to a
278     -- limit = (parTotBytesCopied / num_gc_threads).
279     -- This number is normalized so that when balance is perfect
280     -- @parBalancedBytesCopied =  parTotBytesCopied@ and when all
281     -- gc is done by a single thread @parBalancedBytesCopied = 0@.
282     , parBalancedBytesCopied :: !Int64
283
284     } deriving (Show, Read)
285
286 -- | Retrieves garbage collection and memory statistics as of the last
287 -- garbage collection.  If you would like your statistics as recent as
288 -- possible, first run a 'System.Mem.performGC'.
289 --
290 -- @since 4.5.0.0
291 {-# DEPRECATED getGCStats
292     "Use getRTSStats instead.  This will be removed in GHC 8.4.1" #-}
293 getGCStats :: IO GCStats
294 getGCStats = do
295   statsEnabled <- getGCStatsEnabled
296   unless statsEnabled .  ioError $ IOError
297     Nothing
298     UnsupportedOperation
299     ""
300     "getGCStats: GC stats not enabled. Use `+RTS -T -RTS' to enable them."
301     Nothing
302     Nothing
303   allocaBytes (#size RTSStats) $ \p -> do
304     getRTSStats_ p
305     bytesAllocated <- (# peek RTSStats, allocated_bytes) p
306     numGcs <- (# peek RTSStats, gcs ) p
307     numByteUsageSamples <- (# peek RTSStats, major_gcs ) p
308     maxBytesUsed <- (# peek RTSStats, max_live_bytes ) p
309     cumulativeBytesUsed <- (# peek RTSStats, cumulative_live_bytes ) p
310     bytesCopied <- (# peek RTSStats, copied_bytes ) p
311     currentBytesUsed <- (# peek RTSStats, gc.live_bytes ) p
312     currentBytesSlop <- (# peek RTSStats, gc.slop_bytes) p
313     maxBytesSlop <- (# peek RTSStats, max_slop_bytes) p
314     peakMegabytesAllocated <- do
315       bytes <- (# peek RTSStats, max_mem_in_use_bytes ) p
316       return (bytes `quot` (1024*1024))
317     mblocksAllocated <- do
318       bytes <- (# peek RTSStats, gc.mem_in_use_bytes) p
319       return (bytes `quot` (1024*1024))
320     mutatorCpuSeconds <- nsToSecs <$> (# peek RTSStats, mutator_cpu_ns) p
321     mutatorWallSeconds <-
322       nsToSecs <$> (# peek RTSStats, mutator_elapsed_ns) p
323     gcCpuSeconds <- nsToSecs <$> (# peek RTSStats, gc_cpu_ns) p
324     gcWallSeconds <- nsToSecs <$> (# peek RTSStats, gc_elapsed_ns) p
325     cpuSeconds <- nsToSecs <$> (# peek RTSStats, cpu_ns) p
326     wallSeconds <- nsToSecs <$> (# peek RTSStats, elapsed_ns) p
327     parTotBytesCopied <- (# peek RTSStats, par_copied_bytes) p
328     parMaxBytesCopied <- (# peek RTSStats, cumulative_par_max_copied_bytes) p
329     parBalancedBytesCopied <-
330       (# peek RTSStats, cumulative_par_balanced_copied_bytes) p
331     return GCStats { .. }
332
333 nsToSecs :: Int64 -> Double
334 nsToSecs ns = fromIntegral ns / (# const TIME_RESOLUTION)
335
336 {-# DEPRECATED getGCStatsEnabled
337     "use getRTSStatsEnabled instead.  This will be removed in GHC 8.4.1" #-}
338 getGCStatsEnabled :: IO Bool
339 getGCStatsEnabled = getRTSStatsEnabled