Commit 24e6594c authored by Simon Marlow's avatar Simon Marlow

Overhaul GC stats

Summary:
Visible API changes:

* The C struct `GCDetails` gives the stats about a single GC.  This is
  passed to the `gcDone()` callback if one is set via the
  RtsConfig. (previously we just passed a collection of values, so this
  is more extensible, at the expense of breaking the existing API)

* `RTSStats` gives cumulative stats since the start of the program,
  and includes the `GCDetails` for the most recent GC.  This struct
  can be obtained via `getRTSStats()` (the old `getGCStats()` has been
  removed, and `getGCStatsEnabled()` has been renamed to
  `getRTSStatsEnabled()`)

Improvements:

* The per-GC stats and cumulative stats are now cleanly separated.

* Inside the RTS we have a top-level `RTSStats` struct to keep all our
  stats in, previously this was just a collection of strangely-named
  variables.  This struct is mostly just copied in `getRTSStats()`, so
  the implementation of that function is a lot shorter.

* Types are more consistent.  We use a uint64_t byte count for all
  memory values, and Time for all time values.

* Names are more consistent.  We use a suffix `_bytes` for all byte
  counts and `_ns` for all time values.

* We now collect information about the amount of memory in large
  objects and compact objects in `GCDetails`. (the latter was the reason
  I started doing this patch but it seems to have ballooned a bit!)

* I fixed a bug in the calculation of the elapsed MUT time, and added
  an ASSERT to stop the calculations going wrong in the future.

For now I kept the Haskell API in `GHC.Stats` the same, by
impedence-matching with the new API.  We could either break that API
and make it match the C API more closely, or we could add a new API
and deprecate the old one.  Opinions welcome.

This stuff is very easy to get wrong, and it's hard to test.  Reviews
welcome!

Test Plan:
manual testing
validate

Reviewers: bgamari, niteria, austin, ezyang, hvr, erikd, rwbarton, Phyx

Subscribers: thomie

