Skip to content

Commit

Permalink
Showing 15 changed files with 72 additions and 475 deletions.
28 changes: 5 additions & 23 deletions library/rubinius/configuration.rb
Original file line number Diff line number Diff line change
@@ -4,33 +4,15 @@
Rubinius::ConfigurationVariables.define do |c|

c.section "gc" do |s|
s.vm_variable "young_initial_bytes", 3145728,
"The initial number of bytes the young generation of the GC should use"

s.vm_variable "young_max_bytes", 5 * 3145728,
"The maximum number of bytes the young generation of the GC should use"

s.vm_variable "young_autotune_size", true,
"Set whether or not the young GC should autotune the size"

s.vm_variable "young_autotune_factor", 8,
"Set the young GC size autotune factor. This is the denominator of the fraction of total memory used for young GC"
s.vm_variable "young_bytes", (40 * 1024 * 1024),
"The number of bytes the young generation of the GC should use"

s.vm_variable "young_lifetime", 2,
"How many young GC cycles an object lives before promotion"

s.vm_variable "young_autotune_lifetime", true,
"Set whether or not the young GC should adjust promotion age for performance"

s.vm_variable "large_object", (50 * 1024),
s.vm_variable "large_object", (1024 * 1024),
"The size (in bytes) of the large object threshold"

s.vm_variable "show", :bool,
"Display information whenever the GC runs"

s.vm_variable "noisy", :bool,
"Beep whenever the GC runs (once for young, twice for mature). Requires gc.show"

s.vm_variable "immix.concurrent", true,
"Set whether we want the Immix mark phase to run concurrently"

@@ -43,10 +25,10 @@
s.vm_variable "autopack", true,
"Set whether or not objects should be packed tightly in memory"

s.vm_variable "marksweep_threshold", (10 * 1024 * 1024),
s.vm_variable "marksweep_threshold", (25 * 1024 * 1024),
"The number of bytes allocated before the marksweep GC region is collected"

s.vm_variable "malloc_threshold", 104857600,
s.vm_variable "malloc_threshold", (25 * 1024 * 1024),
"How many bytes allocated by C extensions til the GC is run"
end

123 changes: 13 additions & 110 deletions vm/gc/baker.cpp
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
#include "builtin/io.hpp"

#include "call_frame.hpp"
#include "configuration.hpp"

#include "gc/gc.hpp"

