summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--includes/rts/EventLogFormat.h11
-rw-r--r--includes/rts/Flags.h1
-rw-r--r--libraries/base/GHC/RTS/Flags.hsc4
-rw-r--r--libraries/base/tests/all.T2
-rw-r--r--libraries/ghc-heap/tests/all.T6
-rw-r--r--rts/RtsFlags.c5
-rw-r--r--rts/Trace.c53
-rw-r--r--rts/Trace.h21
-rw-r--r--rts/eventlog/EventLog.c75
-rw-r--r--rts/eventlog/EventLog.h10
-rw-r--r--rts/rts.cabal.in1
-rw-r--r--rts/sm/NonMoving.c8
-rw-r--r--rts/sm/NonMovingCensus.c129
-rw-r--r--rts/sm/NonMovingCensus.h28
-rw-r--r--rts/sm/NonMovingMark.c5
-rw-r--r--testsuite/config/ghc12
-rw-r--r--testsuite/tests/codeGen/should_run/all.T11
-rw-r--r--testsuite/tests/concurrent/should_run/all.T14
-rw-r--r--testsuite/tests/perf/compiler/all.T4
-rw-r--r--testsuite/tests/rts/all.T15
20 files changed, 390 insertions, 25 deletions
diff --git a/includes/rts/EventLogFormat.h b/includes/rts/EventLogFormat.h
index ad983e70b3..0ffa77a2df 100644
--- a/includes/rts/EventLogFormat.h
+++ b/includes/rts/EventLogFormat.h
@@ -183,12 +183,21 @@
#define EVENT_USER_BINARY_MSG 181
+#define EVENT_CONC_MARK_BEGIN 200
+#define EVENT_CONC_MARK_END 201
+#define EVENT_CONC_SYNC_BEGIN 202
+#define EVENT_CONC_SYNC_END 203
+#define EVENT_CONC_SWEEP_BEGIN 204
+#define EVENT_CONC_SWEEP_END 205
+#define EVENT_CONC_UPD_REM_SET_FLUSH 206
+#define EVENT_NONMOVING_HEAP_CENSUS 207
+
/*
* The highest event code +1 that ghc itself emits. Note that some event
* ranges higher than this are reserved but not currently emitted by ghc.
* This must match the size of the EventDesc[] array in EventLog.c
*/
-#define NUM_GHC_EVENT_TAGS 182
+#define NUM_GHC_EVENT_TAGS 208
#if 0 /* DEPRECATED EVENTS: */
/* we don't actually need to record the thread, it's implicit */
diff --git a/includes/rts/Flags.h b/includes/rts/Flags.h
index 4499af9da6..9a039fd95c 100644
--- a/includes/rts/Flags.h
+++ b/includes/rts/Flags.h
@@ -170,6 +170,7 @@ typedef struct _TRACE_FLAGS {
bool timestamp; /* show timestamp in stderr output */
bool scheduler; /* trace scheduler events */
bool gc; /* trace GC events */
+ bool nonmoving_gc; /* trace nonmoving GC events */
bool sparks_sampled; /* trace spark events by a sampled method */
bool sparks_full; /* trace spark events 100% accurately */
bool user; /* trace user events (emitted from Haskell code) */
diff --git a/libraries/base/GHC/RTS/Flags.hsc b/libraries/base/GHC/RTS/Flags.hsc
index 4778eac397..913344c166 100644
--- a/libraries/base/GHC/RTS/Flags.hsc
+++ b/libraries/base/GHC/RTS/Flags.hsc
@@ -292,6 +292,8 @@ data TraceFlags = TraceFlags
, timestamp :: Bool -- ^ show timestamp in stderr output
, traceScheduler :: Bool -- ^ trace scheduler events
, traceGc :: Bool -- ^ trace GC events
+ , traceNonmovingGc
+ :: Bool -- ^ trace nonmoving GC heap census samples
, sparksSampled :: Bool -- ^ trace spark events by a sampled method
, sparksFull :: Bool -- ^ trace spark events 100% accurately
, user :: Bool -- ^ trace user events (emitted from Haskell code)
@@ -526,6 +528,8 @@ getTraceFlags = do
<*> (toBool <$>
(#{peek TRACE_FLAGS, gc} ptr :: IO CBool))
<*> (toBool <$>
+ (#{peek TRACE_FLAGS, nonmoving_gc} ptr :: IO CBool))
+ <*> (toBool <$>
(#{peek TRACE_FLAGS, sparks_sampled} ptr :: IO CBool))
<*> (toBool <$>
(#{peek TRACE_FLAGS, sparks_full} ptr :: IO CBool))
diff --git a/libraries/base/tests/all.T b/libraries/base/tests/all.T
index 0b45c9aff2..0242ece32e 100644
--- a/libraries/base/tests/all.T
+++ b/libraries/base/tests/all.T
@@ -74,7 +74,7 @@ test('length001',
# excessive amounts of stack space. So we specifically set a low
# stack limit and mark it as failing under a few conditions.
[extra_run_opts('+RTS -K8m -RTS'),
- expect_fail_for(['normal', 'threaded1', 'llvm'])],
+ expect_fail_for(['normal', 'threaded1', 'llvm', 'nonmoving', 'nonmoving_thr', 'nonmoving_thr_ghc'])],
compile_and_run, [''])
test('ratio001', normal, compile_and_run, [''])
diff --git a/libraries/ghc-heap/tests/all.T b/libraries/ghc-heap/tests/all.T
index afa224fde7..89e6f47ecb 100644
--- a/libraries/ghc-heap/tests/all.T
+++ b/libraries/ghc-heap/tests/all.T
@@ -2,7 +2,11 @@ test('heap_all',
[when(have_profiling(), extra_ways(['prof'])),
# These ways produce slightly different heap representations.
# Currently we don't test them.
- omit_ways(['ghci', 'hpc'])
+ omit_ways(['ghci', 'hpc',
+ 'nonmoving', 'nonmoving_thr', 'nonmoving_thr_ghc']),
+ # The debug RTS initializes some fields with 0xaa and so
+ # this test spuriously fails.
+ when(compiler_debugged(), skip)
],
compile_and_run, [''])
diff --git a/rts/RtsFlags.c b/rts/RtsFlags.c
index 7d486824ab..c606d86418 100644
--- a/rts/RtsFlags.c
+++ b/rts/RtsFlags.c
@@ -222,6 +222,7 @@ void initRtsFlagsDefaults(void)
RtsFlags.TraceFlags.timestamp = false;
RtsFlags.TraceFlags.scheduler = false;
RtsFlags.TraceFlags.gc = false;
+ RtsFlags.TraceFlags.nonmoving_gc = false;
RtsFlags.TraceFlags.sparks_sampled= false;
RtsFlags.TraceFlags.sparks_full = false;
RtsFlags.TraceFlags.user = false;
@@ -2131,6 +2132,10 @@ static void read_trace_flags(const char *arg)
RtsFlags.TraceFlags.gc = enabled;
enabled = true;
break;
+ case 'n':
+ RtsFlags.TraceFlags.nonmoving_gc = enabled;
+ enabled = true;
+ break;
case 'u':
RtsFlags.TraceFlags.user = enabled;
enabled = true;
diff --git a/rts/Trace.c b/rts/Trace.c
index de647f762b..ecc28d8fec 100644
--- a/rts/Trace.c
+++ b/rts/Trace.c
@@ -30,6 +30,7 @@
// events
int TRACE_sched;
int TRACE_gc;
+int TRACE_nonmoving_gc;
int TRACE_spark_sampled;
int TRACE_spark_full;
int TRACE_user;
@@ -72,6 +73,9 @@ void initTracing (void)
RtsFlags.GcFlags.giveStats = COLLECT_GC_STATS;
}
+ TRACE_nonmoving_gc =
+ RtsFlags.TraceFlags.nonmoving_gc;
+
TRACE_spark_sampled =
RtsFlags.TraceFlags.sparks_sampled;
@@ -802,6 +806,55 @@ void traceThreadLabel_(Capability *cap,
}
}
+void traceConcMarkBegin()
+{
+ if (eventlog_enabled)
+ postEventNoCap(EVENT_CONC_MARK_BEGIN);
+}
+
+void traceConcMarkEnd(StgWord32 marked_obj_count)
+{
+ if (eventlog_enabled)
+ postConcMarkEnd(marked_obj_count);
+}
+
+void traceConcSyncBegin()
+{
+ if (eventlog_enabled)
+ postEventNoCap(EVENT_CONC_SYNC_BEGIN);
+}
+
+void traceConcSyncEnd()
+{
+ if (eventlog_enabled)
+ postEventNoCap(EVENT_CONC_SYNC_END);
+}
+
+void traceConcSweepBegin()
+{
+ if (eventlog_enabled)
+ postEventNoCap(EVENT_CONC_SWEEP_BEGIN);
+}
+
+void traceConcSweepEnd()
+{
+ if (eventlog_enabled)
+ postEventNoCap(EVENT_CONC_SWEEP_END);
+}
+
+void traceConcUpdRemSetFlush(Capability *cap)
+{
+ if (eventlog_enabled)
+ postConcUpdRemSetFlush(cap);
+}
+
+void traceNonmovingHeapCensus(uint32_t log_blk_size,
+ const struct NonmovingAllocCensus *census)
+{
+ if (eventlog_enabled && TRACE_nonmoving_gc)
+ postNonmovingHeapCensus(log_blk_size, census);
+}
+
void traceThreadStatus_ (StgTSO *tso USED_IF_DEBUG)
{
#if defined(DEBUG)
diff --git a/rts/Trace.h b/rts/Trace.h
index be4d844a6b..7f72fd8093 100644
--- a/rts/Trace.h
+++ b/rts/Trace.h
@@ -9,6 +9,7 @@
#pragma once
#include "rts/EventLogFormat.h"
+#include "sm/NonMovingCensus.h"
#include "Capability.h"
#if defined(DTRACE)
@@ -72,6 +73,7 @@ extern int TRACE_spark_sampled;
extern int TRACE_spark_full;
/* extern int TRACE_user; */ // only used in Trace.c
extern int TRACE_cap;
+extern int TRACE_nonmoving_gc;
// -----------------------------------------------------------------------------
// Posting events
@@ -304,6 +306,16 @@ void traceHeapProfSampleCostCentre(StgWord8 profile_id,
CostCentreStack *stack, StgWord residency);
#endif /* PROFILING */
+void traceConcMarkBegin(void);
+void traceConcMarkEnd(StgWord32 marked_obj_count);
+void traceConcSyncBegin(void);
+void traceConcSyncEnd(void);
+void traceConcSweepBegin(void);
+void traceConcSweepEnd(void);
+void traceConcUpdRemSetFlush(Capability *cap);
+void traceNonmovingHeapCensus(uint32_t log_blk_size,
+ const struct NonmovingAllocCensus *census);
+
void flushTrace(void);
#else /* !TRACING */
@@ -344,6 +356,15 @@ void flushTrace(void);
#define traceHeapProfSampleCostCentre(profile_id, stack, residency) /* nothing */
#define traceHeapProfSampleString(profile_id, label, residency) /* nothing */
+#define traceConcMarkBegin() /* nothing */
+#define traceConcMarkEnd(marked_obj_count) /* nothing */
+#define traceConcSyncBegin() /* nothing */
+#define traceConcSyncEnd() /* nothing */
+#define traceConcSweepBegin() /* nothing */
+#define traceConcSweepEnd() /* nothing */
+#define traceConcUpdRemSetFlush(cap) /* nothing */
+#define traceNonmovingHeapCensus(blk_size, census) /* nothing */
+
#define flushTrace() /* nothing */
#endif /* TRACING */
diff --git a/rts/eventlog/EventLog.c b/rts/eventlog/EventLog.c
index 5c6a1ca48a..8683ad9972 100644
--- a/rts/eventlog/EventLog.c
+++ b/rts/eventlog/EventLog.c
@@ -107,7 +107,15 @@ char *EventDesc[] = {
[EVENT_HEAP_PROF_SAMPLE_END] = "End of heap profile sample",
[EVENT_HEAP_PROF_SAMPLE_STRING] = "Heap profile string sample",
[EVENT_HEAP_PROF_SAMPLE_COST_CENTRE] = "Heap profile cost-centre sample",
- [EVENT_USER_BINARY_MSG] = "User binary message"
+ [EVENT_USER_BINARY_MSG] = "User binary message",
+ [EVENT_CONC_MARK_BEGIN] = "Begin concurrent mark phase",
+ [EVENT_CONC_MARK_END] = "End concurrent mark phase",
+ [EVENT_CONC_SYNC_BEGIN] = "Begin concurrent GC synchronisation",
+ [EVENT_CONC_SYNC_END] = "End concurrent GC synchronisation",
+ [EVENT_CONC_SWEEP_BEGIN] = "Begin concurrent sweep",
+ [EVENT_CONC_SWEEP_END] = "End concurrent sweep",
+ [EVENT_CONC_UPD_REM_SET_FLUSH] = "Update remembered set flushed",
+ [EVENT_NONMOVING_HEAP_CENSUS] = "Nonmoving heap census"
};
// Event type.
@@ -446,6 +454,27 @@ init_event_types(void)
eventTypes[t].size = EVENT_SIZE_DYNAMIC;
break;
+ case EVENT_CONC_MARK_BEGIN:
+ case EVENT_CONC_SYNC_BEGIN:
+ case EVENT_CONC_SYNC_END:
+ case EVENT_CONC_SWEEP_BEGIN:
+ case EVENT_CONC_SWEEP_END:
+ eventTypes[t].size = 0;
+ break;
+
+ case EVENT_CONC_MARK_END:
+ eventTypes[t].size = 4;
+ break;
+
+ case EVENT_CONC_UPD_REM_SET_FLUSH: // (cap)
+ eventTypes[t].size =
+ sizeof(EventCapNo);
+ break;
+
+ case EVENT_NONMOVING_HEAP_CENSUS: // (cap, blk_size, active_segs, filled_segs, live_blks)
+ eventTypes[t].size = 13;
+ break;
+
default:
continue; /* ignore deprecated events */
}
@@ -487,8 +516,10 @@ initEventLogging(const EventLogWriter *ev_writer)
event_log_writer = ev_writer;
initEventLogWriter();
- if (sizeof(EventDesc) / sizeof(char*) != NUM_GHC_EVENT_TAGS) {
- barf("EventDesc array has the wrong number of elements");
+ int num_descs = sizeof(EventDesc) / sizeof(char*);
+ if (num_descs != NUM_GHC_EVENT_TAGS) {
+ barf("EventDesc array has the wrong number of elements (%d, NUM_GHC_EVENT_TAGS=%d)",
+ num_descs, NUM_GHC_EVENT_TAGS);
}
/*
@@ -1005,6 +1036,15 @@ void postTaskDeleteEvent (EventTaskId taskId)
}
void
+postEventNoCap (EventTypeNum tag)
+{
+ ACQUIRE_LOCK(&eventBufMutex);
+ ensureRoomForEvent(&eventBuf, tag);
+ postEventHeader(&eventBuf, tag);
+ RELEASE_LOCK(&eventBufMutex);
+}
+
+void
postEvent (Capability *cap, EventTypeNum tag)
{
EventsBuf *eb = &capEventBuf[cap->no];
@@ -1130,6 +1170,35 @@ void postThreadLabel(Capability *cap,
postBuf(eb, (StgWord8*) label, strsize);
}
+void postConcUpdRemSetFlush(Capability *cap)
+{
+ EventsBuf *eb = &capEventBuf[cap->no];
+ ensureRoomForEvent(eb, EVENT_CONC_UPD_REM_SET_FLUSH);
+ postEventHeader(eb, EVENT_CONC_UPD_REM_SET_FLUSH);
+ postCapNo(eb, cap->no);
+}
+
+void postConcMarkEnd(StgWord32 marked_obj_count)
+{
+ ACQUIRE_LOCK(&eventBufMutex);
+ ensureRoomForEvent(&eventBuf, EVENT_CONC_MARK_END);
+ postEventHeader(&eventBuf, EVENT_CONC_MARK_END);
+ postWord32(&eventBuf, marked_obj_count);
+ RELEASE_LOCK(&eventBufMutex);
+}
+
+void postNonmovingHeapCensus(int log_blk_size,
+ const struct NonmovingAllocCensus *census)
+{
+ ACQUIRE_LOCK(&eventBufMutex);
+ postEventHeader(&eventBuf, EVENT_NONMOVING_HEAP_CENSUS);
+ postWord8(&eventBuf, log_blk_size);
+ postWord32(&eventBuf, census->n_active_segs);
+ postWord32(&eventBuf, census->n_filled_segs);
+ postWord32(&eventBuf, census->n_live_blocks);
+ RELEASE_LOCK(&eventBufMutex);
+}
+
void closeBlockMarker (EventsBuf *ebuf)
{
if (ebuf->marker)
diff --git a/rts/eventlog/EventLog.h b/rts/eventlog/EventLog.h
index d8a614b45c..0d439b836a 100644
--- a/rts/eventlog/EventLog.h
+++ b/rts/eventlog/EventLog.h
@@ -11,6 +11,7 @@
#include "rts/EventLogFormat.h"
#include "rts/EventLogWriter.h"
#include "Capability.h"
+#include "sm/NonMovingCensus.h"
#include "BeginPrivate.h"
@@ -39,6 +40,7 @@ void postSchedEvent(Capability *cap, EventTypeNum tag,
* Post a nullary event.
*/
void postEvent(Capability *cap, EventTypeNum tag);
+void postEventNoCap(EventTypeNum tag);
void postEventAtTimestamp (Capability *cap, EventTimestamp ts,
EventTypeNum tag);
@@ -159,6 +161,11 @@ void postHeapProfSampleCostCentre(StgWord8 profile_id,
StgWord64 residency);
#endif /* PROFILING */
+void postConcUpdRemSetFlush(Capability *cap);
+void postConcMarkEnd(StgWord32 marked_obj_count);
+void postNonmovingHeapCensus(int log_blk_size,
+ const struct NonmovingAllocCensus *census);
+
#else /* !TRACING */
INLINE_HEADER void postSchedEvent (Capability *cap STG_UNUSED,
@@ -172,6 +179,9 @@ INLINE_HEADER void postEvent (Capability *cap STG_UNUSED,
EventTypeNum tag STG_UNUSED)
{ /* nothing */ }
+INLINE_HEADER void postEventNoCap (EventTypeNum tag STG_UNUSED)
+{ /* nothing */ }
+
INLINE_HEADER void postMsg (char *msg STG_UNUSED,
va_list ap STG_UNUSED)
{ /* nothing */ }
diff --git a/rts/rts.cabal.in b/rts/rts.cabal.in
index 2c28426d75..a53c166849 100644
--- a/rts/rts.cabal.in
+++ b/rts/rts.cabal.in
@@ -467,6 +467,7 @@ library
sm/MBlock.c
sm/MarkWeak.c
sm/NonMoving.c
+ sm/NonMovingCensus.c
sm/NonMovingMark.c
sm/NonMovingScav.c
sm/NonMovingSweep.c
diff --git a/rts/sm/NonMoving.c b/rts/sm/NonMoving.c
index 9b50c2d7dd..6dc1010d43 100644
--- a/rts/sm/NonMoving.c
+++ b/rts/sm/NonMoving.c
@@ -21,6 +21,7 @@
#include "NonMoving.h"
#include "NonMovingMark.h"
#include "NonMovingSweep.h"
+#include "NonMovingCensus.h"
#include "StablePtr.h" // markStablePtrTable
#include "Schedule.h" // markScheduler
#include "Weak.h" // dead_weak_ptr_list
@@ -872,6 +873,8 @@ static void nonmovingMark_(MarkQueue *mark_queue, StgWeak **dead_weaks, StgTSO *
* Sweep
****************************************************/
+ traceConcSweepBegin();
+
// Because we can't mark large object blocks (no room for mark bit) we
// collect them in a map in mark_queue and we pass it here to sweep large
// objects
@@ -881,6 +884,11 @@ static void nonmovingMark_(MarkQueue *mark_queue, StgWeak **dead_weaks, StgTSO *
nonmovingSweep();
ASSERT(nonmovingHeap.sweep_list == NULL);
debugTrace(DEBUG_nonmoving_gc, "Finished sweeping.");
+ traceConcSweepEnd();
+#if defined(DEBUG)
+ if (RtsFlags.DebugFlags.nonmoving_gc)
+ nonmovingPrintAllocatorCensus();
+#endif
// TODO: Remainder of things done by GarbageCollect (update stats)
diff --git a/rts/sm/NonMovingCensus.c b/rts/sm/NonMovingCensus.c
new file mode 100644
index 0000000000..670d51263c
--- /dev/null
+++ b/rts/sm/NonMovingCensus.c
@@ -0,0 +1,129 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team, 1998-2018
+ *
+ * Non-moving garbage collector and allocator: Accounting census
+ *
+ * This is a simple space accounting census useful for characterising
+ * fragmentation in the nonmoving heap.
+ *
+ * ---------------------------------------------------------------------------*/
+
+#include "Rts.h"
+#include "NonMoving.h"
+#include "Trace.h"
+#include "NonMovingCensus.h"
+
+// N.B. This may miss segments in the event of concurrent mutation (e.g. if a
+// mutator retires its current segment to the filled list).
+//
+// all_stopped is whether we can guarantee that all mutators and minor GCs are
+// stopped. In this case is safe to look at active and current segments so we can
+// also collect statistics on live words.
+static inline struct NonmovingAllocCensus
+nonmovingAllocatorCensus_(struct NonmovingAllocator *alloc, bool collect_live_words)
+{
+ struct NonmovingAllocCensus census = {0, 0, 0, 0};
+
+ for (struct NonmovingSegment *seg = alloc->filled;
+ seg != NULL;
+ seg = seg->link)
+ {
+ unsigned int n = nonmovingSegmentBlockCount(seg);
+ census.n_filled_segs++;
+ census.n_live_blocks += n;
+ if (collect_live_words) {
+ for (unsigned int i=0; i < n; i++) {
+ StgClosure *c = (StgClosure *) nonmovingSegmentGetBlock(seg, i);
+ census.n_live_words += closure_sizeW(c);
+ }
+ }
+ }
+
+ for (struct NonmovingSegment *seg = alloc->active;
+ seg != NULL;
+ seg = seg->link)
+ {
+ census.n_active_segs++;
+ unsigned int n = nonmovingSegmentBlockCount(seg);
+ for (unsigned int i=0; i < n; i++) {
+ if (nonmovingGetMark(seg, i)) {
+ StgClosure *c = (StgClosure *) nonmovingSegmentGetBlock(seg, i);
+ if (collect_live_words)
+ census.n_live_words += closure_sizeW(c);
+ census.n_live_blocks++;
+ }
+ }
+ }
+
+ for (unsigned int cap=0; cap < n_capabilities; cap++)
+ {
+ struct NonmovingSegment *seg = alloc->current[cap];
+ unsigned int n = nonmovingSegmentBlockCount(seg);
+ for (unsigned int i=0; i < n; i++) {
+ if (nonmovingGetMark(seg, i)) {
+ StgClosure *c = (StgClosure *) nonmovingSegmentGetBlock(seg, i);
+ if (collect_live_words)
+ census.n_live_words += closure_sizeW(c);
+ census.n_live_blocks++;
+ }
+ }
+ }
+ return census;
+}
+
+/* This must not be used when mutators are active since it assumes that
+ * all blocks in nonmoving heap are valid closures.
+ */
+struct NonmovingAllocCensus
+nonmovingAllocatorCensusWithWords(struct NonmovingAllocator *alloc)
+{
+ return nonmovingAllocatorCensus_(alloc, true);
+}
+
+struct NonmovingAllocCensus
+nonmovingAllocatorCensus(struct NonmovingAllocator *alloc)
+{
+ return nonmovingAllocatorCensus_(alloc, false);
+}
+
+
+void nonmovingPrintAllocatorCensus()
+{
+ if (!RtsFlags.GcFlags.useNonmoving)
+ return;
+
+ for (int i=0; i < NONMOVING_ALLOCA_CNT; i++) {
+ struct NonmovingAllocCensus census =
+ nonmovingAllocatorCensus(nonmovingHeap.allocators[i]);
+
+ uint32_t blk_size = 1 << (i + NONMOVING_ALLOCA0);
+ // We define occupancy as the fraction of space that is used for useful
+ // data (that is, live and not slop).
+ double occupancy = 100.0 * census.n_live_words * sizeof(W_)
+ / (census.n_live_blocks * blk_size);
+ if (census.n_live_blocks == 0) occupancy = 100;
+ (void) occupancy; // silence warning if !DEBUG
+ debugTrace(DEBUG_nonmoving_gc, "Allocator %d (%d bytes - %d bytes): "
+ "%d active segs, %d filled segs, %d live blocks, %d live words "
+ "(%2.1f%% occupancy)",
+ i, 1 << (i + NONMOVING_ALLOCA0 - 1), 1 << (i + NONMOVING_ALLOCA0),
+ census.n_active_segs, census.n_filled_segs, census.n_live_blocks, census.n_live_words,
+ occupancy);
+ }
+}
+
+void nonmovingTraceAllocatorCensus()
+{
+#if defined(TRACING)
+ if (!RtsFlags.GcFlags.useNonmoving && !TRACE_nonmoving_gc)
+ return;
+
+ for (int i=0; i < NONMOVING_ALLOCA_CNT; i++) {
+ const struct NonmovingAllocCensus census =
+ nonmovingAllocatorCensus(nonmovingHeap.allocators[i]);
+ const uint32_t log_blk_size = i + NONMOVING_ALLOCA0;
+ traceNonmovingHeapCensus(log_blk_size, &census);
+ }
+#endif
+}
diff --git a/rts/sm/NonMovingCensus.h b/rts/sm/NonMovingCensus.h
new file mode 100644
index 0000000000..7a66dc9b69
--- /dev/null
+++ b/rts/sm/NonMovingCensus.h
@@ -0,0 +1,28 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team, 1998-2018
+ *
+ * Non-moving garbage collector and allocator: Accounting census
+ *
+ * ---------------------------------------------------------------------------*/
+
+#pragma once
+
+#include "NonMoving.h"
+
+struct NonmovingAllocCensus {
+ uint32_t n_active_segs;
+ uint32_t n_filled_segs;
+ uint32_t n_live_blocks;
+ uint32_t n_live_words;
+};
+
+
+struct NonmovingAllocCensus
+nonmovingAllocatorCensusWithWords(struct NonmovingAllocator *alloc);
+
+struct NonmovingAllocCensus
+nonmovingAllocatorCensus(struct NonmovingAllocator *alloc);
+
+void nonmovingPrintAllocatorCensus(void);
+void nonmovingTraceAllocatorCensus(void);
diff --git a/rts/sm/NonMovingMark.c b/rts/sm/NonMovingMark.c
index 2ab4572447..bb5d72bbf1 100644
--- a/rts/sm/NonMovingMark.c
+++ b/rts/sm/NonMovingMark.c
@@ -281,6 +281,7 @@ void nonmovingFlushCapUpdRemSetBlocks(Capability *cap)
debugTrace(DEBUG_nonmoving_gc,
"Capability %d flushing update remembered set: %d",
cap->no, markQueueLength(&cap->upd_rem_set.queue));
+ traceConcUpdRemSetFlush(cap);
nonmovingAddUpdRemSetBlocks(&cap->upd_rem_set.queue);
atomic_inc(&upd_rem_set_flush_count, 1);
signalCondition(&upd_rem_set_flushed_cond);
@@ -294,6 +295,7 @@ void nonmovingFlushCapUpdRemSetBlocks(Capability *cap)
void nonmovingBeginFlush(Task *task)
{
debugTrace(DEBUG_nonmoving_gc, "Starting update remembered set flush...");
+ traceConcSyncBegin();
upd_rem_set_flush_count = 0;
stopAllCapabilitiesWith(NULL, task, SYNC_FLUSH_UPD_REM_SET);
@@ -385,6 +387,7 @@ void nonmovingFinishFlush(Task *task)
upd_rem_set_block_list = NULL;
debugTrace(DEBUG_nonmoving_gc, "Finished update remembered set flush...");
+ traceConcSyncEnd();
releaseAllCapabilities(n_capabilities, NULL, task);
}
#endif
@@ -1575,6 +1578,7 @@ mark_closure (MarkQueue *queue, StgClosure *p, StgClosure **origin)
GNUC_ATTR_HOT void
nonmovingMark (MarkQueue *queue)
{
+ traceConcMarkBegin();
debugTrace(DEBUG_nonmoving_gc, "Starting mark pass");
unsigned int count = 0;
while (true) {
@@ -1615,6 +1619,7 @@ nonmovingMark (MarkQueue *queue)
} else {
// Nothing more to do
debugTrace(DEBUG_nonmoving_gc, "Finished mark pass: %d", count);
+ traceConcMarkEnd(count);
return;
}
}
diff --git a/testsuite/config/ghc b/testsuite/config/ghc
index ec35ed0d8c..9a3459ea96 100644
--- a/testsuite/config/ghc
+++ b/testsuite/config/ghc
@@ -27,7 +27,9 @@ config.other_ways = ['prof', 'normal_h',
'debug',
'ghci-ext', 'ghci-ext-prof',
'ext-interp',
- 'nonmoving']
+ 'nonmoving',
+ 'nonmoving_thr',
+ 'nonmoving_thr_ghc']
if ghc_with_native_codegen:
config.compile_ways.append('optasm')
@@ -98,7 +100,9 @@ config.way_flags = {
'ghci-ext' : ['--interactive', '-v0', '-ignore-dot-ghci', '-fno-ghci-history', '-fexternal-interpreter', '+RTS', '-I0.1', '-RTS'],
'ghci-ext-prof' : ['--interactive', '-v0', '-ignore-dot-ghci', '-fno-ghci-history', '-fexternal-interpreter', '-prof', '+RTS', '-I0.1', '-RTS'],
'ext-interp' : ['-fexternal-interpreter'],
- 'nonmoving' : ['-debug'],
+ 'nonmoving' : [],
+ 'nonmoving_thr': ['-threaded'],
+ 'nonmoving_thr_ghc': ['+RTS', '-xn', '-N2', '-RTS', '-threaded'],
}
config.way_rts_flags = {
@@ -137,7 +141,9 @@ config.way_rts_flags = {
'ghci-ext' : [],
'ghci-ext-prof' : [],
'ext-interp' : [],
- 'nonmoving' : ['-DS', '-xn'],
+ 'nonmoving' : ['-xn'],
+ 'nonmoving_thr' : ['-xn', '-N2'],
+ 'nonmoving_thr_ghc': ['-xn', '-N2'],
}
# Useful classes of ways that can be used with only_ways(), omit_ways() and
diff --git a/testsuite/tests/codeGen/should_run/all.T b/testsuite/tests/codeGen/should_run/all.T
index 0882f2b605..f96820de81 100644
--- a/testsuite/tests/codeGen/should_run/all.T
+++ b/testsuite/tests/codeGen/should_run/all.T
@@ -1,5 +1,6 @@
# Test +RTS -G1 here (it isn't tested anywhere else)
-setTestOpts(unless(fast(), extra_ways(['g1'])))
+# N.B. Nonmoving collector doesn't support -G1
+setTestOpts(unless(fast(), [ extra_ways(['g1']), omit_ways(['nonmoving', 'nonmoving_thr', 'nonmoving_thr_ghc'])]))
test('cgrun001', normal, compile_and_run, [''])
test('cgrun002', normal, compile_and_run, [''])
@@ -194,9 +195,11 @@ test('T15696_3', normal, compile_and_run, ['-O'])
test('T15892',
[ ignore_stdout,
- # we want to do lots of major GC to make the bug more likely to
- # happen, so -G1 -A32k:
- extra_run_opts('+RTS -G1 -A32k -RTS') ],
+ # -G1 is unsupported by the nonmoving GC
+ omit_ways(['nonmoving', 'nonmoving_thr', 'nonmoving_thr_ghc']),
+ # we want to do lots of major GC to make the bug more likely to
+ # happen, so -G1 -A32k:
+ extra_run_opts('+RTS -G1 -A32k -RTS') ],
compile_and_run, ['-O'])
test('T16617', normal, compile_and_run, [''])
test('T16449_2', exit_code(0), compile_and_run, [''])
diff --git a/testsuite/tests/concurrent/should_run/all.T b/testsuite/tests/concurrent/should_run/all.T
index 467040223f..9297c5890e 100644
--- a/testsuite/tests/concurrent/should_run/all.T
+++ b/testsuite/tests/concurrent/should_run/all.T
@@ -7,7 +7,7 @@ test('conc027', normal, compile_and_run, [''])
test('conc051', normal, compile_and_run, [''])
if ('threaded1' in config.run_ways):
- only_threaded_ways = only_ways(['ghci','threaded1','threaded2'])
+ only_threaded_ways = only_ways(['ghci','threaded1','threaded2', 'nonmoving_thr'])
else:
only_threaded_ways = skip
@@ -203,8 +203,8 @@ test('foreignInterruptible', [when(fast(), skip),
],
compile_and_run, [''])
-test('conc037', only_ways(['threaded1','threaded2']), compile_and_run, [''])
-test('conc038', only_ways(['threaded1','threaded2']), compile_and_run, [''])
+test('conc037', only_ways(['threaded1', 'threaded2', 'nonmoving_thr']), compile_and_run, [''])
+test('conc038', only_ways(['threaded1', 'threaded2', 'nonmoving_thr']), compile_and_run, [''])
# Omit for GHCi, uses foreign export
# Omit for the threaded ways, because in this case the main thread is allowed to
@@ -224,7 +224,7 @@ test('conc045', normal, compile_and_run, [''])
test('conc058', normal, compile_and_run, [''])
test('conc059',
- [only_ways(['threaded1', 'threaded2']),
+ [only_ways(['threaded1', 'threaded2', 'nonmoving_thr']),
pre_cmd('$MAKE -s --no-print-directory conc059_setup')],
compile_and_run, ['conc059_c.c -no-hs-main'])
@@ -243,7 +243,7 @@ test('conc067', ignore_stdout, compile_and_run, [''])
test('conc068', [ omit_ways(concurrent_ways), exit_code(1) ], compile_and_run, [''])
test('setnumcapabilities001',
- [ only_ways(['threaded1','threaded2']),
+ [ only_ways(['threaded1','threaded2', 'nonmoving_thr']),
extra_run_opts('8 12 2000'),
req_smp ],
compile_and_run, [''])
@@ -254,7 +254,7 @@ test('compareAndSwap', [omit_ways(['ghci','hpc']), reqlib('primitive')], compile
test('hs_try_putmvar001',
[
when(opsys('mingw32'),skip), # uses pthread APIs in the C code
- only_ways(['threaded1','threaded2']),
+ only_ways(['threaded1', 'threaded2', 'nonmoving_thr']),
extra_clean(['hs_try_putmvar001_c.o'])],
compile_and_run,
['hs_try_putmvar001_c.c'])
@@ -272,7 +272,7 @@ test('hs_try_putmvar003',
[
when(opsys('mingw32'),skip), # uses pthread APIs in the C code
pre_cmd('$MAKE -s --no-print-directory hs_try_putmvar003_setup'),
- only_ways(['threaded1','threaded2']),
+ only_ways(['threaded1', 'threaded2', 'nonmoving_thr']),
extra_clean(['hs_try_putmvar003_c.o']),
extra_run_opts('1 16 32 100'),
fragile_for(16361, ['threaded1'])
diff --git a/testsuite/tests/perf/compiler/all.T b/testsuite/tests/perf/compiler/all.T
index cfc860d0b0..72e240a4c5 100644
--- a/testsuite/tests/perf/compiler/all.T
+++ b/testsuite/tests/perf/compiler/all.T
@@ -385,7 +385,9 @@ test ('T9630',
extra_clean(['T9630a.hi', 'T9630a.o']),
# Use `+RTS -G1` for more stable residency measurements. Note [residency].
- extra_hc_opts('+RTS -G1 -RTS')
+ extra_hc_opts('+RTS -G1 -RTS'),
+ # The nonmoving collector does not support -G1
+ omit_ways(['nonmoving', 'nonmoving_thr', 'nonmoving_thr_ghc'])
],
multimod_compile,
['T9630', '-v0 -O'])
diff --git a/testsuite/tests/rts/all.T b/testsuite/tests/rts/all.T
index 9e20ba0b81..36f63c571e 100644
--- a/testsuite/tests/rts/all.T
+++ b/testsuite/tests/rts/all.T
@@ -12,7 +12,10 @@ test('testmblockalloc',
# See bug #101, test requires +RTS -c (or equivalently +RTS -M<something>)
# only GHCi triggers the bug, but we run the test all ways for completeness.
-test('bug1010', normal, compile_and_run, ['+RTS -c -RTS'])
+test('bug1010',
+ # Non-moving GC doesn't support -c
+ omit_ways(['nonmoving', 'nonmoving_thr', 'nonmoving_thr_ghc']),
+ compile_and_run, ['+RTS -c -RTS'])
def normalise_address(str):
return re.sub('Access violation in generated code when reading [0]+',
@@ -67,8 +70,12 @@ test('outofmem', when(opsys('darwin'), skip),
makefile_test, ['outofmem'])
test('outofmem2', normal, makefile_test, ['outofmem2'])
-test('T2047', [ignore_stdout, extra_run_opts('+RTS -c -RTS')],
- compile_and_run, ['-package containers'])
+test('T2047',
+ [ignore_stdout,
+ extra_run_opts('+RTS -c -RTS'),
+ # Non-moving collector doesn't support -c
+ omit_ways(['nonmoving', 'nonmoving_thr', 'nonmoving_thr_ghc'])],
+ compile_and_run, ['-package containers'])
# Blackhole-detection test.
# Skip GHCi due to #2786
@@ -183,7 +190,7 @@ test('T6006', [ omit_ways(prof_ways + ['ghci']),
test('T7037', [], makefile_test, ['T7037'])
test('T7087', exit_code(1), compile_and_run, [''])
-test('T7160', normal, compile_and_run, [''])
+test('T7160', omit_ways(['nonmoving_thr', 'nonmoving_thr_ghc']), compile_and_run, [''])
test('T7040', [omit_ways(['ghci'])], compile_and_run, ['T7040_c.c'])