Collect only optimizable function samples.
Keep track of the ratio between JS and non-JS ticks and use this ratio to adjust the lookup threshold. (Also add support to trace compilation statistics.) Review URL: http://codereview.chromium.org/5633009 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5955 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
a695d0731e
commit
69d6c0bb61
@ -116,13 +116,26 @@ static bool AlwaysFullCompiler() {
|
||||
static void FinishOptimization(Handle<JSFunction> function, int64_t start) {
|
||||
int opt_count = function->shared()->opt_count();
|
||||
function->shared()->set_opt_count(opt_count + 1);
|
||||
if (!FLAG_trace_opt) return;
|
||||
|
||||
double ms = static_cast<double>(OS::Ticks() - start) / 1000;
|
||||
if (FLAG_trace_opt) {
|
||||
PrintF("[optimizing: ");
|
||||
function->PrintName();
|
||||
PrintF(" / %" V8PRIxPTR, reinterpret_cast<intptr_t>(*function));
|
||||
PrintF(" - took %0.3f ms]\n", ms);
|
||||
}
|
||||
if (FLAG_trace_opt_stats) {
|
||||
static double compilation_time = 0.0;
|
||||
static int compiled_functions = 0;
|
||||
static int code_size = 0;
|
||||
|
||||
compilation_time += ms;
|
||||
compiled_functions++;
|
||||
code_size += function->shared()->SourceSize();
|
||||
PrintF("Compiled: %d functions with %d byte source size in %fms.\n",
|
||||
compiled_functions,
|
||||
code_size,
|
||||
compilation_time);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -194,6 +194,7 @@ DEFINE_bool(mask_constants_with_cookie,
|
||||
// codegen.cc
|
||||
DEFINE_bool(lazy, true, "use lazy compilation")
|
||||
DEFINE_bool(trace_opt, false, "trace lazy optimization")
|
||||
DEFINE_bool(trace_opt_stats, false, "trace lazy optimization statistics")
|
||||
DEFINE_bool(opt, true, "use adaptive optimizations")
|
||||
DEFINE_bool(opt_eagerly, false, "be more eager when adaptively optimizing")
|
||||
DEFINE_bool(always_opt, false, "always try to optimize functions")
|
||||
|
@ -68,12 +68,18 @@ class PendingListNode : public Malloced {
|
||||
};
|
||||
|
||||
|
||||
enum SamplerState {
|
||||
IN_NON_JS_STATE = 0,
|
||||
IN_JS_STATE = 1
|
||||
};
|
||||
|
||||
|
||||
// Optimization sampler constants.
|
||||
static const int kSamplerFrameCount = 2;
|
||||
static const int kSamplerFrameWeight[kSamplerFrameCount] = { 2, 1 };
|
||||
static const int kSamplerWindowSize = 16;
|
||||
|
||||
static const int kSamplerTicksDelta = 32;
|
||||
static const int kSamplerTicksBetweenThresholdAdjustment = 32;
|
||||
|
||||
static const int kSamplerThresholdInit = 3;
|
||||
static const int kSamplerThresholdMin = 1;
|
||||
@ -88,6 +94,11 @@ static const int kSizeLimit = 1500;
|
||||
static int sampler_threshold = kSamplerThresholdInit;
|
||||
static int sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit;
|
||||
|
||||
static int sampler_ticks_until_threshold_adjustment =
|
||||
kSamplerTicksBetweenThresholdAdjustment;
|
||||
|
||||
// The ratio of ticks spent in JS code in percent.
|
||||
static Atomic32 js_ratio;
|
||||
|
||||
// The JSFunctions in the sampler window are not GC safe. Old-space
|
||||
// pointers are not cleared during mark-sweep collection and therefore
|
||||
@ -267,29 +278,59 @@ void RuntimeProfiler::OptimizeNow() {
|
||||
it.Advance()) {
|
||||
JavaScriptFrame* frame = it.frame();
|
||||
JSFunction* function = JSFunction::cast(frame->function());
|
||||
int function_size = function->shared()->SourceSize();
|
||||
int threshold_size_factor;
|
||||
if (function_size > kSizeLimit) {
|
||||
threshold_size_factor = sampler_threshold_size_factor;
|
||||
} else {
|
||||
threshold_size_factor = 1;
|
||||
|
||||
// Adjust threshold each time we have processed
|
||||
// a certain number of ticks.
|
||||
if (sampler_ticks_until_threshold_adjustment > 0) {
|
||||
sampler_ticks_until_threshold_adjustment--;
|
||||
if (sampler_ticks_until_threshold_adjustment <= 0) {
|
||||
// If the threshold is not already at the minimum
|
||||
// modify and reset the ticks until next adjustment.
|
||||
if (sampler_threshold > kSamplerThresholdMin) {
|
||||
sampler_threshold -= kSamplerThresholdDelta;
|
||||
sampler_ticks_until_threshold_adjustment =
|
||||
kSamplerTicksBetweenThresholdAdjustment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int threshold = sampler_threshold * threshold_size_factor;
|
||||
samples[count++] = function;
|
||||
if (function->IsMarkedForLazyRecompilation()) {
|
||||
Code* unoptimized = function->shared()->code();
|
||||
int nesting = unoptimized->allow_osr_at_loop_nesting_level();
|
||||
if (nesting == 0) AttemptOnStackReplacement(function);
|
||||
int new_nesting = Min(nesting + 1, Code::kMaxLoopNestingMarker);
|
||||
unoptimized->set_allow_osr_at_loop_nesting_level(new_nesting);
|
||||
} else if (LookupSample(function) >= threshold) {
|
||||
if (IsOptimizable(function)) {
|
||||
}
|
||||
|
||||
// Do not record non-optimizable functions.
|
||||
if (!IsOptimizable(function)) continue;
|
||||
samples[count++] = function;
|
||||
|
||||
int function_size = function->shared()->SourceSize();
|
||||
int threshold_size_factor = (function_size > kSizeLimit)
|
||||
? sampler_threshold_size_factor
|
||||
: 1;
|
||||
|
||||
int threshold = sampler_threshold * threshold_size_factor;
|
||||
int current_js_ratio = NoBarrier_Load(&js_ratio);
|
||||
|
||||
// Adjust threshold depending on the ratio of time spent
|
||||
// in JS code.
|
||||
if (current_js_ratio < 20) {
|
||||
// If we spend less than 20% of the time in JS code,
|
||||
// do not optimize.
|
||||
continue;
|
||||
} else if (current_js_ratio < 75) {
|
||||
// Below 75% of time spent in JS code, only optimize very
|
||||
// frequently used functions.
|
||||
threshold *= 3;
|
||||
}
|
||||
|
||||
if (LookupSample(function) >= threshold) {
|
||||
Optimize(function, false, 0);
|
||||
CompilationCache::MarkForEagerOptimizing(Handle<JSFunction>(function));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the collected functions as samples. It's important not to do
|
||||
// this as part of collecting them because this will interfere with
|
||||
@ -341,6 +382,8 @@ void RuntimeProfiler::Setup() {
|
||||
|
||||
void RuntimeProfiler::Reset() {
|
||||
sampler_threshold = kSamplerThresholdInit;
|
||||
sampler_ticks_until_threshold_adjustment =
|
||||
kSamplerTicksBetweenThresholdAdjustment;
|
||||
sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit;
|
||||
}
|
||||
|
||||
@ -360,6 +403,24 @@ int RuntimeProfiler::SamplerWindowSize() {
|
||||
}
|
||||
|
||||
|
||||
static void AddStateSample(SamplerState current_state) {
|
||||
static const int kStateWindowSize = 128;
|
||||
static SamplerState state_window[kStateWindowSize];
|
||||
static int state_window_position = 0;
|
||||
static int state_counts[2] = { kStateWindowSize, 0 };
|
||||
|
||||
SamplerState old_state = state_window[state_window_position];
|
||||
state_counts[old_state]--;
|
||||
state_window[state_window_position] = current_state;
|
||||
state_counts[current_state]++;
|
||||
ASSERT(IsPowerOf2(kStateWindowSize));
|
||||
state_window_position = (state_window_position + 1) &
|
||||
(kStateWindowSize - 1);
|
||||
NoBarrier_Store(&js_ratio, state_counts[IN_JS_STATE] * 100 /
|
||||
kStateWindowSize);
|
||||
}
|
||||
|
||||
|
||||
bool RuntimeProfilerRateLimiter::SuspendIfNecessary() {
|
||||
static const int kNonJSTicksThreshold = 100;
|
||||
// We suspend the runtime profiler thread when not running
|
||||
@ -369,8 +430,10 @@ bool RuntimeProfilerRateLimiter::SuspendIfNecessary() {
|
||||
!CpuProfiler::is_profiling() &&
|
||||
!(FLAG_prof && FLAG_prof_auto)) {
|
||||
if (Top::IsInJSState()) {
|
||||
AddStateSample(IN_JS_STATE);
|
||||
non_js_ticks_ = 0;
|
||||
} else {
|
||||
AddStateSample(IN_NON_JS_STATE);
|
||||
if (non_js_ticks_ < kNonJSTicksThreshold) {
|
||||
++non_js_ticks_;
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user