Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: rubinius/rubinius
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: aa83a0c7416d
Choose a base ref
...
head repository: rubinius/rubinius
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: ffd3943b8bcd
Choose a head ref
  • 2 commits
  • 9 files changed
  • 1 contributor

Commits on Mar 28, 2016

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    e271490 View commit details
  2. Partially mitigate allocation spills with concurrent marker.

    See the commit message for edd398c.
    brixen committed Mar 28, 2016
    Copy the full SHA
    ffd3943 View commit details
Showing with 76 additions and 27 deletions.
  1. +14 −7 machine/bytecode_verification.cpp
  2. +9 −0 machine/memory.cpp
  3. +1 −19 machine/memory/immix_marker.cpp
  4. +0 −1 machine/memory/immix_marker.hpp
  5. +2 −0 machine/metrics.cpp
  6. +3 −0 machine/metrics.hpp
  7. +15 −0 machine/thread_phase.hpp
  8. +29 −0 machine/vm.cpp
  9. +3 −0 machine/vm.hpp
21 changes: 14 additions & 7 deletions machine/bytecode_verification.cpp
Original file line number Diff line number Diff line change
@@ -40,27 +40,27 @@ namespace rubinius {
if(Fixnum* fix = try_as<Fixnum>(method_->local_count())) {
locals_ = fix->to_native();
} else {
fail("method not initialized properly", -1);
fail("local_count is not a Fixnum", -1);
return false;
}

InstructionSequence* iseq = try_as<InstructionSequence>(method_->iseq());
if(!iseq) {
fail("method not initialized properly", -1);
fail("iseq is not an InstructionSequence", -1);
return false;
}

if(Tuple* tup = try_as<Tuple>(iseq->opcodes())) {
ops_ = tup;
} else {
fail("method not initialized properly", -1);
fail("opcodes is not a Tuple", -1);
return false;
}

if(Fixnum* fix = try_as<Fixnum>(method_->stack_size())) {
max_stack_allowed_ = fix->to_native();
} else {
fail("method not initialized properly", -1);
fail("stack_size is not a Fixnum", -1);
return false;
}

@@ -72,11 +72,18 @@ namespace rubinius {
}

Fixnum* tot = try_as<Fixnum>(method_->total_args());
if(!tot) {
fail("total_args is not a Fixnum", -1);
return false;
}
Fixnum* req = try_as<Fixnum>(method_->required_args());
if(!req) {
fail("required_args is not a Fixnum", -1);
return false;
}
Fixnum* post = try_as<Fixnum>(method_->post_args());

if(!tot || !req || !post) {
fail("method not initialized properly (missing arg counts)", -1);
if(!post) {
fail("post_args is not a Fixnum", -1);
return false;
}

9 changes: 9 additions & 0 deletions machine/memory.cpp
Original file line number Diff line number Diff line change
@@ -804,6 +804,15 @@ namespace rubinius {
schedule_full_collection(
"mature region allocate object",
state->vm()->metrics().gc.immix_set);

if(mature_mark_concurrent_) {
/* Spilling allocations to the Large Object Space can be costly
* because that region and collector are less efficient. To mitigate
* spilling, we sleep for a very small random interval to allow the
* concurrent marking thread to catch up and complete the GC cycle.
*/
state->vm()->blocking_suspend(state, state->vm()->metrics().memory.suspend_ms);
}
}

collect_flag = false;
20 changes: 1 addition & 19 deletions machine/memory/immix_marker.cpp
Original file line number Diff line number Diff line change
@@ -61,24 +61,6 @@ namespace memory {
InternalThread::stop(state);
}

void ImmixMarker::suspend(STATE) {
static int i = 0;
static int delay[] = {
45, 17, 38, 31, 10, 40, 13, 37, 16, 37, 1, 20, 23, 43, 38, 4, 2, 26, 25, 5
};
static int modulo = sizeof(delay) / sizeof(int);
static struct timespec ts = {0, 0};

SleepPhase sleeping(state);

timer::StopWatch<timer::milliseconds> timer(
state->vm()->metrics().gc.immix_suspend_ms);

ts.tv_nsec = delay[i++ % modulo];

nanosleep(&ts, NULL);
}

void ImmixMarker::run(STATE) {
state->vm()->become_managed();

@@ -122,7 +104,7 @@ namespace memory {
continue;
}

suspend(state);
state->vm()->sleeping_suspend(state, state->vm()->metrics().gc.immix_suspend_ms);
}

state->memory()->clear_mature_mark_in_progress();
1 change: 0 additions & 1 deletion machine/memory/immix_marker.hpp
Original file line number Diff line number Diff line change
@@ -26,7 +26,6 @@ namespace memory {
void initialize(STATE);
void cleanup();
void run(STATE);
void suspend(STATE);
void stop(STATE);

void after_fork_child(STATE);
2 changes: 2 additions & 0 deletions machine/metrics.cpp
Original file line number Diff line number Diff line change
@@ -400,6 +400,8 @@ namespace rubinius {
"memory.capi_handles", metrics_data_.memory.capi_handles));
metrics_map_.push_back(new MetricsItem(
"memory.inflated_headers", metrics_data_.memory.inflated_headers));
metrics_map_.push_back(new MetricsItem(
"memory.suspend.ms", metrics_data_.memory.suspend_ms));

// System metrics
metrics_map_.push_back(new MetricsItem(
3 changes: 3 additions & 0 deletions machine/metrics.hpp
Original file line number Diff line number Diff line change
@@ -208,6 +208,7 @@ namespace rubinius {
metric data_objects;
metric capi_handles;
metric inflated_headers;
metric suspend_ms;

MemoryMetrics() {
young_bytes = 0;
@@ -228,6 +229,7 @@ namespace rubinius {
data_objects = 0;
capi_handles = 0;
inflated_headers = 0;
suspend_ms = 0;
}

void add(MemoryMetrics& data) {
@@ -249,6 +251,7 @@ namespace rubinius {
data_objects += data.data_objects;
capi_handles += data.capi_handles;
inflated_headers += data.inflated_headers;
suspend_ms += data.suspend_ms;
}
};

15 changes: 15 additions & 0 deletions machine/thread_phase.hpp
Original file line number Diff line number Diff line change
@@ -27,6 +27,21 @@ namespace rubinius {
}
};

class BlockPhase {
State* state_;

public:
BlockPhase(STATE)
: state_(state)
{
state->shared().thread_nexus()->blocking(state->vm());
}

~BlockPhase() {
state_->vm()->become_managed();
}
};

class SleepPhase {
State* state_;

29 changes: 29 additions & 0 deletions machine/vm.cpp
Original file line number Diff line number Diff line change
@@ -3,6 +3,8 @@
#include "memory.hpp"
#include "global_cache.hpp"
#include "environment.hpp"
#include "thread_phase.hpp"

#include "memory/gc.hpp"

#include "object_utils.hpp"
@@ -201,6 +203,33 @@ namespace rubinius {
memory()->collect_maybe(state);
}

static void suspend_thread() {
static int i = 0;
static int delay[] = {
45, 17, 38, 31, 10, 40, 13, 37, 16, 37, 1, 20, 23, 43, 38, 4, 2, 26, 25, 5
};
static int modulo = sizeof(delay) / sizeof(int);
static struct timespec ts = {0, 0};

ts.tv_nsec = delay[i++ % modulo];

nanosleep(&ts, NULL);
}

void VM::blocking_suspend(STATE, metrics::metric& counter) {
timer::StopWatch<timer::milliseconds> timer(counter);

BlockPhase blocking(state);
suspend_thread();
}

void VM::sleeping_suspend(STATE, metrics::metric& counter) {
timer::StopWatch<timer::milliseconds> timer(counter);

SleepPhase sleeping(state);
suspend_thread();
}

void VM::become_managed() {
thread_nexus_->managed_lock(this);
}
3 changes: 3 additions & 0 deletions machine/vm.hpp
Original file line number Diff line number Diff line change
@@ -422,6 +422,9 @@ namespace rubinius {
}
}

void blocking_suspend(STATE, metrics::metric& counter);
void sleeping_suspend(STATE, metrics::metric& counter);

void become_managed();
void become_unmanaged() {
thread_phase_ = ThreadNexus::cUnmanaged;