Index: src/runtime-profiler.cc |
diff --git a/src/runtime-profiler.cc b/src/runtime-profiler.cc |
index df94ddfa2e687e139addb1bed79cbfe598777b77..b1e640c2ecb42c78215f6f632fb3a9b0aa13105b 100644 |
--- a/src/runtime-profiler.cc |
+++ b/src/runtime-profiler.cc |
@@ -55,6 +55,33 @@ static const int kOSRCodeSizeAllowancePerTickIgnition = |
static const int kMaxSizeEarlyOpt = |
5 * FullCodeGenerator::kCodeSizeMultiplier; |
+#define OPTIMIZATION_REASON_LIST(V) \ |
+ V(DoNotOptimize, "do not optimize") \ |
+ V(HotAndStable, "hot and stable") \ |
+ V(HotEnoughForBaseline, "hot enough for baseline") \ |
+ V(HotWithoutMuchTypeInfo, "not much type info but very hot") \ |
+ V(SmallFunction, "small function") |
+ |
+enum class OptimizationReason : uint8_t { |
+#define OPTIMIZATION_REASON_CONSTANTS(Constant, message) k##Constant, |
+ OPTIMIZATION_REASON_LIST(OPTIMIZATION_REASON_CONSTANTS) |
+#undef OPTIMIZATION_REASON_CONSTANTS |
+}; |
+ |
+char const* OptimizationReasonToString(OptimizationReason reason) { |
+ static char const* reasons[] = { |
+#define OPTIMIZATION_REASON_TEXTS(Constant, message) message, |
+ OPTIMIZATION_REASON_LIST(OPTIMIZATION_REASON_TEXTS) |
+#undef OPTIMIZATION_REASON_TEXTS |
+ }; |
+ size_t const index = static_cast<size_t>(reason); |
+ DCHECK_LT(index, arraysize(reasons)); |
+ return reasons[index]; |
+} |
+ |
+std::ostream& operator<<(std::ostream& os, OptimizationReason reason) { |
+ return os << OptimizationReasonToString(reason); |
+} |
RuntimeProfiler::RuntimeProfiler(Isolate* isolate) |
: isolate_(isolate), |
@@ -80,11 +107,15 @@ static void GetICCounts(JSFunction* function, int* ic_with_type_info_count, |
// Harvest vector-ics as well |
TypeFeedbackVector* vector = function->feedback_vector(); |
- int with = 0, gen = 0; |
+ int with = 0, gen = 0, type_vector_ic_count = 0; |
const bool is_interpreted = |
function->shared()->code()->is_interpreter_trampoline_builtin(); |
- vector->ComputeCounts(&with, &gen, is_interpreted); |
+ vector->ComputeCounts(&with, &gen, &type_vector_ic_count, is_interpreted); |
+ if (is_interpreted) { |
+ DCHECK_EQ(*ic_total_count, 0); |
+ *ic_total_count = type_vector_ic_count; |
+ } |
*ic_with_type_info_count += with; |
*ic_generic_count += gen; |
@@ -116,13 +147,17 @@ static void TraceRecompile(JSFunction* function, const char* reason, |
} |
} |
-void RuntimeProfiler::Optimize(JSFunction* function, const char* reason) { |
- TraceRecompile(function, reason, "optimized"); |
+void RuntimeProfiler::Optimize(JSFunction* function, |
+ OptimizationReason reason) { |
+ DCHECK_NE(reason, OptimizationReason::kDoNotOptimize); |
+ TraceRecompile(function, OptimizationReasonToString(reason), "optimized"); |
function->AttemptConcurrentOptimization(); |
} |
-void RuntimeProfiler::Baseline(JSFunction* function, const char* reason) { |
- TraceRecompile(function, reason, "baseline"); |
+void RuntimeProfiler::Baseline(JSFunction* function, |
+ OptimizationReason reason) { |
+ DCHECK_NE(reason, OptimizationReason::kDoNotOptimize); |
+ TraceRecompile(function, OptimizationReasonToString(reason), "baseline"); |
// TODO(4280): Fix this to check function is compiled for the interpreter |
// once we have a standard way to check that. For now function will only |
@@ -241,9 +276,9 @@ void RuntimeProfiler::MaybeOptimizeFullCodegen(JSFunction* function, |
generic_percentage <= FLAG_generic_ic_threshold) { |
// If this particular function hasn't had any ICs patched for enough |
// ticks, optimize it now. |
- Optimize(function, "hot and stable"); |
+ Optimize(function, OptimizationReason::kHotAndStable); |
} else if (ticks >= kTicksWhenNotEnoughTypeInfo) { |
- Optimize(function, "not much type info but very hot"); |
+ Optimize(function, OptimizationReason::kHotWithoutMuchTypeInfo); |
} else { |
shared_code->set_profiler_ticks(ticks + 1); |
if (FLAG_trace_opt_verbose) { |
@@ -262,7 +297,7 @@ void RuntimeProfiler::MaybeOptimizeFullCodegen(JSFunction* function, |
&generic_percentage); |
if (type_percentage >= FLAG_type_info_threshold && |
generic_percentage <= FLAG_generic_ic_threshold) { |
- Optimize(function, "small function"); |
+ Optimize(function, OptimizationReason::kSmallFunction); |
} else { |
shared_code->set_profiler_ticks(ticks + 1); |
} |
@@ -275,31 +310,16 @@ void RuntimeProfiler::MaybeBaselineIgnition(JSFunction* function, |
JavaScriptFrame* frame) { |
if (function->IsInOptimizationQueue()) return; |
- SharedFunctionInfo* shared = function->shared(); |
- int ticks = shared->profiler_ticks(); |
- |
- // TODO(rmcilroy): Also ensure we only OSR top-level code if it is smaller |
- // than kMaxToplevelSourceSize. |
- |
if (FLAG_always_osr) { |
AttemptOnStackReplacement(frame, AbstractCode::kMaxLoopNestingMarker); |
// Fall through and do a normal baseline compile as well. |
- } else if (!frame->is_optimized() && |
- (function->IsMarkedForBaseline() || |
- function->IsMarkedForOptimization() || |
- function->IsMarkedForConcurrentOptimization() || |
- function->IsOptimized())) { |
- // Attempt OSR if we are still running interpreted code even though the |
- // the function has long been marked or even already been optimized. |
- int64_t allowance = |
- kOSRCodeSizeAllowanceBaseIgnition + |
- static_cast<int64_t>(ticks) * kOSRCodeSizeAllowancePerTickIgnition; |
- if (shared->bytecode_array()->Size() <= allowance) { |
- AttemptOnStackReplacement(frame); |
- } |
+ } else if (MaybeOSRIgnition(function, frame)) { |
return; |
} |
+ SharedFunctionInfo* shared = function->shared(); |
+ int ticks = shared->profiler_ticks(); |
+ |
if (shared->optimization_disabled() && |
shared->disable_optimization_reason() == kOptimizationDisabledForTest) { |
// Don't baseline functions which have been marked by NeverOptimizeFunction |
@@ -308,7 +328,7 @@ void RuntimeProfiler::MaybeBaselineIgnition(JSFunction* function, |
} |
if (ticks >= kProfilerTicksBeforeBaseline) { |
- Baseline(function, "hot enough for baseline"); |
+ Baseline(function, OptimizationReason::kHotEnoughForBaseline); |
} |
} |
@@ -316,31 +336,16 @@ void RuntimeProfiler::MaybeOptimizeIgnition(JSFunction* function, |
JavaScriptFrame* frame) { |
if (function->IsInOptimizationQueue()) return; |
- SharedFunctionInfo* shared = function->shared(); |
- int ticks = shared->profiler_ticks(); |
- |
- // TODO(rmcilroy): Also ensure we only OSR top-level code if it is smaller |
- // than kMaxToplevelSourceSize. |
- |
if (FLAG_always_osr) { |
AttemptOnStackReplacement(frame, AbstractCode::kMaxLoopNestingMarker); |
// Fall through and do a normal optimized compile as well. |
- } else if (!frame->is_optimized() && |
- (function->IsMarkedForBaseline() || |
- function->IsMarkedForOptimization() || |
- function->IsMarkedForConcurrentOptimization() || |
- function->IsOptimized())) { |
- // Attempt OSR if we are still running interpreted code even though the |
- // the function has long been marked or even already been optimized. |
- int64_t allowance = |
- kOSRCodeSizeAllowanceBaseIgnition + |
- static_cast<int64_t>(ticks) * kOSRCodeSizeAllowancePerTickIgnition; |
- if (shared->bytecode_array()->Size() <= allowance) { |
- AttemptOnStackReplacement(frame); |
- } |
+ } else if (MaybeOSRIgnition(function, frame)) { |
return; |
} |
+ SharedFunctionInfo* shared = function->shared(); |
+ int ticks = shared->profiler_ticks(); |
+ |
if (shared->optimization_disabled()) { |
if (shared->deopt_count() >= FLAG_max_opt_count) { |
// If optimization was disabled due to many deoptimizations, |
@@ -352,8 +357,51 @@ void RuntimeProfiler::MaybeOptimizeIgnition(JSFunction* function, |
} |
return; |
} |
+ |
if (function->IsOptimized()) return; |
+ OptimizationReason reason = ShouldOptimizeIgnition(function, frame); |
+ |
+ if (reason != OptimizationReason::kDoNotOptimize) { |
+ Optimize(function, reason); |
+ } |
+} |
+ |
+bool RuntimeProfiler::MaybeOSRIgnition(JSFunction* function, |
+ JavaScriptFrame* frame) { |
+ if (!FLAG_ignition_osr) return false; |
+ |
+ SharedFunctionInfo* shared = function->shared(); |
+ int ticks = shared->profiler_ticks(); |
+ |
+ // TODO(rmcilroy): Also ensure we only OSR top-level code if it is smaller |
+ // than kMaxToplevelSourceSize. |
+ |
+ bool osr_before_baselined = function->IsMarkedForBaseline() && |
+ ShouldOptimizeIgnition(function, frame) != |
+ OptimizationReason::kDoNotOptimize; |
+ if (!frame->is_optimized() && |
+ (osr_before_baselined || function->IsMarkedForOptimization() || |
+ function->IsMarkedForConcurrentOptimization() || |
+ function->IsOptimized())) { |
+ // Attempt OSR if we are still running interpreted code even though the |
+ // the function has long been marked or even already been optimized. |
+ int64_t allowance = |
+ kOSRCodeSizeAllowanceBaseIgnition + |
+ static_cast<int64_t>(ticks) * kOSRCodeSizeAllowancePerTickIgnition; |
+ if (shared->bytecode_array()->Size() <= allowance) { |
+ AttemptOnStackReplacement(frame); |
+ } |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+OptimizationReason RuntimeProfiler::ShouldOptimizeIgnition( |
+ JSFunction* function, JavaScriptFrame* frame) { |
+ SharedFunctionInfo* shared = function->shared(); |
+ int ticks = shared->profiler_ticks(); |
+ |
if (ticks >= kProfilerTicksBeforeOptimization) { |
int typeinfo, generic, total, type_percentage, generic_percentage; |
GetICCounts(function, &typeinfo, &generic, &total, &type_percentage, |
@@ -362,9 +410,9 @@ void RuntimeProfiler::MaybeOptimizeIgnition(JSFunction* function, |
generic_percentage <= FLAG_generic_ic_threshold) { |
// If this particular function hasn't had any ICs patched for enough |
// ticks, optimize it now. |
- Optimize(function, "hot and stable"); |
+ return OptimizationReason::kHotAndStable; |
} else if (ticks >= kTicksWhenNotEnoughTypeInfo) { |
- Optimize(function, "not much type info but very hot"); |
+ return OptimizationReason::kHotWithoutMuchTypeInfo; |
} else { |
if (FLAG_trace_opt_verbose) { |
PrintF("[not yet optimizing "); |
@@ -372,10 +420,12 @@ void RuntimeProfiler::MaybeOptimizeIgnition(JSFunction* function, |
PrintF(", not enough type info: %d/%d (%d%%)]\n", typeinfo, total, |
type_percentage); |
} |
+ return OptimizationReason::kDoNotOptimize; |
} |
} |
// TODO(rmcilroy): Consider whether we should optimize small functions when |
// they are first seen on the stack (e.g., kMaxSizeEarlyOpt). |
+ return OptimizationReason::kDoNotOptimize; |
} |
void RuntimeProfiler::MarkCandidatesForOptimization() { |
@@ -423,6 +473,5 @@ void RuntimeProfiler::MarkCandidatesForOptimization() { |
any_ic_changed_ = false; |
} |
- |
} // namespace internal |
} // namespace v8 |