Skip to content

Commit

Permalink
Don't inline calls for not often called methods
Browse files Browse the repository at this point in the history
This changes the JIT so we don't inline methods that aren't often
called, allowing for more room in JIT'ted code for methods that are
often called.

It also changes to keep track of compiling explicitly instead of
(ab)using the call_count for that. Resetting the call count had other
effects such as disabling that method for future jitting that has
adverse effects.

On my system this shaves off around 1 - 2 seconds of a CI run.
  • Loading branch information
dbussink committed Feb 24, 2013
1 parent 9f5349b commit a787d83
Show file tree
Hide file tree
Showing 11 changed files with 65 additions and 32 deletions.
6 changes: 1 addition & 5 deletions vm/builtin/compiledcode.cpp
Expand Up @@ -254,11 +254,7 @@ namespace rubinius {

// Must happen only on the first specialization
if(!v->unspecialized) {
if(execute == specialized_executor) {
rubinius::bug("cant setup unspecialized from specialized");
}

v->unspecialized = execute;
v->unspecialized = v->fallback;
}

for(int i = 0; i < MachineCode::cMaxSpecializations; i++) {
Expand Down
5 changes: 3 additions & 2 deletions vm/inline_cache.hpp
Expand Up @@ -301,9 +301,10 @@ namespace rubinius {
return NULL;
}

Class* get_class(int idx) {
MethodCacheEntry* entry = cache_[idx].entry();
Class* get_class(int idx, int* hits) {
MethodCacheEntry* entry = cache_[idx].entry();
if(entry) {
*hits = cache_[idx].hits();
return entry->receiver_class();
} else {
return NULL;
Expand Down
12 changes: 9 additions & 3 deletions vm/llvm/background_compile_request.hpp
Expand Up @@ -16,15 +16,17 @@ namespace rubinius {
CompiledCode* method_;
Object* extra_;

bool is_block_;
utilities::thread::Condition* waiter_;
int hits_;
bool is_block_;

public:
BackgroundCompileRequest(STATE, CompiledCode* code, Object* extra, bool is_block=false)
BackgroundCompileRequest(STATE, CompiledCode* code, Object* extra, int hits, bool is_block=false)
: method_(code)
, extra_(extra)
, is_block_(is_block)
, waiter_(0)
, hits_(hits)
, is_block_(is_block)
{}

MachineCode* machine_code() {
Expand All @@ -51,6 +53,10 @@ namespace rubinius {
return is_block_;
}

int hits() {
return hits_;
}

void set_waiter(utilities::thread::Condition* cond) {
waiter_ = cond;
}
Expand Down
22 changes: 15 additions & 7 deletions vm/llvm/inline.cpp
Expand Up @@ -30,8 +30,9 @@ namespace rubinius {

bool Inliner::consider_mono() {
if(cache_->classes_seen() != 1) return false;
Class* klass = cache_->get_class(0);
return inline_for_class(klass);
int hits = 0;
Class* klass = cache_->get_class(0, &hits);
return inline_for_class(klass, hits);
}

bool Inliner::consider_poly() {
Expand All @@ -47,11 +48,12 @@ namespace rubinius {
ops_.set_block(current);

for(int i = 0; i < classes_seen; ++i) {
Class* klass = cache_->get_class(i);
int hits = 0;
Class* klass = cache_->get_class(i, &hits);
// Fallback to the next for failure
set_failure(fallback);

if(!inline_for_class(klass)) {
if(!inline_for_class(klass, hits)) {
// If we fail to inline this, emit a send to the method
Value* cache_const = ops_.b().CreateIntToPtr(
ConstantInt::get(ops_.context()->IntPtrTy, (reinterpret_cast<uintptr_t>(cache_))),
Expand Down Expand Up @@ -104,7 +106,7 @@ namespace rubinius {
return true;
}

bool Inliner::inline_for_class(Class* klass) {
bool Inliner::inline_for_class(Class* klass, int hits) {
if(!klass) return false;

Module* defined_in = 0;
Expand Down Expand Up @@ -154,6 +156,8 @@ namespace rubinius {

if(mcode->no_inline_p()) {
decision = cInlineDisabled;
} else if(ops_.info().hits / 10 > hits) {
decision = cTooFewSends;
} else {
decision = policy->inline_p(mcode, opts);
}
Expand Down Expand Up @@ -184,6 +188,9 @@ namespace rubinius {
ops_.llvm_state()->log() << " (block not allowed)";
}
break;
case cTooFewSends:
ops_.llvm_state()->log() << "too few sends: (" << hits << " / " << ops_.info().hits << ")";
break;
default:
ops_.llvm_state()->log() << "no policy";
}
Expand Down Expand Up @@ -220,7 +227,7 @@ namespace rubinius {
policy->increase_size(mcode);
meth->add_inliner(ops_.llvm_state()->shared().om, ops_.root_method_info()->method());

inline_generic_method(klass, defined_in, code, mcode);
inline_generic_method(klass, defined_in, code, mcode, hits);
return true;
} else {
if(ops_.llvm_state()->config().jit_inline_debug) {
Expand Down Expand Up @@ -546,14 +553,15 @@ namespace rubinius {
}

void Inliner::inline_generic_method(Class* klass, Module* defined_in,
CompiledCode* code, MachineCode* mcode) {
CompiledCode* code, MachineCode* mcode, int hits) {
ctx_->enter_inline();

check_recv(klass);

JITMethodInfo info(ctx_, code, mcode);

prime_info(info);
info.hits = hits;

info.self_type = guarded_type_;

Expand Down
4 changes: 2 additions & 2 deletions vm/llvm/inline.hpp
Expand Up @@ -143,11 +143,11 @@ namespace rubinius {

bool consider_poly();

bool inline_for_class(Class* klass);
bool inline_for_class(Class* klass, int hits);

void inline_block(JITInlineBlock* ib, Value* self);

void inline_generic_method(Class* klass, Module* mod, CompiledCode* code, MachineCode* mcode);
void inline_generic_method(Class* klass, Module* mod, CompiledCode* code, MachineCode* mcode, int hits);

bool detect_trivial_method(MachineCode* mcode, CompiledCode* code = 0);

Expand Down
3 changes: 2 additions & 1 deletion vm/llvm/inline_policy.hpp
Expand Up @@ -117,7 +117,8 @@ namespace rubinius {
cInline,
cTooComplex,
cTooBig,
cInlineDisabled
cInlineDisabled,
cTooFewSends
};

class InlinePolicy {
Expand Down
10 changes: 8 additions & 2 deletions vm/llvm/jit_compiler.cpp
Expand Up @@ -143,13 +143,17 @@ namespace jit {

void Compiler::compile(BackgroundCompileRequest* req) {
if(req->is_block()) {
compile_block(req->method(), req->machine_code());
compile_block(req);
} else {
compile_method(req);
}
}

void Compiler::compile_block(CompiledCode* code, MachineCode* mcode) {
void Compiler::compile_block(BackgroundCompileRequest* req) {

CompiledCode* code = req->method();
MachineCode* mcode = req->machine_code();

if(ctx_->llvm_state()->config().jit_inline_debug) {

struct timeval tv;
Expand All @@ -175,6 +179,7 @@ namespace jit {

JITMethodInfo info(ctx_, code, mcode);
info.is_block = true;
info.hits = req->hits();

ctx_->set_root(&info);

Expand Down Expand Up @@ -221,6 +226,7 @@ namespace jit {

JITMethodInfo info(ctx_, code, code->machine_code());
info.is_block = false;
info.hits = req->hits();

if(Class* cls = req->receiver_class()) {
info.set_self_class(cls);
Expand Down
2 changes: 1 addition & 1 deletion vm/llvm/jit_compiler.hpp
Expand Up @@ -60,7 +60,7 @@ namespace jit {

void compile(BackgroundCompileRequest* req);
void compile_method(BackgroundCompileRequest* req);
void compile_block(CompiledCode* code, MachineCode* mcode);
void compile_block(BackgroundCompileRequest* req);
void compile_builder(JITMethodInfo&, rubinius::jit::Builder&);

void* function_pointer();
Expand Down
1 change: 1 addition & 0 deletions vm/llvm/method_info.hpp
Expand Up @@ -49,6 +49,7 @@ namespace rubinius {
InlinePolicy* inline_policy;
llvm::BasicBlock* fin_block;
int called_args;
int hits;
JITStackArgs* stack_args;

JITMethodInfo* root;
Expand Down
17 changes: 9 additions & 8 deletions vm/llvm/state.cpp
Expand Up @@ -361,6 +361,8 @@ namespace rubinius {
req->method()->set_unspecialized(reinterpret_cast<executor>(func), rd);
}

req->machine_code()->clear_compiling();

// assert(req->method()->jit_data());

ls_->end_method_update();
Expand Down Expand Up @@ -560,12 +562,17 @@ namespace rubinius {
return;
}

if(code->machine_code()->compiling_p()) {
return;
}

// Don't do this because it prevents other class from heating
// it up too!
code->machine_code()->call_count = -1;
int hits = code->machine_code()->call_count;
code->machine_code()->set_compiling();

BackgroundCompileRequest* req =
new BackgroundCompileRequest(state, code, placement, is_block);
new BackgroundCompileRequest(state, code, placement, hits, is_block);

queued_methods_++;

Expand Down Expand Up @@ -646,10 +653,6 @@ namespace rubinius {
candidate->print_backtrace(state, 1);
}

if(start && candidate->compiled_code != start) {
start->machine_code()->call_count = 0;
}

if(candidate->compiled_code->machine_code()->call_count <= 1) {
if(!start || start->machine_code()->jitted()) return;
// Ignore it. compile this one.
Expand Down Expand Up @@ -828,8 +831,6 @@ namespace rubinius {

// if(!next || cur->machine_code()->total > SMALL_METHOD_SIZE) return call_frame;

callee->compiled_code->machine_code()->call_count = 0;

callee = call_frame;
call_frame = prev;
}
Expand Down
15 changes: 14 additions & 1 deletion vm/machine_code.hpp
Expand Up @@ -32,7 +32,8 @@ namespace rubinius {
static void** instructions;

enum Flags {
eNoInline = 1 << 0
eNoInline = 1 << 0,
eCompiling = 1 << 1
};

const static int cMaxSpecializations = 3;
Expand Down Expand Up @@ -105,6 +106,18 @@ namespace rubinius {
return execute_status_ == eJITDisable;
}

bool compiling_p() {
return (flags & eCompiling) == eCompiling;
}

void set_compiling() {
flags |= eCompiling;
}

void clear_compiling() {
flags &= ~eCompiling;
}

void set_execute_status(ExecuteStatus s) {
execute_status_ = s;
}
Expand Down

0 comments on commit a787d83

Please sign in to comment.