@@ -31,27 +32,16 @@ namespace rubinius {
* - Heap A and Heap B, which get one quarter of the heap each. Heaps A and B
* alternate between being the Current and Next space on each collection.
*/
BakerGC::BakerGC(ObjectMemory *om, size_t bytes)
BakerGC::BakerGC(ObjectMemory *om, Configuration& config)
: GarbageCollector(om)
, full(new Heap(bytes))
, eden(new Heap(full->allocate(bytes / 2), bytes / 2))
, heap_a(new Heap(full->allocate(bytes / 4), bytes / 4))
, heap_b(new Heap(full->allocate(bytes / 4), bytes / 4))
, full_new(NULL)
, eden_new(NULL)
, heap_a_new(NULL)
, heap_b_new(NULL)
, bytes_(config.gc_young_bytes * 2)
, full(new Heap(bytes_))
, eden(new Heap(full->allocate(bytes_ / 2), bytes_ / 2))
, heap_a(new Heap(full->allocate(bytes_ / 4), bytes_ / 4))
, heap_b(new Heap(full->allocate(bytes_ / 4), bytes_ / 4))
, current(heap_a)
, next(heap_b)
, total_objects(0)
, current_byte_size_(bytes)
, requested_byte_size_(bytes)
, original_lifetime_(1)
, lifetime_(1)
, copy_spills_(0)
, promoted_objects_(0)
, tune_threshold_(0)
, autotune_lifetime_(false)
, lifetime_(config.gc_young_lifetime)
{
reset();
}
@@ -98,9 +88,7 @@ namespace rubinius {
} else if(likely(next->enough_space_p(
obj->size_in_bytes(object_memory_->state())))) {
copy = next->move_object(object_memory_->state(), obj);
total_objects++;
} else {
copy_spills_++;
copy = object_memory_->promote_object(obj);
promoted_push(copy);
}
@@ -137,18 +125,10 @@ namespace rubinius {
return next->fully_scanned_p();
}

const static double cOverFullThreshold = 95.0;
const static int cOverFullTimes = 3;
const static size_t cMinimumLifetime = 1;

const static double cUnderFullThreshold = 20.0;
const static int cUnderFullTimes = -3;
const static size_t cMaximumLifetime = 6;

/**
* Perform garbage collection on the young objects.
*/
void BakerGC::collect(GCData* data, YoungCollectStats* stats) {
void BakerGC::collect(GCData* data) {

#ifdef HAVE_VALGRIND_H
(void)VALGRIND_MAKE_MEM_DEFINED(next->start().as_int(), next->size());
@@ -157,15 +137,8 @@ namespace rubinius {
mprotect(next->start(), next->size(), PROT_READ | PROT_WRITE);
mprotect(current->start(), current->size(), PROT_READ | PROT_WRITE);

check_growth_start();

ObjectArray *current_rs = object_memory_->swap_remember_set();

total_objects = 0;

copy_spills_ = 0;
reset_promoted();

// Start by copying objects in the remember set
for(ObjectArray::iterator oi = current_rs->begin();
oi != current_rs->end();
@@ -199,7 +172,10 @@ namespace rubinius {
}
}

for(Allocator<capi::Handle>::Iterator i(data->handles()->allocator()); i.more(); i.advance()) {
for(Allocator<capi::Handle>::Iterator i(data->handles()->allocator());
i.more();
i.advance())
{
if(!i->in_use_p()) continue;

if(!i->weak_p() && i->object()->young_object_p()) {
@@ -293,47 +269,9 @@ namespace rubinius {
Heap* x = next;
next = current;
current = x;

if(stats) {
stats->lifetime = lifetime_;
stats->percentage_used = current->percentage_used();
stats->promoted_objects = promoted_objects_;
stats->excess_objects = copy_spills_;
}

// Tune the age at which promotion occurs
if(autotune_lifetime_) {
double used = current->percentage_used();
if(used > cOverFullThreshold) {
if(tune_threshold_ >= cOverFullTimes) {
if(lifetime_ > cMinimumLifetime) lifetime_--;
} else {
tune_threshold_++;
}
} else if(used < cUnderFullThreshold) {
if(tune_threshold_ <= cUnderFullTimes) {
if(lifetime_ < cMaximumLifetime) lifetime_++;
} else {
tune_threshold_--;
}
} else if(tune_threshold_ > 0) {
tune_threshold_--;
} else if(tune_threshold_ < 0) {
tune_threshold_++;
} else if(tune_threshold_ == 0) {
if(lifetime_ < original_lifetime_) {
lifetime_++;
} else if(lifetime_ > original_lifetime_) {
lifetime_--;
}
}
}

}

void BakerGC::reset() {
check_growth_finish();

next->reset();
eden->reset();

@@ -362,41 +300,6 @@ namespace rubinius {
return true;
}

void BakerGC::check_growth_start() {
if(unlikely(current_byte_size_ != requested_byte_size_)) {

full_new = new Heap(requested_byte_size_);
eden_new = new Heap(full_new->allocate(requested_byte_size_ / 2), requested_byte_size_ / 2);
heap_a_new = new Heap(full_new->allocate(requested_byte_size_ / 4), requested_byte_size_ / 4);
heap_b_new = new Heap(full_new->allocate(requested_byte_size_ / 4), requested_byte_size_ / 4);

// Install the next pointer so we move objects to the new memory space.
next = heap_a_new;
}
}

void BakerGC::check_growth_finish() {
if(unlikely(full_new)) {
delete heap_a;
delete heap_b;
delete eden;
delete full;
heap_a = heap_a_new;
heap_b = heap_b_new;
eden = eden_new;
full = full_new;
current = heap_a_new;
next = heap_b_new;

heap_a_new = NULL;
heap_b_new = NULL;
eden_new = NULL;
full_new = NULL;

current_byte_size_ = requested_byte_size_;
}
}

void BakerGC::scan_mark_set() {
// Scan any mature objects in the mark set
// since they might refer to young objects.
104 changes: 6 additions & 98 deletions vm/gc/baker.hpp
Original file line number Diff line number Diff line change
@@ -23,7 +23,6 @@
namespace rubinius {

class GCData;
struct YoungCollectStats;

/**
* The BakerGC garbage collector is used for managing memory in the young
@@ -57,6 +56,7 @@ namespace rubinius {
*/

class BakerGC : public GarbageCollector {
unsigned int bytes_;

/// The total memory heap allocated to the BakerGC
Heap* full;
@@ -71,32 +71,13 @@ namespace rubinius {
Heap* heap_b;


/// The new heap if we request a resize. We need to set
/// this up at the start of a young GC cycle and clean
/// up at the end
Heap* full_new;

/// The new Eden space heap when resizing
Heap* eden_new;

/// The new A heap when resizing
Heap* heap_a_new;

/// The new B heap when resizing
Heap* heap_b_new;

/// Pointer to the Current space heap (i.e. Heap A or B)
Heap* current;

/// Pointer to the Next space heap (i.e. Heap B or A)
Heap* next;

public:
/// Total number of objects currently allocated in the young generation
/// Note: This does not include objects allocated in the Eden space in
/// thread-local slabs.
size_t total_objects;

/**
* Allocates a slab of memory from the Eden space for use as a thread-local
* allocation area that can be used without locking.
@@ -134,7 +115,6 @@ namespace rubinius {
if(!eden->enough_space_p(bytes)) {
return NULL;
} else {
total_objects++;
obj = eden->allocate(bytes).as<Object>();

if(eden->over_limit_p(obj)) {
@@ -167,7 +147,6 @@ namespace rubinius {
if(!eden->enough_space_p(bytes)) {
return NULL;
} else {
total_objects++;
obj = eden->allocate(bytes).as<Object>();

if(eden->over_limit_p(obj)) {
@@ -192,36 +171,9 @@ namespace rubinius {
/// not yet scanned
ObjectArray promoted_stack_;

/// Current size of the young gen, number of bytes in Eden
size_t current_byte_size_;

/// Request size of new young space for resizing
size_t requested_byte_size_;

/// The original configured lifetime objects had to survive before being
/// promoted to the mature generation
unsigned int original_lifetime_;

/// The current lifetime objects have to survive before being promoted
unsigned int lifetime_;

/// Count of the number of objects that were promoted to the mature
/// generation on the current collection due to lack of space in the Next
/// space.
int copy_spills_;

/// Count of the number of objects promoted on the current collection
int promoted_objects_;

/// Count of the successive number of times a collection has gone over
/// the cOverFullThreshhold (positive value) or under the
/// cUnderFullThreshhold (negative value). Used to auto-tune the age
/// at which objects are promoted to the mature generation.
int tune_threshold_;

/// True if the young to mature promotion threshhold should be auto-tuned
bool autotune_lifetime_;

/**
* Adds the specified object to the promoted objects stack.
* Objects on the promoted_objects_ stack must be scanned after the
@@ -230,20 +182,9 @@ namespace rubinius {
* remember set.
*/
void promoted_push(Object* obj) {
promoted_objects_++;
promoted_stack_.push_back(obj);
}

/**
* Reset the list of promoted objects.
*/
void reset_promoted() {
promoted_objects_ = 0;
}

void check_growth_start();
void check_growth_finish();

public:

/**
@@ -253,37 +194,6 @@ namespace rubinius {
return eden->used();
}

/**
* Returns the number of bytes used in the Eden space.
*/
size_t& bytes_size() {
return current_byte_size_;
}

/**
* Sets the age at which objects will be promoted from the young generation
* to the mature generation.
*/
void set_lifetime(int val) {
lifetime_ = original_lifetime_ = val;
}

/**
* Controls whether the BakerGC is self-tuning.
*
* This involves tweaking the lifetime threshhold at which objects are
* promoted to the mature generation, based on how full the Next space is
* following a collecion.
*/
void set_autotune_lifetime(bool val = true) {
autotune_lifetime_ = val;
}

/// Returns true if the BakerGC is auto-tuning
bool autotune_lifetime() {
return autotune_lifetime_;
}

/// Returns the start address of the young generation
void* start_address() {
return full->start();
@@ -296,13 +206,9 @@ namespace rubinius {

void reset();

void grow(size_t bytes) {
requested_byte_size_ = bytes;
}

public:
/* Prototypes */
BakerGC(ObjectMemory *om, size_t size);
BakerGC(ObjectMemory *om, Configuration& config);
virtual ~BakerGC();

/// Called for each object "seen" during the collection of the young
@@ -323,7 +229,7 @@ namespace rubinius {
bool fully_scanned_p();

/// Performs a collection of the young generation.
void collect(GCData* data, YoungCollectStats* stats = 0);
void collect(GCData* data);

/// Gathers statistics on the age of objects at the time of their death.
void find_lost_souls();
@@ -359,8 +265,10 @@ namespace rubinius {
/// Returns true if the specified object is in the Current space.
bool in_current_p(Object* obj);

double percentage_used() {
return current->percentage_used();
}
};

};

#endif
19 changes: 4 additions & 15 deletions vm/gc/gc.cpp
Original file line number Diff line number Diff line change
@@ -42,14 +42,12 @@ namespace rubinius {
#ifdef ENABLE_LLVM
, llvm_state_(state->shared.llvm_state)
#endif
, young_bytes_allocated_(state->om->young_bytes_allocated())
, mature_bytes_allocated_(state->om->mature_bytes_allocated())
, code_bytes_allocated_(state->om->code_bytes_allocated())
, symbol_bytes_allocated_(state->om->symbol_bytes_allocated())
{}
{ }

GarbageCollector::GarbageCollector(ObjectMemory *om)
:object_memory_(om), weak_refs_(NULL) { }
: object_memory_(om)
, weak_refs_(NULL)
{ }

VM* GarbageCollector::state() {
return object_memory_->state();
@@ -462,13 +460,4 @@ namespace rubinius {
}
}
}

size_t GCData::jit_bytes_allocated() const {
#ifdef ENABLE_LLVM
if(llvm_state_) {
return llvm_state_->code_bytes();
}
#endif
return 0;
}
}
22 changes: 0 additions & 22 deletions vm/gc/gc.hpp
Original file line number Diff line number Diff line change
@@ -38,10 +38,6 @@ namespace rubinius {
#ifdef ENABLE_LLVM
LLVMState* llvm_state_;
#endif
size_t young_bytes_allocated_;
size_t mature_bytes_allocated_;
size_t code_bytes_allocated_;
size_t symbol_bytes_allocated_;

public:
GCData(VM*);
@@ -75,24 +71,6 @@ namespace rubinius {
return llvm_state_;
}
#endif

size_t young_bytes_allocated() const {
return young_bytes_allocated_;
}

size_t mature_bytes_allocated() const {
return mature_bytes_allocated_;
}

size_t code_bytes_allocated() const {
return code_bytes_allocated_;
}

size_t symbol_bytes_allocated() const {
return symbol_bytes_allocated_;
}

size_t jit_bytes_allocated() const;
};

class AddressDisplacement {
4 changes: 2 additions & 2 deletions vm/llvm/inline.cpp
Original file line number Diff line number Diff line change
@@ -428,7 +428,7 @@ namespace rubinius {
}

ctx_->enter_inline();
ops_.llvm_state()->add_accessor_inlined();
ops_.llvm_state()->metrics().m.jit_metrics.inlined_accessors++;

check_recv(klass, data);

@@ -514,7 +514,7 @@ namespace rubinius {
}

ctx_->enter_inline();
ops_.llvm_state()->add_accessor_inlined();
ops_.llvm_state()->metrics().m.jit_metrics.inlined_accessors++;

check_recv(klass, data);

3 changes: 2 additions & 1 deletion vm/llvm/jit_compiler.cpp
Original file line number Diff line number Diff line change
@@ -135,7 +135,8 @@ namespace jit {

if(indy) ctx_->llvm_state()->shared().gc_dependent(ctx_->llvm_state()->vm());

ctx_->llvm_state()->add_code_bytes(mci_->size());
ctx_->llvm_state()->metrics().m.jit_metrics.bytes += mci_->size();

// Inject the RuntimeData objects used into the original CompiledCode
// Do this way after we've validated the IR so things are consistent.

2 changes: 1 addition & 1 deletion vm/llvm/jit_util.cpp
Original file line number Diff line number Diff line change
@@ -1255,7 +1255,7 @@ extern "C" {
int32_t unwind_count,
bool force_deoptimization) {

state->shared().llvm_state->add_uncommons_taken();
state->vm()->metrics().m.jit_metrics.uncommon_exits++;

MachineCode* mcode = call_frame->compiled_code->machine_code();

3 changes: 0 additions & 3 deletions vm/llvm/state.cpp
Original file line number Diff line number Diff line change
@@ -93,11 +93,8 @@ namespace rubinius {
, config_(state->shared().config)
, compile_list_(state)
, symbols_(state->shared().symbols)
, accessors_inlined_(0)
, uncommons_taken_(0)
, shared_(state->shared())
, include_profiling_(state->shared().config.jit_profile)
, code_bytes_(0)
, log_(NULL)
, enabled_(false)
, current_compiler_(0)
30 changes: 0 additions & 30 deletions vm/llvm/state.hpp
Original file line number Diff line number Diff line change
@@ -79,15 +79,9 @@ namespace rubinius {
TypedRoot<List*> compile_list_;
SymbolTable& symbols_;

int jitted_methods_;
int accessors_inlined_;
int uncommons_taken_;

SharedState& shared_;
bool include_profiling_;

int code_bytes_;

std::ostream* log_;

uint32_t fixnum_class_id_;
@@ -151,30 +145,6 @@ namespace rubinius {
jit::RubiniusJITMemoryManager* memory() { return memory_; }
llvm::JITEventListener* jit_event_listener() { return jit_event_listener_; }

int code_bytes() {
return code_bytes_;
}

void add_code_bytes(int bytes) {
code_bytes_ += bytes;
}

void add_accessor_inlined() {
accessors_inlined_++;
}

int accessors_inlined() {
return accessors_inlined_;
}

void add_uncommons_taken() {
uncommons_taken_++;
}

int uncommons_taken() {
return uncommons_taken_;
}

SharedState& shared() { return shared_; }

std::ostream& log() {
14 changes: 10 additions & 4 deletions vm/metrics.cpp
Original file line number Diff line number Diff line change
@@ -301,8 +301,18 @@ namespace rubinius {
"jit.methods.compiled", metrics_collection_.jit_metrics.methods_compiled));
metrics_map_.push_back(new MetricsItem(
"jit.methods.failed", metrics_collection_.jit_metrics.methods_failed));
metrics_map_.push_back(new MetricsItem(
"jit.bytes", metrics_collection_.jit_metrics.bytes));
metrics_map_.push_back(new MetricsItem(
"jit.time.us", metrics_collection_.jit_metrics.time_us));
metrics_map_.push_back(new MetricsItem(
"jit.uncommon_exits", metrics_collection_.jit_metrics.uncommon_exits));
metrics_map_.push_back(new MetricsItem(
"jit.inlined.accessors", metrics_collection_.jit_metrics.inlined_accessors));
metrics_map_.push_back(new MetricsItem(
"jit.inlined.methods", metrics_collection_.jit_metrics.inlined_methods));
metrics_map_.push_back(new MetricsItem(
"jit.inlined.blocks", metrics_collection_.jit_metrics.inlined_blocks));

// Object memory metrics
metrics_map_.push_back(new MetricsItem(
@@ -337,8 +347,6 @@ namespace rubinius {
metrics_collection_.ruby_metrics.memory_symbols_bytes));
metrics_map_.push_back(new MetricsItem(
"memory.code.bytes", metrics_collection_.ruby_metrics.memory_code_bytes));
metrics_map_.push_back(new MetricsItem(
"memory.jit.bytes", metrics_collection_.ruby_metrics.memory_jit_bytes));
metrics_map_.push_back(new MetricsItem(
"memory.promoted.bytes",
metrics_collection_.ruby_metrics.memory_promoted_bytes));
@@ -366,8 +374,6 @@ namespace rubinius {
"gc.young.count", metrics_collection_.ruby_metrics.gc_young_count));
metrics_map_.push_back(new MetricsItem(
"gc.young.ms", metrics_collection_.ruby_metrics.gc_young_ms));
metrics_map_.push_back(new MetricsItem(
"gc.young.lifetime", metrics_collection_.ruby_metrics.gc_young_lifetime));
metrics_map_.push_back(new MetricsItem(
"gc.immix.count", metrics_collection_.ruby_metrics.gc_immix_count));
metrics_map_.push_back(new MetricsItem(
21 changes: 15 additions & 6 deletions vm/metrics.hpp
Original file line number Diff line number Diff line change
@@ -44,7 +44,6 @@ namespace rubinius {
metric memory_symbols;
metric memory_symbols_bytes;
metric memory_code_bytes;
metric memory_jit_bytes;
metric memory_promoted_bytes;
metric memory_promoted_objects;
metric memory_slab_refills;
@@ -56,7 +55,6 @@ namespace rubinius {
// Garbage collector metrics
metric gc_young_count;
metric gc_young_ms;
metric gc_young_lifetime;
metric gc_immix_count;
metric gc_immix_stop_ms;
metric gc_immix_concurrent_ms;
@@ -75,7 +73,6 @@ namespace rubinius {
memory_symbols = 0;
memory_symbols_bytes = 0;
memory_code_bytes = 0;
memory_jit_bytes = 0;
memory_promoted_bytes = 0;
memory_promoted_objects = 0;
memory_slab_refills = 0;
@@ -85,7 +82,6 @@ namespace rubinius {
memory_inflated_headers = 0;
gc_young_count = 0;
gc_young_ms = 0;
gc_young_lifetime = 0;
gc_immix_count = 0;
gc_immix_stop_ms = 0;
gc_immix_concurrent_ms = 0;
@@ -105,7 +101,6 @@ namespace rubinius {
memory_symbols += data.memory_symbols;
memory_symbols_bytes += data.memory_symbols_bytes;
memory_code_bytes += data.memory_code_bytes;
memory_jit_bytes += data.memory_jit_bytes;
memory_promoted_bytes += data.memory_promoted_bytes;
memory_promoted_objects += data.memory_promoted_objects;
memory_slab_refills += data.memory_slab_refills;
@@ -116,7 +111,6 @@ namespace rubinius {
memory_inflated_headers += data.memory_inflated_headers;
gc_young_count += data.gc_young_count;
gc_young_ms += data.gc_young_ms;
gc_young_lifetime += data.gc_young_lifetime;
gc_immix_count += data.gc_immix_count;
gc_immix_stop_ms += data.gc_immix_stop_ms;
gc_immix_concurrent_ms += data.gc_immix_concurrent_ms;
@@ -148,20 +142,35 @@ namespace rubinius {
metric methods_queued;
metric methods_compiled;
metric methods_failed;
metric bytes;
metric time_us;
metric uncommon_exits;
metric inlined_accessors;
metric inlined_methods;
metric inlined_blocks;

void init() {
methods_queued = 0;
methods_compiled = 0;
methods_failed = 0;
bytes = 0;
time_us = 0;
uncommon_exits = 0;
inlined_accessors = 0;
inlined_methods = 0;
inlined_blocks = 0;
}

void add(JITMetrics& data) {
methods_queued += data.methods_queued;
methods_compiled += data.methods_compiled;
methods_failed += data.methods_failed;
bytes += data.bytes;
time_us += data.time_us;
uncommon_exits += data.uncommon_exits;
inlined_accessors += data.inlined_accessors;
inlined_methods += data.inlined_methods;
inlined_blocks += data.inlined_blocks;
}

void add(MetricsData& data);
140 changes: 9 additions & 131 deletions vm/object_memory.cpp
Original file line number Diff line number Diff line change
@@ -54,7 +54,7 @@ namespace rubinius {

/* ObjectMemory methods */
ObjectMemory::ObjectMemory(VM* state, Configuration& config)
: young_(new BakerGC(this, config.gc_young_initial_bytes * 2))
: young_(new BakerGC(this, config))
, mark_sweep_(new MarkSweepGC(this, config))
, immix_(new ImmixGC(this))
, immix_marker_(NULL)
@@ -67,16 +67,12 @@ namespace rubinius {
, mature_gc_in_progress_(false)
, slab_size_(4096)
, shared_(state->shared)

, collect_young_now(false)
, collect_mature_now(false)
, root_state_(state)
, last_object_id(1)
, last_snapshot_id(0)
, large_object_threshold(config.gc_large_object)
, young_max_bytes(config.gc_young_max_bytes * 2)
, young_autotune_factor(config.gc_young_autotune_factor)
, young_autotune_size(config.gc_young_autotune_size)
{
// TODO Not sure where this code should be...
#ifdef ENABLE_OBJECT_WATCH
@@ -86,10 +82,6 @@ namespace rubinius {
}
#endif

young_->set_lifetime(config.gc_young_lifetime);

if(config.gc_young_autotune_lifetime) young_->set_autotune_lifetime();

for(size_t i = 0; i < LastObjectType; i++) {
type_info[i] = NULL;
}
@@ -451,11 +443,6 @@ namespace rubinius {
}
}

// TODO: Fix API to support proper testing.
void ObjectMemory::set_young_lifetime(size_t age) {
young_->set_lifetime(age);
}

// TODO: Fix API to support proper testing.
void ObjectMemory::debug_marksweep(bool val) {
if(val) {
@@ -528,26 +515,22 @@ namespace rubinius {

if(collect_young_now) {
GCData gc_data(state->vm());
YoungCollectStats stats;

RUBINIUS_GC_BEGIN(0);
#ifdef RBX_PROFILER
if(unlikely(state->vm()->tooling())) {
tooling::GCEntry method(state, tooling::GCYoung);
collect_young(state, &gc_data, &stats);
collect_young(state, &gc_data);
} else {
collect_young(state, &gc_data, &stats);
collect_young(state, &gc_data);
}
#else
collect_young(state, &gc_data, &stats);
collect_young(state, &gc_data);
#endif
RUBINIUS_GC_END(0);

metrics::MetricsData& metrics = state->vm()->metrics();
metrics.m.ruby_metrics.memory_young_bytes +=
state->memory()->young_bytes_allocated();
metrics.m.ruby_metrics.memory_young_occupancy += stats.percentage_used;
metrics.m.ruby_metrics.gc_young_lifetime += stats.lifetime;
metrics.m.ruby_metrics.memory_young_occupancy += young_->percentage_used();
}

if(collect_mature_now) {
@@ -572,18 +555,15 @@ namespace rubinius {
state->restart_world();
}

void ObjectMemory::collect_young(STATE, GCData* data, YoungCollectStats* stats) {
void ObjectMemory::collect_young(STATE, GCData* data) {
#ifndef RBX_GC_STRESS_YOUNG
collect_young_now = false;
#endif

timer::StopWatch<timer::milliseconds> timerx(
state->vm()->metrics().m.ruby_metrics.gc_young_ms);

young_gc_while_marking_++;
young_->reset_stats();

young_->collect(data, stats);
young_->collect(data);

prune_handles(data->handles(), data->cached_handles(), young_);

@@ -627,7 +607,6 @@ namespace rubinius {

// If we're already collecting, ignore this request
if(mature_gc_in_progress_) return;
young_gc_while_marking_ = 0;

code_manager_.clear_marks();
clear_fiber_marks(data->threads());
@@ -673,36 +652,12 @@ namespace rubinius {
metrics.m.ruby_metrics.memory_symbols += shared_.symbols.size();
metrics.m.ruby_metrics.memory_symbols_bytes += shared_.symbols.bytes_used();
metrics.m.ruby_metrics.memory_code_bytes += code_manager_.size();
metrics.m.ruby_metrics.memory_jit_bytes += data->jit_bytes_allocated();

if(FinalizerThread* hdl = state->shared().finalizer_handler()) {
hdl->finish_collection(state);
}

RUBINIUS_GC_END(1);
young_autotune();
young_gc_while_marking_ = 0;
}

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);
}
}
}
}

immix::MarkStack& ObjectMemory::mature_mark_stack() {
@@ -785,35 +740,6 @@ namespace rubinius {
}
}

// TODO: delete after metrics
size_t ObjectMemory::young_bytes_allocated() const {
return young_->bytes_size();
}

// TODO: delete after metrics
size_t ObjectMemory::mature_bytes_allocated() const {
return immix_->bytes_allocated() + mark_sweep_->allocated_bytes;
}

// TODO: delete after metrics
size_t ObjectMemory::code_bytes_allocated() const {
return code_manager_.size();
}

// TODO: delete after metrics
size_t ObjectMemory::symbol_bytes_allocated() const {
return shared_.symbols.bytes_used();
}

// TODO: delete after metrics
size_t ObjectMemory::jit_bytes_allocated() const {
#if ENABLE_LLVM
return shared_.llvm_state->code_bytes();
#else
return 0;
#endif
}

void ObjectMemory::add_type_info(TypeInfo* ti) {
utilities::thread::SpinLock::LockGuard guard(shared_.type_info_lock());

@@ -948,8 +874,8 @@ namespace rubinius {
Object* obj = mark_sweep_->allocate(bytes, &collect_mature_now);
if(unlikely(!obj)) return NULL;

state()->metrics().m.ruby_metrics.memory_immix_objects++;
state()->metrics().m.ruby_metrics.memory_immix_bytes += bytes;
state()->metrics().m.ruby_metrics.memory_large_objects++;
state()->metrics().m.ruby_metrics.memory_large_bytes += bytes;

obj->clear_fields(bytes);
return obj;
@@ -1105,54 +1031,6 @@ namespace rubinius {
ObjectArray* ObjectMemory::weak_refs_set() {
return immix_->weak_refs_set();
}

size_t& ObjectMemory::loe_usage() {
return mark_sweep_->allocated_bytes;
}

size_t& ObjectMemory::young_usage() {
return young_->bytes_size();
}

size_t& ObjectMemory::immix_usage() {
return immix_->bytes_allocated();
}

size_t& ObjectMemory::code_usage() {
return code_manager_.size();
}

void ObjectMemory::memstats() {
size_t total = 0;

size_t baker = young_usage();
total += baker;
size_t immix = immix_usage();
total += immix;
size_t large = loe_usage();
total += large;
size_t code = code_usage();
total += code;
size_t shared = root_state_->shared.size();
total += shared;

std::cout << "baker: " << baker << "\n";
std::cout << "immix: " << immix << "\n";
std::cout << "large: " << large << "\n"
<< " objects: " << mark_sweep_->allocated_objects << "\n"
<< " times: " << mark_sweep_->times_collected << "\n"
<< " last_freed: " << mark_sweep_->last_freed << "\n";
std::cout << " code: " << code << "\n";
std::cout << "shared: " << shared << "\n";

std::cout << "total: "
<< ((double)total / (1024 * 1024))
<< " M\n";

std::cout << "CodeManager:\n";
std::cout << " total allocated: " << code_manager_.total_allocated() << "\n";
std::cout << " total freed: " << code_manager_.total_freed() << "\n";
}
};

// The following memory functions are defined in ruby.h for use by C-API
26 changes: 1 addition & 25 deletions vm/object_memory.hpp
Original file line number Diff line number Diff line change
@@ -45,22 +45,6 @@ namespace rubinius {
class GlobalHandle;
}

struct YoungCollectStats {
int bytes_copied;
double percentage_used;
int promoted_objects;
int lifetime;
int excess_objects;

YoungCollectStats()
: bytes_copied(0)
, percentage_used(0.0)
, promoted_objects(0)
, lifetime(0)
, excess_objects(0)
{}
};

/**
* ObjectMemory is the primary API that the rest of the VM uses to interact
* with actions such as allocating objects, storing data in objects, and
@@ -115,15 +99,13 @@ namespace rubinius {
/// The current mark value used when marking objects.
unsigned int mark_;

unsigned int young_gc_while_marking_;
/// Flag controlling whether garbage collections are allowed
bool allow_gc_;
/// Flag set when concurrent mature mark is requested
bool mature_mark_concurrent_;
/// Flag set when a mature GC is already in progress
bool mature_gc_in_progress_;
/// Flag set when requesting a young gen resize
bool young_gc_resize_;

/// Size of slabs to be allocated to threads for lockless thread-local
/// allocations.
@@ -153,9 +135,6 @@ namespace rubinius {

/* Config variables */
size_t large_object_threshold;
size_t young_max_bytes;
int young_autotune_factor;
bool young_autotune_size;

public:
VM* state() {
@@ -286,7 +265,6 @@ namespace rubinius {
}

TypeInfo* find_type_info(Object* obj);
void set_young_lifetime(size_t age);
Object* promote_object(Object* obj);

bool refill_slab(STATE, gc::Slab& slab);
@@ -346,13 +324,11 @@ namespace rubinius {

immix::MarkStack& mature_mark_stack();

void young_autotune();

private:
Object* allocate_object(size_t bytes);
Object* allocate_object_mature(size_t bytes);

void collect_young(STATE, GCData* data, YoungCollectStats* stats = 0);
void collect_young(STATE, GCData* data);
void collect_mature(STATE, GCData* data);

public:
8 changes: 4 additions & 4 deletions vm/test/test_object_memory.hpp
Original file line number Diff line number Diff line change
@@ -225,12 +225,12 @@ class TestObjectMemory : public CxxTest::TestSuite, public VMTest {

Root r(roots, young);

om.set_young_lifetime(1);

TS_ASSERT_EQUALS(young->age(), 0U);
om.collect_young(state, gc_data);
TS_ASSERT_EQUALS(roots->front()->get()->age(), 1U);
om.collect_young(state, gc_data);
TS_ASSERT_EQUALS(roots->front()->get()->age(), 2U);
om.collect_young(state, gc_data);

TS_ASSERT(roots->front()->get()->mature_object_p());
}
@@ -250,14 +250,14 @@ class TestObjectMemory : public CxxTest::TestSuite, public VMTest {
mature->field[0] = young;
om.write_barrier(mature, young);

om.set_young_lifetime(1);

TS_ASSERT_EQUALS(mature->remembered_p(), 1U);

TS_ASSERT_EQUALS(young->age(), 0U);
om.collect_young(state, gc_data);
TS_ASSERT_EQUALS(mature->field[0]->age(), 1U);
om.collect_young(state, gc_data);
TS_ASSERT_EQUALS(mature->field[0]->age(), 2U);
om.collect_young(state, gc_data);
}

void test_collect_young_uses_forwarding_pointers() {

0 comments on commit a8dcb34

Please sign in to comment.