Differential Revision: https://phabricator.haskell.org/D2756
parent eec02ab7
......@@ -39,6 +39,7 @@ extern "C" {
#endif
#include "rts/Types.h"
#include "rts/Time.h"
#if __GNUC__ >= 3
#define ATTRIBUTE_ALIGNED(n) __attribute__((aligned(n)))
......@@ -144,38 +145,6 @@ void _assertFail(const char *filename, unsigned int linenum)
#define FMT_SizeT "zu"
#define FMT_HexSizeT "zx"
/* -----------------------------------------------------------------------------
Time values in the RTS
-------------------------------------------------------------------------- */
// For most time values in the RTS we use a fixed resolution of nanoseconds,
// normalising the time we get from platform-dependent APIs to this
// resolution.
#define TIME_RESOLUTION 1000000000
typedef StgInt64 Time;
#define TIME_MAX HS_INT64_MAX
#if TIME_RESOLUTION == 1000000000
// I'm being lazy, but it's awkward to define fully general versions of these
#define TimeToUS(t) ((t) / 1000)
#define TimeToNS(t) (t)
#define USToTime(t) ((Time)(t) * 1000)
#define NSToTime(t) ((Time)(t))
#else
#error Fix TimeToNS(), TimeToUS() etc.
#endif
#define SecondsToTime(t) ((Time)(t) * TIME_RESOLUTION)
#define TimeToSeconds(t) ((t) / TIME_RESOLUTION)
// Use instead of SecondsToTime() when we have a floating-point
// seconds value, to avoid truncating it.
INLINE_HEADER Time fsecondsToTime (double t)
{
return (Time)(t * TIME_RESOLUTION);
}
/* -----------------------------------------------------------------------------
Include everything STG-ish
-------------------------------------------------------------------------- */
......
......@@ -17,6 +17,7 @@ extern "C" {
#endif
#include "HsFFI.h"
#include "rts/Time.h"
/*
* Running the scheduler
......@@ -56,6 +57,8 @@ typedef enum {
RtsOptsAll // all RTS options allowed
} RtsOptsEnabledEnum;
struct GCDetails_;
// The RtsConfig struct is passed (by value) to hs_init_ghc(). The
// reason for using a struct is extensibility: we can add more
// fields to this later without breaking existing client code.
......@@ -93,15 +96,7 @@ typedef struct {
void (* mallocFailHook) (W_ request_size /* in bytes */, const char *msg);
// Called for every GC
void (* gcDoneHook) (unsigned int gen,
W_ allocated_bytes, /* since last GC */
W_ live_bytes,
W_ copied_bytes,
W_ max_copied_per_thread_bytes,
W_ total_bytes,
W_ slop_bytes,
W_ sync_elapsed_ns, W_ elapsed_ns, W_ cpu_ns);
void (* gcDoneHook) (const struct GCDetails_ *stats);
} RtsConfig;
// Clients should start with defaultRtsConfig and then customise it.
......@@ -109,6 +104,108 @@ typedef struct {
// you can't do that in C (it generates code).
extern const RtsConfig defaultRtsConfig;
/* -----------------------------------------------------------------------------
Statistics
-------------------------------------------------------------------------- */
//
// Stats about a single GC
//
typedef struct GCDetails_ {
// The generation number of this GC
uint32_t gen;
// Number of threads used in this GC
uint32_t threads;
// Number of bytes allocated since the previous GC
uint64_t allocated_bytes;
// Total amount of live data in the heap (incliudes large + compact data)
uint64_t live_bytes;
// Total amount of live data in large objects
uint64_t large_objects_bytes;
// Total amount of live data in compact regions
uint64_t compact_bytes;
// Total amount of slop (wasted memory)
uint64_t slop_bytes;
// Total amount of memory in use by the RTS
uint64_t mem_in_use_bytes;
// Total amount of data copied during this GC
uint64_t copied_bytes;
// In parallel GC, the max amount of data copied by any one thread
uint64_t par_max_copied_bytes;
// The time elapsed during synchronisation before GC
Time sync_elapsed_ns;
// The CPU time used during GC itself
Time cpu_ns;
// The time elapsed during GC itself
Time elapsed_ns;
} GCDetails;
//
// Stats about the RTS currently, and since the start of execution
//
typedef struct _RTSStats {
// -----------------------------------
// Cumulative stats about memory use
// Total number of GCs
uint32_t gcs;
// Total number of major (oldest generation) GCs
uint32_t major_gcs;
// Total bytes allocated
uint64_t allocated_bytes;
// Maximum live data (including large objects + compact regions)
uint64_t max_live_bytes;
// Maximum live data in large objects
uint64_t max_large_objects_bytes;
// Maximum live data in compact regions
uint64_t max_compact_bytes;
// Maximum slop
uint64_t max_slop_bytes;
// Maximum memory in use by the RTS
uint64_t max_mem_in_use_bytes;
// Sum of live bytes across all major GCs. Divided by major_gcs
// gives the average live data over the lifetime of the program.
uint64_t cumulative_live_bytes;
// Sum of copied_bytes across all GCs
uint64_t copied_bytes;
// Sum of copied_bytes across all parallel GCs
uint64_t par_copied_bytes;
// Sum of par_max_copied_bytes across all parallel GCs
uint64_t cumulative_par_max_copied_bytes;
// -----------------------------------
// 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
Time mutator_cpu_ns;
// Total elapsed time used by the mutator
Time mutator_elapsed_ns;
// Total CPU time used by the GC
Time gc_cpu_ns;
// Total elapsed time used by the GC
Time gc_elapsed_ns;
// Total CPU time (at the previous GC)
Time cpu_ns;
// Total elapsed time (at the previous GC)
Time elapsed_ns;
// -----------------------------------
// Stats about the most recent GC
GCDetails gc;
} RTSStats;
void getRTSStats (RTSStats *s);
int getRTSStatsEnabled (void);
// Returns the total number of bytes allocated since the start of the program.
// TODO: can we remove this?
uint64_t getAllocations (void);
/* ----------------------------------------------------------------------------
Starting up and shutting down the Haskell RTS.
------------------------------------------------------------------------- */
......
/* ----------------------------------------------------------------------------
*
* (c) The GHC Team, 1998-2004
*
* Time values in the RTS
*
* To understand the structure of the RTS headers, see the wiki:
* http://ghc.haskell.org/trac/ghc/wiki/Commentary/SourceTree/Includes
*
* --------------------------------------------------------------------------*/
#ifndef RTSTIME_H
#define RTSTIME_H
// For most time values in the RTS we use a fixed resolution of nanoseconds,
// normalising the time we get from platform-dependent APIs to this
// resolution.
#define TIME_RESOLUTION 1000000000
typedef int64_t Time;
#define TIME_MAX HS_INT64_MAX
#if TIME_RESOLUTION == 1000000000
// I'm being lazy, but it's awkward to define fully general versions of these
#define TimeToUS(t) ((t) / 1000)
#define TimeToNS(t) (t)
#define USToTime(t) ((Time)(t) * 1000)
#define NSToTime(t) ((Time)(t))
#else
#error Fix TimeToNS(), TimeToUS() etc.
#endif
#define SecondsToTime(t) ((Time)(t) * TIME_RESOLUTION)
#define TimeToSeconds(t) ((t) / TIME_RESOLUTION)
// Use instead of SecondsToTime() when we have a floating-point
// seconds value, to avoid truncating it.
INLINE_HEADER Time fsecondsToTime (double t)
{
return (Time)(t * TIME_RESOLUTION);
}
#endif // RTSTIME_H
......@@ -222,61 +222,6 @@ void revertCAFs (void);
// (preferably use RtsConfig.keep_cafs instead)
void setKeepCAFs (void);
/* -----------------------------------------------------------------------------
Stats
-------------------------------------------------------------------------- */
typedef struct _GCStats {
StgWord64 bytes_allocated;
StgWord64 num_gcs;
StgWord64 num_byte_usage_samples;
StgWord64 max_bytes_used;
StgWord64 cumulative_bytes_used;
StgWord64 bytes_copied;
StgWord64 current_bytes_used;
StgWord64 current_bytes_slop;
StgWord64 max_bytes_slop;
StgWord64 peak_megabytes_allocated;
StgWord64 mblocks_allocated;
StgWord64 par_tot_bytes_copied;
StgWord64 par_max_bytes_copied;
StgDouble mutator_cpu_seconds;
StgDouble mutator_wall_seconds;
StgDouble gc_cpu_seconds;
StgDouble gc_wall_seconds;
StgDouble cpu_seconds;
StgDouble wall_seconds;
} GCStats;
void getGCStats (GCStats *s);
bool getGCStatsEnabled (void);
// These don't change over execution, so do them elsewhere
// StgDouble init_cpu_seconds;
// StgDouble init_wall_seconds;
typedef struct _ParGCStats {
StgWord64 tot_copied;
StgWord64 max_copied;
} ParGCStats;
void getParGCStats (ParGCStats *s);
/*
typedef struct _TaskStats {
StgWord64 mut_time;
StgWord64 mut_etime;
StgWord64 gc_time;
StgWord64 gc_etime;
} TaskStats;
// would need to allocate arbitrarily large amount of memory
// because it's a linked list of results
void getTaskStats (TaskStats **s);
// Need to stuff SparkCounters in a public header file...
void getSparkStats (SparkCounters *s);
*/
// Returns the total number of bytes allocated since the start of the program.
HsInt64 getAllocations (void);
/* -----------------------------------------------------------------------------
This is the write barrier for MUT_VARs, a.k.a. IORefs. A
MUT_VAR_CLEAN object is not on the mutable list; a MUT_VAR_DIRTY
......
......@@ -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
......@@ -567,8 +567,8 @@
SymI_HasProto(getOrSetSystemTimerThreadEventManagerStore) \
SymI_HasProto(getOrSetSystemTimerThreadIOManagerThreadStore) \
SymI_HasProto(getOrSetLibHSghcFastStringTable) \
SymI_HasProto(getGCStats) \
SymI_HasProto(getGCStatsEnabled) \
SymI_HasProto(getRTSStats) \
SymI_HasProto(getRTSStatsEnabled) \
SymI_HasProto(genericRaise) \
SymI_HasProto(getProgArgv) \
SymI_HasProto(getFullProgArgv) \
......
This diff is collapsed.
......@@ -31,7 +31,7 @@ void stat_startGCSync(struct gc_thread_ *_gct);
void stat_startGC(Capability *cap, struct gc_thread_ *_gct);
void stat_endGC (Capability *cap, struct gc_thread_ *_gct, W_ live,
W_ copied, W_ slop, uint32_t gen, uint32_t n_gc_threads,
W_ par_max_copied, W_ par_tot_copied);
W_ par_max_copied);
#ifdef PROFILING
void stat_startRP(void);
......
......@@ -187,7 +187,7 @@ GarbageCollect (uint32_t collect_gen,
{
bdescr *bd;
generation *gen;
StgWord live_blocks, live_words, par_max_copied, par_tot_copied;
StgWord live_blocks, live_words, par_max_copied;
#if defined(THREADED_RTS)
gc_thread *saved_gct;
#endif
......@@ -459,7 +459,6 @@ GarbageCollect (uint32_t collect_gen,
copied = 0;
par_max_copied = 0;
par_tot_copied = 0;
{
uint32_t i;
for (i=0; i < n_gc_threads; i++) {
......@@ -474,10 +473,8 @@ GarbageCollect (uint32_t collect_gen,
copied += gc_threads[i]->copied;
par_max_copied = stg_max(gc_threads[i]->copied, par_max_copied);
}
par_tot_copied = copied;
if (n_gc_threads == 1) {
par_max_copied = 0;
par_tot_copied = 0;
}
}
......@@ -773,7 +770,7 @@ GarbageCollect (uint32_t collect_gen,
// ok, GC over: tell the stats department what happened.
stat_endGC(cap, gct, live_words, copied,
live_blocks * BLOCK_SIZE_W - live_words /* slop */,
N, n_gc_threads, par_max_copied, par_tot_copied);
N, n_gc_threads, par_max_copied);
#if defined(RTS_USER_SIGNALS)
if (RtsFlags.MiscFlags.install_signal_handlers) {
......
......@@ -1293,6 +1293,28 @@ calcNeeded (bool force_major, memcount *blocks_needed)
return N;
}
StgWord calcTotalLargeObjectsW (void)
{