Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Tooling can be enabled anytime, anywhere.

  • Loading branch information...
commit 8133e094ce50fe449ad1a9491b7b217a2946b76d 1 parent 4aa76a4
Evan Phoenix authored
View
20 kernel/bootstrap/rubinius.rb
@@ -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"
@@ -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"
View
2  lib/profiler.rb
@@ -1,3 +1,5 @@
+require 'tooling/profiler/profiler'
+
module Profiler__
def start_profile
@p = Rubinius::Profiler::Instrumenter.new
View
9 lib/tooling/profiler/profiler.rb
@@ -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"]
View
37 lib/tooling/profiler/profiler_vm.cpp
@@ -361,6 +361,10 @@ namespace profiler {
attached_ = false;
}
+ bool attached_p() {
+ return attached_;
+ }
+
int id() {
return id_;
}
@@ -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);
}
@@ -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,
@@ -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;
@@ -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);
@@ -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();
@@ -863,6 +893,10 @@ namespace profiler {
prof->results(env, thread, nodes, methods, keys, runtime);
}
+ tool_shutdown(env);
+ delete profiler;
+
+ env->disable_thread_tooling();
return profile;
}
@@ -870,7 +904,6 @@ namespace profiler {
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();
View
2  spec/custom/guards/profiler.rb
@@ -1,3 +1,5 @@
+require 'tooling/profiler/profiler'
+
class ProfilerGuard < SpecGuard
def match?
Rubinius::Profiler::Instrumenter.available? and
View
73 vm/builtin/system.cpp
@@ -12,6 +12,8 @@
#include <unistd.h>
#include <pwd.h>
+#include <dlfcn.h>
+
#include "vm/call_frame.hpp"
#include "vm/helpers.hpp"
@@ -60,6 +62,8 @@
#include "instruments/tooling.hpp"
+#include "gc/walker.hpp"
+
#ifdef ENABLE_LLVM
#include "llvm/jit.hpp"
#include "llvm/jit_compiler.hpp"
@@ -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;
@@ -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;
View
9 vm/builtin/system.hpp
@@ -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);
@@ -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);
View
1  vm/capi/include/rbxti.hpp
@@ -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);
View
6 vm/configuration.hpp
@@ -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() { }
};
}
View
4 vm/instruments/rbxti.cpp
@@ -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();
}
View
13 vm/instruments/tooling.cpp
@@ -1,6 +1,7 @@
#include "vm/vm.hpp"
#include "arguments.hpp"
#include "dispatch.hpp"
+#include "configuration.hpp"
#include "instruments/rbxti-internal.hpp"
#include "instruments/tooling.hpp"
@@ -8,6 +9,7 @@
#include "builtin/compiledmethod.hpp"
#include "builtin/block_environment.hpp"
#include "builtin/variable_scope.hpp"
+#include "builtin/system.hpp"
namespace rubinius {
namespace tooling {
@@ -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());
}
@@ -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()));
}
View
32 vm/llvm/jit.cpp
@@ -334,23 +334,27 @@ namespace rubinius {
jit.show_machine_code();
}
- req->vmmethod()->set_jitted(jit.llvm_function(),
- jit.code_bytes(),
- func);
-
- if(!req->is_block()) {
- req->method()->execute = reinterpret_cast<executor>(func);
- }
- assert(req->method()->jit_data());
+ // If the method has had jit'ing request disabled since we started
+ // JIT'ing it, discard our work.
+ if(!req->vmmethod()->jit_disabled()) {
+ req->vmmethod()->set_jitted(jit.llvm_function(),
+ jit.code_bytes(),
+ func);
+
+ if(!req->is_block()) {
+ req->method()->execute = reinterpret_cast<executor>(func);
+ }
+ assert(req->method()->jit_data());
- req->method()->jit_data()->run_write_barrier(ls_->write_barrier(), req->method());
+ req->method()->jit_data()->run_write_barrier(ls_->write_barrier(), req->method());
- ls_->shared().stats.jitted_methods++;
+ ls_->shared().stats.jitted_methods++;
- if(ls_->config().jit_show_compiling) {
- llvm::outs() << "[[[ JIT finished background compiling "
- << (req->is_block() ? " (block)" : " (method)")
- << " ]]]\n";
+ if(ls_->config().jit_show_compiling) {
+ llvm::outs() << "[[[ JIT finished background compiling "
+ << (req->is_block() ? " (block)" : " (method)")
+ << " ]]]\n";
+ }
}
// If someone was waiting on this, wake them up.
View
40 vm/vmmethod.cpp
@@ -680,23 +680,37 @@ namespace rubinius {
/* This is a noop for this class. */
void VMMethod::compile(STATE) { }
- void VMMethod::deoptimize(STATE, CompiledMethod* original) {
+ // If +disable+ is set, then the method is tagged as not being
+ // available for JIT.
+ void VMMethod::deoptimize(STATE, CompiledMethod* original, bool disable) {
#ifdef ENABLE_LLVM
- // This resets execute to use the interpreter
- setup_argument_handler(original);
+ if(jitted_impl_) {
+ // This resets execute to use the interpreter
+ setup_argument_handler(original);
- // Don't call LLVMState::get(state)->remove(llvm_function_)
- // here. We let the CodeManager do that later, when we're sure
- // the llvm function is no longer used.
- llvm_function_ = 0;
- jitted_impl_ = 0;
- jitted_bytes_ = 0;
+ // Don't call LLVMState::get(state)->remove(llvm_function_)
+ // here. We let the CodeManager do that later, when we're sure
+ // the llvm function is no longer used.
+ llvm_function_ = 0;
- // Remove any JIT data, which will be cleanup by the CodeManager
- // later.
- original->set_jit_data(0);
+ jitted_impl_ = 0;
- call_count = 0;
+ if(disable) {
+ jitted_bytes_ = -1;
+ } else {
+ jitted_bytes_ = 0;
+ }
+
+ // Remove any JIT data, which will be cleanup by the CodeManager
+ // later.
+ original->set_jit_data(0);
+ }
+
+ if(disable) {
+ call_count = -1;
+ } else {
+ call_count = 0;
+ }
#endif
}
View
10 vm/vmmethod.hpp
@@ -73,7 +73,7 @@ namespace rubinius {
#ifdef ENABLE_LLVM
private:
llvm::Function* llvm_function_;
- size_t jitted_bytes_;
+ int jitted_bytes_;
void* jitted_impl_;
#endif
@@ -94,7 +94,11 @@ namespace rubinius {
#ifdef ENABLE_LLVM
bool jitted() {
- return jitted_impl_ != 0;
+ return jit_disabled() && jitted_impl_ != 0;
+ }
+
+ bool jit_disabled() {
+ return jitted_bytes_ == -1;
}
void set_jitted(llvm::Function* func, size_t bytes, void* impl) {
@@ -227,7 +231,7 @@ namespace rubinius {
void initialize_caches(STATE, CompiledMethod* original, int sends);
void find_super_instructions();
- void deoptimize(STATE, CompiledMethod* original);
+ void deoptimize(STATE, CompiledMethod* original, bool disable=false);
/*
* Helper class for iterating over an Opcode array. Used to convert a
Please sign in to comment.
Something went wrong with that request. Please try again.