8203883: Remove State from InvocationCounters

Reviewed-by: redestad, thartmann
This commit is contained in:
Nils Eliasson 2020-02-12 20:53:48 +01:00
parent b4b8ead78b
commit 18c01206d0
8 changed files with 80 additions and 197 deletions

View File

@ -295,8 +295,8 @@ void SimpleCompPolicy::reset_counter_for_invocation_event(const methodHandle& m)
// Set carry bit and reduce counter's value to min(count, CompileThreshold/2).
MethodCounters* mcs = m->method_counters();
assert(mcs != NULL, "MethodCounters cannot be NULL for profiling");
mcs->invocation_counter()->set_carry();
mcs->backedge_counter()->set_carry();
mcs->invocation_counter()->set_carry_and_reduce();
mcs->backedge_counter()->set_carry_and_reduce();
assert(!m->was_never_executed(), "don't reset to 0 -- could be mistaken for never-executed");
}
@ -312,9 +312,9 @@ void SimpleCompPolicy::reset_counter_for_back_branch_event(const methodHandle& m
// Don't set invocation_counter's value too low otherwise the method will
// look like immature (ic < ~5300) which prevents the inlining based on
// the type profiling.
i->set(i->state(), CompileThreshold);
i->set(CompileThreshold);
// Don't reset counter too low - it is used to check if OSR method is ready.
b->set(b->state(), CompileThreshold / 2);
b->set(CompileThreshold / 2);
}
// Called at the end of the safepoint
@ -340,7 +340,7 @@ void SimpleCompPolicy::reprofile(ScopeDesc* trap_scope, bool is_osr) {
c = mcs->invocation_counter();
if (is_osr) {
// It was an OSR method, so bump the count higher.
c->set(c->state(), CompileThreshold);
c->set(CompileThreshold);
} else {
c->reset();
}
@ -358,14 +358,6 @@ void SimpleCompPolicy::delay_compilation(Method* method) {
}
}
void SimpleCompPolicy::disable_compilation(Method* method) {
MethodCounters* mcs = method->method_counters();
if (mcs != NULL) {
mcs->invocation_counter()->set_state(InvocationCounter::wait_for_nothing);
mcs->backedge_counter()->set_state(InvocationCounter::wait_for_nothing);
}
}
CompileTask* SimpleCompPolicy::select_task(CompileQueue* compile_queue) {
return select_task_helper(compile_queue);
}

View File

