Commit ef8a5a48 authored by Ben Gamari's avatar Ben Gamari 🐢

XXX: Mark tracing

parent 81a2fb2c
...@@ -257,6 +257,96 @@ static uint32_t markQueueLength(MarkQueue *q); ...@@ -257,6 +257,96 @@ static uint32_t markQueueLength(MarkQueue *q);
#endif #endif
static void init_mark_queue_(MarkQueue *queue); static void init_mark_queue_(MarkQueue *queue);
#if defined(MARK_DUMP)
static StgClosure *current_src = NULL;
static enum MarkQueueEntSource mark_queue_ent_source;
static enum MarkQueueEntSource popped_source = MARK_QUEUE_OTHER;
static int mark_n = 0;
static FILE *mark_dump = NULL;
static void
set_mark_queue_ent_source(enum MarkQueueEntSource source)
{
mark_queue_ent_source = source;
}
static void
mark_dump_start(void)
{
if (mark_dump) {
fprintf(mark_dump, "}\n");
fclose(mark_dump);
}
char fname[255];
snprintf(fname, 255, "dumps/%05d.dot", mark_n);
mark_dump = fopen(fname, "w");
if (mark_dump == NULL) abort();
fprintf(mark_dump, "digraph {\n");
debugBelch("mark dump: Starting mark %d\n", mark_n);
trace(DEBUG_nonmoving_gc, "mark dump: Starting mark %d\n", mark_n);
mark_n++;
}
static void
mark_dump_node(StgClosure *c)
{
current_src = c;
if (!mark_dump)
return;
const StgInfoTable *info = get_itbl(c);
const char *type;
switch ( info->type ) {
case CONSTR:
case CONSTR_1_0: case CONSTR_0_1:
case CONSTR_1_1: case CONSTR_0_2: case CONSTR_2_0:
case CONSTR_NOCAF:
{
const StgConInfoTable *con_info = get_con_itbl (c);
type = GET_CON_DESC(con_info);
break;
}
default:
type = closure_type_names[info->type];
}
char *source;
switch (popped_source) {
case MARK_QUEUE_ROOT:
source = "root";
break;
case MARK_QUEUE_EVACD:
source = "evacd";
break;
case MARK_QUEUE_UPD_REM_SET:
source = "upd_rem_set";
break;
case MARK_QUEUE_OTHER:
source = "other";
break;
default:
abort();
}
fprintf(mark_dump, " \"%p\" [label=\"%p\\n%s\" source=\"%s\" info=\"%p\" type=\"%s\"];\n",
UNTAG_CLOSURE(c), UNTAG_CLOSURE(c), type, source, info, type);
}
static void
mark_dump_edge(StgClosure *tgt)
{
if (!mark_dump)
return;
fprintf(mark_dump, " \"%p\" -> \"%p\";\n", UNTAG_CLOSURE(current_src), UNTAG_CLOSURE(tgt));
}
#else
static void set_mark_queue_ent_source(enum MarkQueueEntSource source STG_UNUSED) {}
static void mark_dump_start(void) {}
static void mark_dump_node(StgClosure *c STG_UNUSED) {}
static void mark_dump_edge(StgClosure *tgt STG_UNUSED) {}
#endif
/* Transfers the given capability's update-remembered set to the global /* Transfers the given capability's update-remembered set to the global
* remembered set. * remembered set.
* *
...@@ -464,6 +554,9 @@ markQueuePushClosureGC (MarkQueue *q, StgClosure *p) ...@@ -464,6 +554,9 @@ markQueuePushClosureGC (MarkQueue *q, StgClosure *p)
} }
MarkQueueEnt ent = { MarkQueueEnt ent = {
#if defined(MARK_DUMP)
.source = MARK_QUEUE_EVACD,
#endif
.mark_closure = { .mark_closure = {
.p = UNTAG_CLOSURE(p), .p = UNTAG_CLOSURE(p),
.origin = NULL, .origin = NULL,
...@@ -494,7 +587,11 @@ void push_closure (MarkQueue *q, ...@@ -494,7 +587,11 @@ void push_closure (MarkQueue *q,
// with a mark_array entry // with a mark_array entry
ASSERT(((uintptr_t) origin & 0x3) == 0); ASSERT(((uintptr_t) origin & 0x3) == 0);
mark_dump_edge(p);
MarkQueueEnt ent = { MarkQueueEnt ent = {
#if defined(MARK_DUMP)
.source = mark_queue_ent_source,
#endif
.mark_closure = { .mark_closure = {
.p = p, .p = p,
.origin = origin, .origin = origin,
...@@ -512,7 +609,11 @@ void push_array (MarkQueue *q, ...@@ -512,7 +609,11 @@ void push_array (MarkQueue *q,
if (HEAP_ALLOCED_GC(array) && (Bdescr((StgPtr) array)->gen != oldest_gen)) if (HEAP_ALLOCED_GC(array) && (Bdescr((StgPtr) array)->gen != oldest_gen))
return; return;
mark_dump_edge((StgClosure *) array);
MarkQueueEnt ent = { MarkQueueEnt ent = {
#if defined(MARK_DUMP)
.source = mark_queue_ent_source,
#endif
.mark_array = { .mark_array = {
.array = array, .array = array,
.start_index = (start_index << 16) | 0x3, .start_index = (start_index << 16) | 0x3,
...@@ -573,6 +674,7 @@ inline void updateRemembSetPushThunk(Capability *cap, StgThunk *thunk) ...@@ -573,6 +674,7 @@ inline void updateRemembSetPushThunk(Capability *cap, StgThunk *thunk)
do { do {
info = get_volatile_itbl((StgClosure *) thunk); info = get_volatile_itbl((StgClosure *) thunk);
} while (info->type == WHITEHOLE); } while (info->type == WHITEHOLE);
set_mark_queue_ent_source(MARK_QUEUE_UPD_REM_SET);
updateRemembSetPushThunkEager(cap, (StgThunkInfoTable *) info, thunk); updateRemembSetPushThunkEager(cap, (StgThunkInfoTable *) info, thunk);
} }
...@@ -588,6 +690,7 @@ void updateRemembSetPushThunkEager(Capability *cap, ...@@ -588,6 +690,7 @@ void updateRemembSetPushThunkEager(Capability *cap,
StgThunk *thunk) StgThunk *thunk)
{ {
/* N.B. info->i.type mustn't be WHITEHOLE */ /* N.B. info->i.type mustn't be WHITEHOLE */
set_mark_queue_ent_source(MARK_QUEUE_UPD_REM_SET);
MarkQueue *queue = &cap->upd_rem_set.queue; MarkQueue *queue = &cap->upd_rem_set.queue;
switch (info->i.type) { switch (info->i.type) {
case THUNK: case THUNK:
...@@ -639,6 +742,7 @@ void updateRemembSetPushThunkEager(Capability *cap, ...@@ -639,6 +742,7 @@ void updateRemembSetPushThunkEager(Capability *cap,
void updateRemembSetPushThunk_(StgRegTable *reg, StgThunk *p) void updateRemembSetPushThunk_(StgRegTable *reg, StgThunk *p)
{ {
set_mark_queue_ent_source(MARK_QUEUE_UPD_REM_SET);
updateRemembSetPushThunk(regTableToCapability(reg), p); updateRemembSetPushThunk(regTableToCapability(reg), p);
} }
...@@ -646,6 +750,7 @@ inline void updateRemembSetPushClosure(Capability *cap, StgClosure *p) ...@@ -646,6 +750,7 @@ inline void updateRemembSetPushClosure(Capability *cap, StgClosure *p)
{ {
if (check_in_nonmoving_heap(p)) { if (check_in_nonmoving_heap(p)) {
MarkQueue *queue = &cap->upd_rem_set.queue; MarkQueue *queue = &cap->upd_rem_set.queue;
set_mark_queue_ent_source(MARK_QUEUE_UPD_REM_SET);
push_closure(queue, p, NULL); push_closure(queue, p, NULL);
} }
} }
...@@ -700,6 +805,7 @@ void updateRemembSetPushTSO(Capability *cap, StgTSO *tso) ...@@ -700,6 +805,7 @@ void updateRemembSetPushTSO(Capability *cap, StgTSO *tso)
{ {
if (needs_upd_rem_set_mark((StgClosure *) tso)) { if (needs_upd_rem_set_mark((StgClosure *) tso)) {
debugTrace(DEBUG_nonmoving_gc, "upd_rem_set: TSO %p", tso); debugTrace(DEBUG_nonmoving_gc, "upd_rem_set: TSO %p", tso);
set_mark_queue_ent_source(MARK_QUEUE_UPD_REM_SET);
mark_tso(&cap->upd_rem_set.queue, tso); mark_tso(&cap->upd_rem_set.queue, tso);
finish_upd_rem_set_mark((StgClosure *) tso); finish_upd_rem_set_mark((StgClosure *) tso);
} }
...@@ -710,6 +816,7 @@ void updateRemembSetPushStack(Capability *cap, StgStack *stack) ...@@ -710,6 +816,7 @@ void updateRemembSetPushStack(Capability *cap, StgStack *stack)
// N.B. caller responsible for checking nonmoving_write_barrier_enabled // N.B. caller responsible for checking nonmoving_write_barrier_enabled
if (needs_upd_rem_set_mark((StgClosure *) stack)) { if (needs_upd_rem_set_mark((StgClosure *) stack)) {
StgWord8 marking = stack->marking; StgWord8 marking = stack->marking;
set_mark_queue_ent_source(MARK_QUEUE_UPD_REM_SET);
// See Note [StgStack dirtiness flags and concurrent marking] // See Note [StgStack dirtiness flags and concurrent marking]
if (cas_word8(&stack->marking, marking, nonmovingMarkEpoch) if (cas_word8(&stack->marking, marking, nonmovingMarkEpoch)
!= nonmovingMarkEpoch) { != nonmovingMarkEpoch) {
...@@ -753,22 +860,26 @@ void markQueuePushClosure (MarkQueue *q, ...@@ -753,22 +860,26 @@ void markQueuePushClosure (MarkQueue *q,
/* TODO: Do we really never want to specify the origin here? */ /* TODO: Do we really never want to specify the origin here? */
void markQueueAddRoot (MarkQueue* q, StgClosure** root) void markQueueAddRoot (MarkQueue* q, StgClosure** root)
{ {
set_mark_queue_ent_source(MARK_QUEUE_ROOT);
markQueuePushClosure(q, *root, NULL); markQueuePushClosure(q, *root, NULL);
} }
/* Push a closure to the mark queue without origin information */ /* Push a closure to the mark queue without origin information */
void markQueuePushClosure_ (MarkQueue *q, StgClosure *p) void markQueuePushClosure_ (MarkQueue *q, StgClosure *p)
{ {
set_mark_queue_ent_source(MARK_QUEUE_OTHER);
markQueuePushClosure(q, p, NULL); markQueuePushClosure(q, p, NULL);
} }
void markQueuePushFunSrt (MarkQueue *q, const StgInfoTable *info) void markQueuePushFunSrt (MarkQueue *q, const StgInfoTable *info)
{ {
set_mark_queue_ent_source(MARK_QUEUE_OTHER);
push_fun_srt(q, info); push_fun_srt(q, info);
} }
void markQueuePushThunkSrt (MarkQueue *q, const StgInfoTable *info) void markQueuePushThunkSrt (MarkQueue *q, const StgInfoTable *info)
{ {
set_mark_queue_ent_source(MARK_QUEUE_OTHER);
push_thunk_srt(q, info); push_thunk_srt(q, info);
} }
...@@ -776,6 +887,7 @@ void markQueuePushArray (MarkQueue *q, ...@@ -776,6 +887,7 @@ void markQueuePushArray (MarkQueue *q,
const StgMutArrPtrs *array, const StgMutArrPtrs *array,
StgWord start_index) StgWord start_index)
{ {
set_mark_queue_ent_source(MARK_QUEUE_OTHER);
push_array(q, array, start_index); push_array(q, array, start_index);
} }
...@@ -812,6 +924,9 @@ again: ...@@ -812,6 +924,9 @@ again:
top->head--; top->head--;
MarkQueueEnt ent = top->entries[top->head]; MarkQueueEnt ent = top->entries[top->head];
#if defined(MARK_DUMP)
popped_source = ent.source;
#endif
return ent; return ent;
} }
...@@ -1174,6 +1289,8 @@ mark_closure (MarkQueue *queue, const StgClosure *p0, StgClosure **origin) ...@@ -1174,6 +1289,8 @@ mark_closure (MarkQueue *queue, const StgClosure *p0, StgClosure **origin)
StgWord tag = GET_CLOSURE_TAG(p); StgWord tag = GET_CLOSURE_TAG(p);
p = UNTAG_CLOSURE(p); p = UNTAG_CLOSURE(p);
mark_dump_node(p);
# define PUSH_FIELD(obj, field) \ # define PUSH_FIELD(obj, field) \
markQueuePushClosure(queue, \ markQueuePushClosure(queue, \
(StgClosure *) (obj)->field, \ (StgClosure *) (obj)->field, \
...@@ -1669,6 +1786,7 @@ done: ...@@ -1669,6 +1786,7 @@ done:
GNUC_ATTR_HOT void GNUC_ATTR_HOT void
nonmovingMark (MarkQueue *queue) nonmovingMark (MarkQueue *queue)
{ {
mark_dump_start();
traceConcMarkBegin(); traceConcMarkBegin();
debugTrace(DEBUG_nonmoving_gc, "Starting mark pass"); debugTrace(DEBUG_nonmoving_gc, "Starting mark pass");
unsigned int count = 0; unsigned int count = 0;
......
...@@ -16,6 +16,9 @@ ...@@ -16,6 +16,9 @@
#include "Hash.h" #include "Hash.h"
// Enable mark tracing
//#define MARK_DUMP
enum EntryType { enum EntryType {
NULL_ENTRY = 0, NULL_ENTRY = 0,
MARK_CLOSURE, MARK_CLOSURE,
...@@ -42,6 +45,13 @@ enum EntryType { ...@@ -42,6 +45,13 @@ enum EntryType {
* *
*/ */
enum MarkQueueEntSource {
MARK_QUEUE_ROOT,
MARK_QUEUE_EVACD,
MARK_QUEUE_UPD_REM_SET,
MARK_QUEUE_OTHER
};
typedef struct { typedef struct {
// Which kind of mark queue entry we have is determined by the low bits of // Which kind of mark queue entry we have is determined by the low bits of
// the second word: they must be zero in the case of a mark_closure entry // the second word: they must be zero in the case of a mark_closure entry
...@@ -63,6 +73,9 @@ typedef struct { ...@@ -63,6 +73,9 @@ typedef struct {
StgWord start_index; // start index is shifted to the left by 16 bits StgWord start_index; // start index is shifted to the left by 16 bits
} mark_array; } mark_array;
}; };
#if defined(MARK_DUMP)
enum MarkQueueEntSource source;
#endif
} MarkQueueEnt; } MarkQueueEnt;
INLINE_HEADER enum EntryType nonmovingMarkQueueEntryType(MarkQueueEnt *ent) INLINE_HEADER enum EntryType nonmovingMarkQueueEntryType(MarkQueueEnt *ent)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment