Skip to content

Commit

Permalink
Tooling can be enabled anytime, anywhere.
Browse files Browse the repository at this point in the history
  • Loading branch information
Evan Phoenix committed Apr 4, 2011
1 parent 4aa76a4 commit 8133e09
Show file tree
Hide file tree
Showing 14 changed files with 219 additions and 39 deletions.
20 changes: 20 additions & 0 deletions kernel/bootstrap/rubinius.rb
Expand Up @@ -44,6 +44,12 @@ def self.deoptimize_inliners(exec)
raise PrimitiveFailure, "Rubinius.vm_deoptimize_inliners failed"
end

# Deoptimize all methods in the system.
def self.deoptimize_all(disable)
Ruby.primitive :vm_deoptimize_all
raise PrimitiveFailure, "Rubinius.vm_deoptimize_all failed"
end

def self.raise_exception(exc)
Ruby.primitive :vm_raise_exception
raise PrimitiveFailure, "Rubinius.vm_raise_exception failed"
Expand Down Expand Up @@ -120,6 +126,20 @@ def self.run_script(cm)
end

module Tooling
def self.raw_load(str)
Ruby.primitive :vm_load_tool
raise PrimitiveFailure, "Tooling.raw_load failed"
end

def self.load(str)
error, reason = raw_load(str)
unless error == true
raise ArgumentError, reason
end

return true
end

def self.available?
Ruby.primitive :vm_tooling_available_p
raise PrimitiveFailure, "Tooling.available? failed"
Expand Down
2 changes: 2 additions & 0 deletions lib/profiler.rb
@@ -1,3 +1,5 @@
require 'tooling/profiler/profiler'

module Profiler__
def start_profile
@p = Rubinius::Profiler::Instrumenter.new
Expand Down
9 changes: 9 additions & 0 deletions lib/tooling/profiler/profiler.rb
Expand Up @@ -17,7 +17,16 @@ def self.active?
Rubinius::Tooling.active?
end

@loaded = false
def self.load
return if @loaded
Rubinius::Tooling.load File.expand_path("../profiler_vm", __FILE__)
@loaded = true
end

def initialize(options = {})
Instrumenter.load

@options = { :sort => :percent }
set_options options
set_options :full_report => true if Config["profiler.full_report"]
Expand Down
37 changes: 35 additions & 2 deletions lib/tooling/profiler/profiler_vm.cpp
Expand Up @@ -361,6 +361,10 @@ namespace profiler {
attached_ = false;
}

bool attached_p() {
return attached_;
}

int id() {
return id_;
}
Expand Down Expand Up @@ -700,8 +704,13 @@ namespace profiler {
}

