Commit 44b261bf authored by Rudi Chen's avatar Rudi Chen

Reorganize mark phase and add more timers to GC.

parent 81a272ee
...@@ -32,15 +32,6 @@ ...@@ -32,15 +32,6 @@
#include "valgrind.h" #include "valgrind.h"
#endif #endif
//#undef VERBOSITY
//#define VERBOSITY(x) 2
#ifndef NDEBUG
#define DEBUG 1
#else
#define DEBUG 0
#endif
namespace pyston { namespace pyston {
namespace gc { namespace gc {
...@@ -283,28 +274,41 @@ void GCVisitor::visitPotentialRange(void* const* start, void* const* end) { ...@@ -283,28 +274,41 @@ void GCVisitor::visitPotentialRange(void* const* start, void* const* end) {
static int ncollections = 0; static int ncollections = 0;
void markPhase() { static inline void visitByGCKind(void* p, GCVisitor& visitor) {
#ifndef NVALGRIND assert(((intptr_t)p) % 8 == 0);
// Have valgrind close its eyes while we do the conservative stack and data scanning,
// since we'll be looking at potentially-uninitialized values: GCAllocation* al = GCAllocation::fromUserData(p);
VALGRIND_DISABLE_ERROR_REPORTING;
#endif GCKind kind_id = al->kind_id;
if (kind_id == GCKind::UNTRACKED) {
#if TRACE_GC_MARKING // Nothing to do here.
#if 1 // separate log file per collection } else if (kind_id == GCKind::CONSERVATIVE || kind_id == GCKind::CONSERVATIVE_PYTHON) {
char tracefn_buf[80]; uint32_t bytes = al->kind_data;
snprintf(tracefn_buf, sizeof(tracefn_buf), "gc_trace_%03d.txt", ncollections); visitor.visitPotentialRange((void**)p, (void**)((char*)p + bytes));
trace_fp = fopen(tracefn_buf, "w"); } else if (kind_id == GCKind::PRECISE) {
#else // overwrite previous log file with each collection uint32_t bytes = al->kind_data;
trace_fp = fopen("gc_trace.txt", "w"); visitor.visitRange((void**)p, (void**)((char*)p + bytes));
#endif } else if (kind_id == GCKind::PYTHON) {
#endif Box* b = reinterpret_cast<Box*>(p);
GC_TRACE_LOG("Starting collection %d\n", ncollections); BoxedClass* cls = b->cls;
GC_TRACE_LOG("Looking at roots\n"); if (cls) {
TraceStack stack(roots); // The cls can be NULL since we use 'new' to construct them.
GCVisitor visitor(&stack); // An arbitrary amount of stuff can happen between the 'new' and
// the call to the constructor (ie the args get evaluated), which
// can trigger a collection.
ASSERT(cls->gc_visit, "%s", getTypeName(b));
cls->gc_visit(&visitor, b);
}
} else if (kind_id == GCKind::HIDDEN_CLASS) {
HiddenClass* hcls = reinterpret_cast<HiddenClass*>(p);
hcls->gc_visit(&visitor);
} else {
RELEASE_ASSERT(0, "Unhandled kind: %d", (int)kind_id);
}
}
static void getMarkPhaseRoots(GCVisitor& visitor) {
GC_TRACE_LOG("Looking at the stack\n"); GC_TRACE_LOG("Looking at the stack\n");
threading::visitAllStacks(&visitor); threading::visitAllStacks(&visitor);
...@@ -317,10 +321,16 @@ void markPhase() { ...@@ -317,10 +321,16 @@ void markPhase() {
for (auto& e : potential_root_ranges) { for (auto& e : potential_root_ranges) {
visitor.visitPotentialRange((void* const*)e.first, (void* const*)e.second); visitor.visitPotentialRange((void* const*)e.first, (void* const*)e.second);
} }
}
static void graphTraversalMarking(TraceStack& stack, GCVisitor& visitor) {
static StatCounter sc_us("us_gc_mark_phase_graph_traversal");
static StatCounter sc_marked_objs("gc_marked_object_count");
Timer _t("traversing", /*min_usec=*/10000);
// if (VERBOSITY()) printf("Found %d roots\n", stack.size());
while (void* p = stack.pop()) { while (void* p = stack.pop()) {
assert(((intptr_t)p) % 8 == 0); sc_marked_objs.log();
GCAllocation* al = GCAllocation::fromUserData(p); GCAllocation* al = GCAllocation::fromUserData(p);
#if TRACE_GC_MARKING #if TRACE_GC_MARKING
...@@ -331,50 +341,42 @@ void markPhase() { ...@@ -331,50 +341,42 @@ void markPhase() {
#endif #endif
assert(isMarked(al)); assert(isMarked(al));
visitByGCKind(p, visitor);
// printf("Marking + scanning %p\n", p);
GCKind kind_id = al->kind_id;
if (kind_id == GCKind::UNTRACKED) {
continue;
} else if (kind_id == GCKind::CONSERVATIVE || kind_id == GCKind::CONSERVATIVE_PYTHON) {
uint32_t bytes = al->kind_data;
if (DEBUG >= 2) {
if (global_heap.small_arena.contains(p)) {
SmallArena::Block* b = SmallArena::Block::forPointer(p);
assert(b->size >= bytes + sizeof(GCAllocation));
}
}
visitor.visitPotentialRange((void**)p, (void**)((char*)p + bytes));
} else if (kind_id == GCKind::PRECISE) {
uint32_t bytes = al->kind_data;
if (DEBUG >= 2) {
if (global_heap.small_arena.contains(p)) {
SmallArena::Block* b = SmallArena::Block::forPointer(p);
assert(b->size >= bytes + sizeof(GCAllocation));
}
}
visitor.visitRange((void**)p, (void**)((char*)p + bytes));
} else if (kind_id == GCKind::PYTHON) {
Box* b = reinterpret_cast<Box*>(p);
BoxedClass* cls = b->cls;
if (cls) {
// The cls can be NULL since we use 'new' to construct them.
// An arbitrary amount of stuff can happen between the 'new' and
// the call to the constructor (ie the args get evaluated), which
// can trigger a collection.
ASSERT(cls->gc_visit, "%s", getTypeName(b));
cls->gc_visit(&visitor, b);
}
} else if (kind_id == GCKind::HIDDEN_CLASS) {
HiddenClass* hcls = reinterpret_cast<HiddenClass*>(p);
hcls->gc_visit(&visitor);
} else {
RELEASE_ASSERT(0, "Unhandled kind: %d", (int)kind_id);
}
} }
long us = _t.end();
sc_us.log(us);
}
static void markPhase() {
static StatCounter sc_us("us_gc_mark_phase");
Timer _t("markPhase", /*min_usec=*/10000);
#ifndef NVALGRIND
// Have valgrind close its eyes while we do the conservative stack and data scanning,
// since we'll be looking at potentially-uninitialized values:
VALGRIND_DISABLE_ERROR_REPORTING;
#endif
#if TRACE_GC_MARKING
#if 1 // separate log file per collection
char tracefn_buf[80];
snprintf(tracefn_buf, sizeof(tracefn_buf), "gc_trace_%03d.txt", ncollections);
trace_fp = fopen(tracefn_buf, "w");
#else // overwrite previous log file with each collection
trace_fp = fopen("gc_trace.txt", "w");
#endif
#endif
GC_TRACE_LOG("Starting collection %d\n", ncollections);
GC_TRACE_LOG("Looking at roots\n");
TraceStack stack(roots);
GCVisitor visitor(&stack);
getMarkPhaseRoots(visitor);
graphTraversalMarking(stack, visitor);
#if TRACE_GC_MARKING #if TRACE_GC_MARKING
fclose(trace_fp); fclose(trace_fp);
trace_fp = NULL; trace_fp = NULL;
...@@ -383,12 +385,21 @@ void markPhase() { ...@@ -383,12 +385,21 @@ void markPhase() {
#ifndef NVALGRIND #ifndef NVALGRIND
VALGRIND_ENABLE_ERROR_REPORTING; VALGRIND_ENABLE_ERROR_REPORTING;
#endif #endif
long us = _t.end();
sc_us.log(us);
} }
static void sweepPhase(std::vector<Box*>& weakly_referenced) { static void sweepPhase(std::vector<Box*>& weakly_referenced) {
static StatCounter sc_us("us_gc_sweep_phase");
Timer _t("sweepPhase", /*min_usec=*/10000);
// we need to use the allocator here because these objects are referenced only here, and calling the weakref // we need to use the allocator here because these objects are referenced only here, and calling the weakref
// callbacks could start another gc // callbacks could start another gc
global_heap.freeUnmarked(weakly_referenced); global_heap.freeUnmarked(weakly_referenced);
long us = _t.end();
sc_us.log(us);
} }
static bool gc_enabled = true; static bool gc_enabled = true;
...@@ -415,6 +426,7 @@ void endGCUnexpectedRegion() { ...@@ -415,6 +426,7 @@ void endGCUnexpectedRegion() {
} }
void runCollection() { void runCollection() {
static StatCounter sc_us("us_gc_collections");
static StatCounter sc("gc_collections"); static StatCounter sc("gc_collections");
sc.log(); sc.log();
...@@ -492,7 +504,6 @@ void runCollection() { ...@@ -492,7 +504,6 @@ void runCollection() {
printf("Collection #%d done\n\n", ncollections); printf("Collection #%d done\n\n", ncollections);
long us = _t.end(); long us = _t.end();
static StatCounter sc_us("gc_collections_us");
sc_us.log(us); sc_us.log(us);
// dumpHeapStatistics(); // dumpHeapStatistics();
......
...@@ -596,8 +596,6 @@ public: ...@@ -596,8 +596,6 @@ public:
} }
void dumpHeapStatistics(int level); void dumpHeapStatistics(int level);
friend void markPhase();
}; };
extern Heap global_heap; extern Heap global_heap;
......
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