void ObjectMemory::young_autotune() { if(young_autotune_size) { // We autotune the size if we do multiple young // collections during a mature mark phase. This indicates // that memory pressure is higher and we might want to grow // if we haven't met the young size factor yet. // // If we don't see any young GC's we check if we should shrink it if(young_gc_while_marking_ > 1) { if(young_->bytes_size() < young_max_bytes && young_->bytes_size() < mature_bytes_allocated() / young_autotune_factor) { young_->grow(young_->bytes_size() * 2); } } else if(young_gc_while_marking_ == 0) { if(young_->bytes_size() > mature_bytes_allocated() / young_autotune_factor) { young_->grow(young_->bytes_size() / 2); } } } }
void ObjectMemory::print_mature_stats(STATE, GCData* data) { if(state->shared().config.gc_show) { uint64_t stop = gc_stats.last_full_stop_collection_time.value; uint64_t concur = gc_stats.last_full_concurrent_collection_time.value; size_t before_mature_kb = data->mature_bytes_allocated() / 1024; size_t mature_kb = mature_bytes_allocated() / 1024; size_t before_code_kb = data->code_bytes_allocated() / 1024; size_t code_kb = code_bytes_allocated() / 1024; std::cerr << "[Full GC mature: " << before_mature_kb << "kB => " << mature_kb << "kB, "; std::cerr << "code: " << before_code_kb << "kB => " << code_kb << "kB, "; std::cerr << "symbols: " << data->symbol_bytes_allocated() / 1024 << "kB, "; std::cerr << "jit: " << data->jit_bytes_allocated() / 1024 << "kB, "; std::cerr << "time: " << stop << "ms (" << concur << "ms), "; std::cerr << capi_handles_->size() << " C-API handles, " << inflated_headers_->size() << " inflated headers]" << std::endl; if(state->shared().config.gc_noisy) { std::cerr << "\a\a" << std::flush; } } }
void ObjectMemory::collect_maybe(STATE, GCToken gct, CallFrame* call_frame) { // Don't go any further unless we're allowed to GC. if(!can_gc()) return; while(!state->stop_the_world()) { state->checkpoint(gct, call_frame); // Someone else got to the GC before we did! No problem, all done! if(!collect_young_now && !collect_mature_now) return; } // Ok, everyone in stopped! LET'S GC! SYNC(state); state->shared().finalizer_handler()->start_collection(state); if(cDebugThreading) { std::cerr << std::endl << "[" << state << " WORLD beginning GC.]" << std::endl; } GCData gc_data(state->vm(), gct); uint64_t start_time = 0; if(collect_young_now) { if(state->shared().config.gc_show) { start_time = get_current_time(); } YoungCollectStats stats; #ifdef RBX_PROFILER if(unlikely(state->vm()->tooling())) { tooling::GCEntry method(state, tooling::GCYoung); collect_young(gc_data, &stats); } else { collect_young(gc_data, &stats); } #else collect_young(gc_data, &stats); #endif if(state->shared().config.gc_show) { uint64_t fin_time = get_current_time(); int diff = (fin_time - start_time) / 1000000; std::cerr << "[GC " << std::fixed << std::setprecision(1) << stats.percentage_used << "% " << stats.promoted_objects << "/" << stats.excess_objects << " " << stats.lifetime << " " << diff << "ms]" << std::endl; if(state->shared().config.gc_noisy) { std::cerr << "\a" << std::flush; } } } if(collect_mature_now) { size_t before_kb = 0; if(state->shared().config.gc_show) { start_time = get_current_time(); before_kb = mature_bytes_allocated() / 1024; } #ifdef RBX_PROFILER if(unlikely(state->vm()->tooling())) { tooling::GCEntry method(state, tooling::GCMature); collect_mature(gc_data); } else { collect_mature(gc_data); } #else collect_mature(gc_data); #endif if(state->shared().config.gc_show) { uint64_t fin_time = get_current_time(); int diff = (fin_time - start_time) / 1000000; size_t kb = mature_bytes_allocated() / 1024; std::cerr << "[Full GC " << before_kb << "kB => " << kb << "kB " << diff << "ms]" << std::endl; if(state->shared().config.gc_noisy) { std::cerr << "\a\a" << std::flush; } } } state->shared().finalizer_handler()->finish_collection(state); state->restart_world(); UNSYNC; }