struct GlobalState {
Profiler* main_profiler;
std::list<Profiler*> profilers;

GlobalState()
: main_profiler(0)
{}

void add(Profiler* prof) {
profilers.push_back(prof);
}
Expand All @@ -715,8 +724,12 @@ namespace profiler {
env->set_global_tool_data(st);

Profiler* profiler = new Profiler(env);
st->main_profiler = profiler;

env->thread_tool_set_data(cProfileToolID, profiler);
st->add(profiler);

env->enable_thread_tooling();
}

void* tool_enter_method(Env* env, robject recv, rsymbol name, rmodule mod,
Expand Down Expand Up @@ -805,12 +818,16 @@ namespace profiler {

void tool_shutdown(Env* env) {
GlobalState* st = (GlobalState*)env->global_tool_data();
if(!st) return;

env->set_global_tool_data(0);

for(std::list<Profiler*>::iterator i = st->profilers.begin();
i != st->profilers.end();
++i) {

Profiler* prof = *i;
delete prof;
if(!prof->attached_p()) delete prof;
}

delete st;
Expand All @@ -819,6 +836,9 @@ namespace profiler {
void tool_start_thread(Env* env) {
GlobalState* st = (GlobalState*)env->global_tool_data();

// No GlobalState means that the tool isn't currently enabled.
if(!st) return;

Profiler* profiler = new Profiler(env);
st->add(profiler);

Expand All @@ -833,11 +853,21 @@ namespace profiler {

env->thread_tool_set_data(cProfileToolID, 0);
profiler->detach();

env->disable_thread_tooling();
}

robject tool_results(Env* env) {
GlobalState* st = (GlobalState*)env->global_tool_data();

Profiler* profiler = (Profiler*)env->thread_tool_data(cProfileToolID);

// Ignore results requests that don't come from the thread that
// started profiling.
if(st->main_profiler != profiler) return env->nil();

env->thread_tool_set_data(cProfileToolID, 0);

rtable profile = env->table_new();

for(std::list<Profiler*>::iterator i = st->profilers.begin();
Expand All @@ -863,14 +893,17 @@ namespace profiler {
prof->results(env, thread, nodes, methods, keys, runtime);
}

tool_shutdown(env);
delete profiler;

env->disable_thread_tooling();
return profile;
}

}

extern "C" int Tool_Init(Env* env) {
env->config_set("tool.require", "tooling/profiler/profiler.rb");
env->config_set("int", "true");

cProfileToolID = env->thread_tool_new_id();

Expand Down
2 changes: 2 additions & 0 deletions spec/custom/guards/profiler.rb
@@ -1,3 +1,5 @@
require 'tooling/profiler/profiler'

class ProfilerGuard < SpecGuard
def match?
Rubinius::Profiler::Instrumenter.available? and
Expand Down
73 changes: 71 additions & 2 deletions vm/builtin/system.cpp
Expand Up @@ -12,6 +12,8 @@
#include <unistd.h>
#include <pwd.h>

#include <dlfcn.h>

#include "vm/call_frame.hpp"
#include "vm/helpers.hpp"

Expand Down Expand Up @@ -60,6 +62,8 @@

#include "instruments/tooling.hpp"

#include "gc/walker.hpp"

#ifdef ENABLE_LLVM
#include "llvm/jit.hpp"
#include "llvm/jit_compiler.hpp"
Expand Down Expand Up @@ -480,15 +484,53 @@ namespace rubinius {

Object* System::vm_tooling_enable(STATE) {
state->shared.tool_broker()->enable(state);
state->enable_tooling();
return Qtrue;
}

Object* System::vm_tooling_disable(STATE) {
state->disable_tooling();
return state->shared.tool_broker()->results(state);
}

Object* System::vm_load_tool(STATE, String* str) {
std::string path = std::string(str->c_str(state)) + ".";

#ifdef _WIN32
path += "dll";
#else
#ifdef __APPLE_CC__
path += "bundle";
#else
path += "so";
#endif
#endif

void* handle = dlopen(path.c_str(), RTLD_NOW);
if(!handle) {
path = std::string(RBX_LIB_PATH) + "/" + path;

handle = dlopen(path.c_str(), RTLD_NOW);
if(!handle) {
return Tuple::from(state, 2, Qfalse, String::create(state, dlerror()));
}
}

void* sym = dlsym(handle, "Tool_Init");
if(!sym) {
dlclose(handle);
return Tuple::from(state, 2, Qfalse, String::create(state, dlerror()));
} else {
typedef int (*init_func)(rbxti::Env* env);
init_func init = (init_func)sym;

if(!init(state->tooling_env())) {
dlclose(handle);
return Tuple::from(state, 2, Qfalse, String::create(state, path.c_str()));
}
}

return Tuple::from(state, 1, Qtrue);
}

Object* System::vm_write_error(STATE, String* str) {
std::cerr << str->c_str(state) << std::endl;
return Qnil;
Expand Down Expand Up @@ -804,6 +846,33 @@ namespace rubinius {
return Qtrue;
}

Object* System::vm_deoptimize_all(STATE, Object* o_disable) {
ObjectWalker walker(state->om);
GCData gc_data(state);

// Seed it with the root objects.
walker.seed(gc_data);

Object* obj = walker.next();

int total = 0;

bool disable = RTEST(o_disable);

while(obj) {
if(CompiledMethod* cm = try_as<CompiledMethod>(obj)) {
if(VMMethod* vmm = cm->backend_method()) {
vmm->deoptimize(state, cm, disable);
}
total++;
}

obj = walker.next();
}

return Integer::from(state, total);
}

Object* System::vm_raise_exception(STATE, Exception* exc) {
state->thread_state()->raise_exception(exc);
return NULL;
Expand Down
9 changes: 9 additions & 0 deletions vm/builtin/system.hpp
Expand Up @@ -124,6 +124,10 @@ namespace rubinius {
// Ruby.primitive :vm_mri_backtrace
static Array* vm_mri_backtrace(STATE, Fixnum* skip, CallFrame* calling_environment);

// Load a tool into the VM.
// Ruby.primitive :vm_load_tool
static Object* vm_load_tool(STATE, String* str);

/** Return true if tooling is enabled */
// Ruby.primitive :vm_tooling_available_p
static Object* vm_tooling_available_p(STATE);
Expand Down Expand Up @@ -223,6 +227,11 @@ namespace rubinius {
// Ruby.primitive :vm_deoptimize_inliners
static Object* vm_deoptimize_inliners(STATE, Executable* exec);

// Deoptimize all methods.
// +disable+ indicates if the methods should also be pulled from being
// available for JIT.
static Object* vm_deoptimize_all(STATE, Object* disable);

// Ruby.primitive :vm_raise_exception
static Object* vm_raise_exception(STATE, Exception* exc);

Expand Down
1 change: 1 addition & 0 deletions vm/capi/include/rbxti.hpp
Expand Up @@ -73,6 +73,7 @@ namespace rbxti {
int current_thread_id();

void enable_thread_tooling();
void disable_thread_tooling();

rinteger integer_new(r_mint val);
r_mint integer_value(rinteger i);
Expand Down
6 changes: 1 addition & 5 deletions vm/configuration.hpp
Expand Up @@ -203,11 +203,7 @@ namespace rubinius {
"Set a custom path to write crash reports");
}

void finalize() {
if(profile) {
tool_to_load.set("tooling/profiler/profiler_vm");
}
}
void finalize() { }
};
}

Expand Down
4 changes: 4 additions & 0 deletions vm/instruments/rbxti.cpp
Expand Up @@ -151,6 +151,10 @@ namespace rbxti {
private_->state()->enable_tooling();
}

void Env::disable_thread_tooling() {
private_->state()->disable_tooling();
}

int Env::current_thread_id() {
return private_->state()->thread_id();
}
Expand Down
13 changes: 13 additions & 0 deletions vm/instruments/tooling.cpp
@@ -1,13 +1,15 @@
#include "vm/vm.hpp"
#include "arguments.hpp"
#include "dispatch.hpp"
#include "configuration.hpp"

#include "instruments/rbxti-internal.hpp"
#include "instruments/tooling.hpp"

#include "builtin/compiledmethod.hpp"
#include "builtin/block_environment.hpp"
#include "builtin/variable_scope.hpp"
#include "builtin/system.hpp"

namespace rubinius {
namespace tooling {
Expand All @@ -19,6 +21,10 @@ namespace tooling {

void ToolBroker::enable(STATE) {
if(!enable_func_) return;

state->shared.config.jit_disabled.set("true");
System::vm_deoptimize_all(state, Qtrue);

enable_func_(state->tooling_env());
}

Expand All @@ -29,6 +35,13 @@ namespace tooling {

Object* ToolBroker::results(STATE) {
if(!results_func_) return Qnil;

state->shared.config.jit_disabled.set("false");

// This finds all the methods again and this time makes them available
// for JIT.
System::vm_deoptimize_all(state, Qfalse);

return rbxti::s(results_func_(state->tooling_env()));
}

Expand Down

0 comments on commit 8133e09

Please sign in to comment.