@ -71,9 +71,6 @@ public:
// delay_compilation(method) can be called by any component of the runtime to notify the policy
// that it's recommended to delay the compilation of this method.
virtual void delay_compilation(Method* method) = 0;
// disable_compilation() is called whenever the runtime decides to disable compilation of the
// specified method.
virtual void disable_compilation(Method* method) = 0;
// Select task is called by CompileBroker. The queue is guaranteed to have at least one
// element and is locked. The function should select one and return it.
virtual CompileTask* select_task(CompileQueue* compile_queue) = 0;
@ -102,7 +99,6 @@ class SimpleCompPolicy : public CompilationPolicy {
virtual void do_safepoint_work();
virtual void reprofile(ScopeDesc* trap_scope, bool is_osr);
virtual void delay_compilation(Method* method);
virtual void disable_compilation(Method* method);
virtual bool is_mature(Method* method);
virtual void initialize();
virtual CompileTask* select_task(CompileQueue* compile_queue);

View File

@ -379,23 +379,17 @@ CompLevel TieredThresholdPolicy::initial_compile_level(const methodHandle& metho
return limit_level(initial_compile_level_helper(method));
}
void TieredThresholdPolicy::set_carry_if_necessary(InvocationCounter *counter) {
if (!counter->carry() && counter->count() > InvocationCounter::count_limit / 2) {
counter->set_carry_flag();
}
}
// Set carry flags on the counters if necessary
void TieredThresholdPolicy::handle_counter_overflow(Method* method) {
MethodCounters *mcs = method->method_counters();
if (mcs != NULL) {
set_carry_if_necessary(mcs->invocation_counter());
set_carry_if_necessary(mcs->backedge_counter());
mcs->invocation_counter()->set_carry_on_overflow();
mcs->backedge_counter()->set_carry_on_overflow();
}
MethodData* mdo = method->method_data();
if (mdo != NULL) {
set_carry_if_necessary(mdo->invocation_counter());
set_carry_if_necessary(mdo->backedge_counter());
mdo->invocation_counter()->set_carry_on_overflow();
mdo->backedge_counter()->set_carry_on_overflow();
}
}

View File

@ -62,9 +62,6 @@ void AbstractInterpreter::initialize() {
if (CountBytecodes || TraceBytecodes || StopInterpreterAt) BytecodeCounter::reset();
if (PrintBytecodeHistogram) BytecodeHistogram::reset();
if (PrintBytecodePairHistogram) BytecodePairHistogram::reset();
InvocationCounter::reinitialize();
}
void AbstractInterpreter::print() {

View File

@ -24,119 +24,69 @@
#include "precompiled.hpp"
#include "interpreter/invocationCounter.hpp"
#include "runtime/frame.hpp"
#include "runtime/handles.inline.hpp"
// Implementation of InvocationCounter
void InvocationCounter::init() {
_counter = 0; // reset all the bits, including the sticky carry
reset();
}
void InvocationCounter::reset() {
// Only reset the state and don't make the method look like it's never
// been executed
set_state(wait_for_compile);
void InvocationCounter::set(uint count, uint flag) {
_counter = (count << number_of_noncount_bits) | (flag & carry_mask);
}
void InvocationCounter::set_carry() {
set_carry_flag();
void InvocationCounter::set(uint count) {
uint carry = (_counter & carry_mask); // the carry bit is sticky
_counter = (count << number_of_noncount_bits) | carry;
}
void InvocationCounter::update(uint new_count) {
// Don't make the method look like it's never been executed
uint counter = raw_counter();
uint c = extract_count(counter);
uint f = extract_carry(counter);
// prevent from going to zero, to distinguish from never-executed methods
if (c > 0 && new_count == 0) new_count = 1;
set(new_count, f);
}
void InvocationCounter::set_carry_and_reduce() {
uint counter = raw_counter();
// The carry bit now indicates that this counter had achieved a very
// large value. Now reduce the value, so that the method can be
// executed many more times before re-entering the VM.
int old_count = count();
int new_count = MIN2(old_count, (int) (CompileThreshold / 2));
uint old_count = extract_count(counter);
uint new_count = MIN2(old_count, (uint)(CompileThreshold / 2));
// prevent from going to zero, to distinguish from never-executed methods
if (new_count == 0) new_count = 1;
if (old_count != new_count) set(state(), new_count);
if (old_count != new_count) set(new_count, carry_mask);
}
void InvocationCounter::set_state(State state) {
assert(0 <= state && state < number_of_states, "illegal state");
int init = _init[state];
// prevent from going to zero, to distinguish from never-executed methods
if (init == 0 && count() > 0) init = 1;
int carry = (_counter & carry_mask); // the carry bit is sticky
_counter = (init << number_of_noncount_bits) | carry | state;
void InvocationCounter::set_carry_on_overflow() {
if (!carry() && count() > InvocationCounter::count_limit / 2) {
set_carry();
}
}
void InvocationCounter::reset() {
update(0);
}
void InvocationCounter::decay() {
update(count() >> 1);
}
void InvocationCounter::print() {
tty->print_cr("invocation count: up = %d, limit = %d, carry = %s, state = %s",
count(), limit(),
carry() ? "true" : "false",
state_as_string(state()));
uint counter = raw_counter();
tty->print_cr("invocation count: up = %d, limit = %d, carry = %s",
extract_count(counter), limit(),
extract_carry(counter) ? "true" : "false");
}
void InvocationCounter::print_short() {
tty->print(" [%d%s;%s]", count(), carry()?"+carry":"", state_as_short_string(state()));
}
// Initialization
int InvocationCounter::_init [InvocationCounter::number_of_states];
InvocationCounter::Action InvocationCounter::_action[InvocationCounter::number_of_states];
#ifdef CC_INTERP
int InvocationCounter::InterpreterInvocationLimit;
int InvocationCounter::InterpreterBackwardBranchLimit;
#endif
const char* InvocationCounter::state_as_string(State state) {
switch (state) {
case wait_for_nothing : return "wait_for_nothing";
case wait_for_compile : return "wait_for_compile";
default:
ShouldNotReachHere();
return NULL;
}
}
const char* InvocationCounter::state_as_short_string(State state) {
switch (state) {
case wait_for_nothing : return "not comp.";
case wait_for_compile : return "compileable";
default:
ShouldNotReachHere();
return NULL;
}
}
static address do_nothing(const methodHandle& method, TRAPS) {
// dummy action for inactive invocation counters
MethodCounters* mcs = method->method_counters();
assert(mcs != NULL, "");
mcs->invocation_counter()->set_carry();
mcs->invocation_counter()->set_state(InvocationCounter::wait_for_nothing);
return NULL;
}
static address do_decay(const methodHandle& method, TRAPS) {
// decay invocation counters so compilation gets delayed
MethodCounters* mcs = method->method_counters();
assert(mcs != NULL, "");
mcs->invocation_counter()->decay();
return NULL;
}
void InvocationCounter::def(State state, int init, Action action) {
assert(0 <= state && state < number_of_states, "illegal state");
assert(0 <= init && init < count_limit, "initial value out of range");
_init [state] = init;
_action[state] = action;
}
void InvocationCounter::reinitialize() {
// define states
guarantee((int)number_of_states <= (int)state_limit, "adjust number_of_state_bits");
def(wait_for_nothing, 0, do_nothing);
def(wait_for_compile, 0, do_decay);
void invocationCounter_init() {
#ifdef CC_INTERP
InterpreterInvocationLimit = CompileThreshold << number_of_noncount_bits;
@ -153,7 +103,3 @@ void InvocationCounter::reinitialize() {
assert(0 <= InterpreterBackwardBranchLimit, "OSR threshold should be non-negative");
#endif
}
void invocationCounter_init() {
InvocationCounter::reinitialize();
}

View File

@ -29,36 +29,26 @@
#include "utilities/exceptions.hpp"
// InvocationCounters are used to trigger actions when a limit (threshold) is reached.
// For different states, different limits and actions can be defined in the initialization
// routine of InvocationCounters.
//
// Implementation notes: For space reasons, state & counter are both encoded in one word,
// The state is encoded using some of the least significant bits, the counter is using the
// more significant bits. The counter is incremented before a method is activated and an
// The counter is incremented before a method is activated and an
// action is triggered when count() > limit().
class InvocationCounter {
friend class VMStructs;
friend class JVMCIVMStructs;
friend class ciReplay;
private: // bit no: |31 3| 2 | 1 0 |
unsigned int _counter; // format: [count|carry|state]
private: // bit no: |31 1| 0 |
uint _counter; // format: [count|carry|
enum PrivateConstants {
number_of_state_bits = 2,
number_of_carry_bits = 1,
number_of_noncount_bits = number_of_state_bits + number_of_carry_bits,
state_limit = nth_bit(number_of_state_bits),
count_grain = nth_bit(number_of_state_bits + number_of_carry_bits),
carry_mask = right_n_bits(number_of_carry_bits) << number_of_state_bits,
state_mask = right_n_bits(number_of_state_bits),
status_mask = right_n_bits(number_of_state_bits + number_of_carry_bits),
count_mask = ((int)(-1) ^ status_mask)
number_of_carry_bits = 1,
number_of_noncount_bits = number_of_carry_bits,
count_grain = nth_bit(number_of_carry_bits),
carry_mask = right_n_bits(number_of_carry_bits),
count_mask = ((int)(-1) ^ carry_mask)
};
public:
typedef address (*Action)(const methodHandle& method, TRAPS);
enum PublicConstants {
count_increment = count_grain, // use this value to increment the 32bit _counter word
count_mask_value = count_mask, // use this value to mask the backedge counter
@ -67,30 +57,31 @@ class InvocationCounter {
count_limit = nth_bit(number_of_count_bits - 1)
};
enum State {
wait_for_nothing, // do nothing when count() > limit()
wait_for_compile, // introduce nmethod when count() > limit()
number_of_states // must be <= state_limit
};
// Manipulation
void reset(); // sets state to wait state
void init(); // sets state into original state
void set_state(State state); // sets state and initializes counter correspondingly
inline void set(State state, int count); // sets state and counter
inline void decay(); // decay counter (divide by two)
void set_carry(); // set the sticky carry bit
void set_carry_flag() { _counter |= carry_mask; }
int raw_counter() { return _counter; }
void reset();
void init();
void decay(); // decay counter (divide by two)
void set_carry_and_reduce(); // set the sticky carry bit
void set_carry_on_overflow();
void set(uint count);
void increment() { _counter += count_increment; }
// Accessors
State state() const { return (State)(_counter & state_mask); }
bool carry() const { return (_counter & carry_mask) != 0; }
int limit() const { return CompileThreshold; }
Action action() const { return _action[state()]; }
int count() const { return _counter >> number_of_noncount_bits; }
bool carry() const { return (_counter & carry_mask) != 0; }
uint count() const { return _counter >> number_of_noncount_bits; }
uint limit() const { return CompileThreshold; }
uint raw_counter() const { return _counter; }
void print();
private:
void set_carry() { _counter |= carry_mask; }
uint extract_carry(uint raw) const { return (raw & carry_mask); }
uint extract_count(uint raw) const { return raw >> number_of_noncount_bits; }
void update(uint new_count);
void set(uint count, uint carry);
public:
#ifdef CC_INTERP
static int InterpreterInvocationLimit; // CompileThreshold scaled for interpreter use
static int InterpreterBackwardBranchLimit; // A separate threshold for on stack replacement
@ -100,47 +91,16 @@ class InvocationCounter {
// Checks sum of invocation_counter and backedge_counter as the template interpreter does.
bool reached_InvocationLimit(InvocationCounter *back_edge_count) const {
return (_counter & count_mask) + (back_edge_count->_counter & count_mask) >=
(unsigned int) InterpreterInvocationLimit;
(uint) InterpreterInvocationLimit;
}
bool reached_BackwardBranchLimit(InvocationCounter *back_edge_count) const {
return (_counter & count_mask) + (back_edge_count->_counter & count_mask) >=
(unsigned int) InterpreterBackwardBranchLimit;
(uint) InterpreterBackwardBranchLimit;
}
#endif // CC_INTERP
void increment() { _counter += count_increment; }
// Printing
void print();
void print_short();
// Miscellaneous
static ByteSize counter_offset() { return byte_offset_of(InvocationCounter, _counter); }
static void reinitialize();
private:
static int _init [number_of_states]; // the counter limits
static Action _action[number_of_states]; // the actions
static void def(State state, int init, Action action);
static const char* state_as_string(State state);
static const char* state_as_short_string(State state);
};
inline void InvocationCounter::set(State state, int count) {
assert(0 <= state && state < number_of_states, "illegal state");
int carry = (_counter & carry_mask); // the carry bit is sticky
_counter = (count << number_of_noncount_bits) | carry | state;
}
inline void InvocationCounter::decay() {
int c = count();
int new_count = c >> 1;
// prevent from going to zero, to distinguish from never-executed methods
if (c > 0 && new_count == 0) new_count = 1;
set(state(), new_count);
}
#endif // SHARE_INTERPRETER_INVOCATIONCOUNTER_HPP

View File

@ -1001,7 +1001,6 @@ void Method::set_not_compilable(const char* reason, int comp_level, bool report)
if (is_c2_compile(comp_level))
set_not_c2_compilable();
}
CompilationPolicy::policy()->disable_compilation(this);
assert(!CompilationPolicy::can_be_compiled(methodHandle(Thread::current(), this), comp_level), "sanity check");
}
@ -1028,7 +1027,6 @@ void Method::set_not_osr_compilable(const char* reason, int comp_level, bool rep
if (is_c2_compile(comp_level))
set_not_c2_osr_compilable();
}
CompilationPolicy::policy()->disable_compilation(this);
assert(!CompilationPolicy::can_be_osr_compiled(methodHandle(Thread::current(), this), comp_level), "sanity check");
}

View File

@ -1130,8 +1130,8 @@ WB_ENTRY(void, WB_MarkMethodProfiled(JNIEnv* env, jobject o, jobject method))
InvocationCounter* icnt = mdo->invocation_counter();
InvocationCounter* bcnt = mdo->backedge_counter();
// set i-counter according to TieredThresholdPolicy::is_method_profiled
icnt->set(InvocationCounter::wait_for_compile, Tier4MinInvocationThreshold);
bcnt->set(InvocationCounter::wait_for_compile, Tier4CompileThreshold);
icnt->set(Tier4MinInvocationThreshold);
bcnt->set(Tier4CompileThreshold);
WB_END
WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method))