Permalink
Browse files

Make interrupt checks in the JIT cheaper

We use the new VMJIT structure to read whether we have an interrupt
scheduled for this thread and check the status of whether we have to GC
from shared state.

Improves performance of for example Integer#gcd, because that checks
interrupts in the loop.

Before:
=== ./bin/rbx ===
Fixnum gcd Fixnum => Fixnum
                      3232489.4 (±3.7%) i/s -   16153410 in   5.004410s

After:
=== bin/rbx ===
Fixnum gcd Fixnum => Fixnum
                      3846171.8 (±2.4%) i/s -   19263285 in   5.011503s
  • Loading branch information...
1 parent 592485d commit e5ec5aa8a28fcbbe58786af1c5e8e41d2971dd38 @dbussink dbussink committed Jan 11, 2013
Showing with 64 additions and 17 deletions.
  1. +43 −2 vm/llvm/jit_visit.hpp
  2. +7 −7 vm/shared_state.cpp
  3. +14 −8 vm/shared_state.hpp
View
@@ -84,6 +84,7 @@ namespace rubinius {
bool use_full_scope_;
Value* global_serial_pos;
+ Value* check_gc_pos;
int called_args_;
int sends_done_;
@@ -177,7 +178,11 @@ namespace rubinius {
global_serial_pos = b().CreateIntToPtr(
clong((intptr_t)ls_->shared().global_serial_address()),
- llvm::PointerType::getUnqual(ls_->IntPtrTy), "cast_to_intptr");
+ llvm::PointerType::getUnqual(ls_->Int32Ty), "cast_to_intptr");
+
+ check_gc_pos = b().CreateIntToPtr(
+ clong((intptr_t)ls_->shared().check_gc_address()),
+ llvm::PointerType::getUnqual(ls_->Int8Ty), "cast_to_intptr");
init_out_args();
@@ -2004,7 +2009,7 @@ namespace rubinius {
Value* current_serial_pos = b().CreateIntToPtr(
clong((intptr_t)entry->serial_location()),
- llvm::PointerType::getUnqual(ls_->IntPtrTy), "cast_to_intptr");
+ llvm::PointerType::getUnqual(ls_->Int32Ty), "cast_to_intptr");
Value* current_serial = b().CreateLoad(current_serial_pos, "serial");
@@ -2765,6 +2770,39 @@ namespace rubinius {
}
void visit_check_interrupts() {
+
+ BasicBlock* cont = new_block("continue");
+ BasicBlock* interrupts = new_block("interrupts");
+ BasicBlock* done = new_block("done");
+
+ Value* idx_jit[] = {
+ cint(0),
+ cint(offset::State::vm_jit)
+ };
+
+ Value* vm_jit = b().CreateLoad(b().CreateGEP(state_, idx_jit), "vm_jit");
+
+ Value* idx_check[] = {
+ cint(0),
+ cint(offset::VMJIT::check_local_interrupts)
+ };
+
+ Value* check_interrupts = b().CreateLoad(b().CreateGEP(vm_jit, idx_check),
+ "check_interrupts");
+
+ Value* check_gc = b().CreateLoad(check_gc_pos, "check_gc");
+ Value* checkpoint = b().CreateOr(check_interrupts, check_gc, "or");
+
+ Value* zero = ConstantInt::get(ls_->Int8Ty, 0);
+ Value* is_zero = b().CreateICmpEQ(checkpoint, zero, "needs_interrupts");
+
+ create_conditional_branch(cont, interrupts, is_zero);
+
+ set_block(cont);
+ create_branch(done);
+
+ set_block(interrupts);
+
std::vector<Type*> types;
types.push_back(StateTy);
@@ -2787,6 +2825,9 @@ namespace rubinius {
Value* ret = b().CreateCall(func, call_args, "ci");
check_for_exception(ret, false);
+ create_branch(done);
+
+ set_block(done);
}
void visit_check_serial(opcode index, opcode serial) {
View
@@ -30,27 +30,27 @@
namespace rubinius {
SharedState::SharedState(Environment* env, Configuration& config, ConfigParser& cp)
- : initialized_(false)
- , auxiliary_threads_(0)
+ : auxiliary_threads_(0)
, signal_handler_(0)
, finalizer_handler_(0)
, global_handles_(new capi::Handles)
- , global_serial_(0)
, world_(new WorldState)
, ic_registry_(new InlineCacheRegistry)
+ , method_count_(0)
, class_count_(0)
+ , global_serial_(0)
, thread_ids_(1)
+ , initialized_(false)
+ , ruby_critical_set_(false)
+ , use_capi_lock_(false)
+ , check_gc_(false)
, kcode_page_(kcode::eAscii)
, kcode_table_(kcode::null_table())
, agent_(0)
, root_vm_(0)
, env_(env)
, tool_broker_(new tooling::ToolBroker)
- , ruby_critical_set_(false)
- , use_capi_lock_(false)
- , check_gc_(false)
, om(0)
-
, global_cache(new GlobalCache)
, config(config)
, user_variables(cp)
View
@@ -63,7 +63,6 @@ namespace rubinius {
class SharedState : public RefCount, public Lockable {
private:
- bool initialized_;
AuxiliaryThreads* auxiliary_threads_;
SignalHandler* signal_handler_;
FinalizerHandler* finalizer_handler_;
@@ -72,18 +71,23 @@ namespace rubinius {
std::list<capi::Handle*> cached_handles_;
std::list<capi::GlobalHandle*> global_handle_locations_;
- int global_serial_;
WorldState* world_;
InlineCacheRegistry* ic_registry_;
- unsigned int class_count_;
- uint64_t method_count_;
std::list<ManagedThread*> threads_;
+
+ uint64_t method_count_;
+ unsigned int class_count_;
+ int global_serial_;
int thread_ids_;
+ bool initialized_;
+ bool ruby_critical_set_;
+ bool use_capi_lock_;
+ bool check_gc_;
+
kcode::CodePage kcode_page_;
kcode::table* kcode_table_;
- int primitive_hits_[Primitives::cTotalPrimitives];
QueryAgent* agent_;
VM* root_vm_;
Environment* env_;
@@ -95,14 +99,12 @@ namespace rubinius {
// the name would make it sound.
utilities::thread::Mutex ruby_critical_lock_;
pthread_t ruby_critical_thread_;
- bool ruby_critical_set_;
- bool use_capi_lock_;
Mutex capi_lock_;
utilities::thread::SpinLock capi_ds_lock_;
- bool check_gc_;
+ int primitive_hits_[Primitives::cTotalPrimitives];
public:
Globals globals;
@@ -265,6 +267,10 @@ namespace rubinius {
check_gc_ = true;
}
+ bool* check_gc_address() {
+ return &check_gc_;
+ }
+
void set_use_capi_lock(bool s) {
use_capi_lock_ = s;
}

0 comments on commit e5ec5aa

Please sign in to comment.