Index: src/runtime-profiler.cc |
=================================================================== |
--- src/runtime-profiler.cc (revision 5952) |
+++ src/runtime-profiler.cc (working copy) |
@@ -68,12 +68,18 @@ |
}; |
+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,7 +94,12 @@ |
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 |
// the window might contain stale pointers. The window is updated on |
@@ -267,28 +278,58 @@ |
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)) { |
- Optimize(function, false, 0); |
- CompilationCache::MarkForEagerOptimizing(Handle<JSFunction>(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 |
@@ -341,6 +382,8 @@ |
void RuntimeProfiler::Reset() { |
sampler_threshold = kSamplerThresholdInit; |
+ sampler_ticks_until_threshold_adjustment = |
+ kSamplerTicksBetweenThresholdAdjustment; |
sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit; |
} |
@@ -360,6 +403,24 @@ |
} |
+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 @@ |
!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 { |