| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/runtime-profiler.h" | 5 #include "src/runtime-profiler.h" |
| 6 | 6 |
| 7 #include "src/assembler.h" | 7 #include "src/assembler.h" |
| 8 #include "src/ast/scopeinfo.h" | 8 #include "src/ast/scopeinfo.h" |
| 9 #include "src/base/platform/platform.h" | 9 #include "src/base/platform/platform.h" |
| 10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
| 11 #include "src/code-stubs.h" | 11 #include "src/code-stubs.h" |
| 12 #include "src/compilation-cache.h" | 12 #include "src/compilation-cache.h" |
| 13 #include "src/execution.h" | 13 #include "src/execution.h" |
| 14 #include "src/frames-inl.h" | 14 #include "src/frames-inl.h" |
| 15 #include "src/full-codegen/full-codegen.h" | 15 #include "src/full-codegen/full-codegen.h" |
| 16 #include "src/global-handles.h" | 16 #include "src/global-handles.h" |
| 17 | 17 |
| 18 namespace v8 { | 18 namespace v8 { |
| 19 namespace internal { | 19 namespace internal { |
| 20 | 20 |
| 21 | 21 |
| 22 // Number of times a function has to be seen on the stack before it is | 22 // Number of times a function has to be seen on the stack before it is |
| 23 // compiled for baseline. |
| 24 static const int kProfilerTicksBeforeBaseline = 2; |
| 25 // Number of times a function has to be seen on the stack before it is |
| 23 // optimized. | 26 // optimized. |
| 24 static const int kProfilerTicksBeforeOptimization = 2; | 27 static const int kProfilerTicksBeforeOptimization = 2; |
| 25 // If the function optimization was disabled due to high deoptimization count, | 28 // If the function optimization was disabled due to high deoptimization count, |
| 26 // but the function is hot and has been seen on the stack this number of times, | 29 // but the function is hot and has been seen on the stack this number of times, |
| 27 // then we try to reenable optimization for this function. | 30 // then we try to reenable optimization for this function. |
| 28 static const int kProfilerTicksBeforeReenablingOptimization = 250; | 31 static const int kProfilerTicksBeforeReenablingOptimization = 250; |
| 29 // If a function does not have enough type info (according to | 32 // If a function does not have enough type info (according to |
| 30 // FLAG_type_info_threshold), but has seen a huge number of ticks, | 33 // FLAG_type_info_threshold), but has seen a huge number of ticks, |
| 31 // optimize it as it is. | 34 // optimize it as it is. |
| 32 static const int kTicksWhenNotEnoughTypeInfo = 100; | 35 static const int kTicksWhenNotEnoughTypeInfo = 100; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 81 | 84 |
| 82 if (*ic_total_count > 0) { | 85 if (*ic_total_count > 0) { |
| 83 *type_info_percentage = 100 * *ic_with_type_info_count / *ic_total_count; | 86 *type_info_percentage = 100 * *ic_with_type_info_count / *ic_total_count; |
| 84 *generic_percentage = 100 * *ic_generic_count / *ic_total_count; | 87 *generic_percentage = 100 * *ic_generic_count / *ic_total_count; |
| 85 } else { | 88 } else { |
| 86 *type_info_percentage = 100; // Compared against lower bound. | 89 *type_info_percentage = 100; // Compared against lower bound. |
| 87 *generic_percentage = 0; // Compared against upper bound. | 90 *generic_percentage = 0; // Compared against upper bound. |
| 88 } | 91 } |
| 89 } | 92 } |
| 90 | 93 |
| 91 | 94 static void TraceRecompile(JSFunction* function, const char* reason, |
| 92 void RuntimeProfiler::Optimize(JSFunction* function, const char* reason) { | 95 const char* type) { |
| 93 if (FLAG_trace_opt && | 96 if (FLAG_trace_opt && |
| 94 function->shared()->PassesFilter(FLAG_hydrogen_filter)) { | 97 function->shared()->PassesFilter(FLAG_hydrogen_filter)) { |
| 95 PrintF("[marking "); | 98 PrintF("[marking "); |
| 96 function->ShortPrint(); | 99 function->ShortPrint(); |
| 97 PrintF(" for recompilation, reason: %s", reason); | 100 PrintF(" for %s recompilation, reason: %s", type, reason); |
| 98 if (FLAG_type_info_threshold > 0) { | 101 if (FLAG_type_info_threshold > 0) { |
| 99 int typeinfo, generic, total, type_percentage, generic_percentage; | 102 int typeinfo, generic, total, type_percentage, generic_percentage; |
| 100 GetICCounts(function->shared(), &typeinfo, &generic, &total, | 103 GetICCounts(function->shared(), &typeinfo, &generic, &total, |
| 101 &type_percentage, &generic_percentage); | 104 &type_percentage, &generic_percentage); |
| 102 PrintF(", ICs with typeinfo: %d/%d (%d%%)", typeinfo, total, | 105 PrintF(", ICs with typeinfo: %d/%d (%d%%)", typeinfo, total, |
| 103 type_percentage); | 106 type_percentage); |
| 104 PrintF(", generic ICs: %d/%d (%d%%)", generic, total, generic_percentage); | 107 PrintF(", generic ICs: %d/%d (%d%%)", generic, total, generic_percentage); |
| 105 } | 108 } |
| 106 PrintF("]\n"); | 109 PrintF("]\n"); |
| 107 } | 110 } |
| 108 | |
| 109 if (function->shared()->HasBytecodeArray()) { | |
| 110 function->MarkForBaseline(); | |
| 111 } else { | |
| 112 function->AttemptConcurrentOptimization(); | |
| 113 } | |
| 114 } | 111 } |
| 115 | 112 |
| 113 void RuntimeProfiler::Optimize(JSFunction* function, const char* reason) { |
| 114 TraceRecompile(function, reason, "optimized"); |
| 115 |
| 116 // TODO(4280): Fix this to check function is compiled to baseline once we |
| 117 // have a standard way to check that. For now, if baseline code doesn't have |
| 118 // a bytecode array. |
| 119 DCHECK(!function->shared()->HasBytecodeArray()); |
| 120 function->AttemptConcurrentOptimization(); |
| 121 } |
| 122 |
| 123 void RuntimeProfiler::Baseline(JSFunction* function, const char* reason) { |
| 124 TraceRecompile(function, reason, "baseline"); |
| 125 |
| 126 // TODO(4280): Fix this to check function is compiled for the interpreter |
| 127 // once we have a standard way to check that. For now function will only |
| 128 // have a bytecode array if compiled for the interpreter. |
| 129 DCHECK(function->shared()->HasBytecodeArray()); |
| 130 function->MarkForBaseline(); |
| 131 } |
| 116 | 132 |
| 117 void RuntimeProfiler::AttemptOnStackReplacement(JSFunction* function, | 133 void RuntimeProfiler::AttemptOnStackReplacement(JSFunction* function, |
| 118 int loop_nesting_levels) { | 134 int loop_nesting_levels) { |
| 119 SharedFunctionInfo* shared = function->shared(); | 135 SharedFunctionInfo* shared = function->shared(); |
| 120 if (!FLAG_use_osr || function->shared()->IsBuiltin()) { | 136 if (!FLAG_use_osr || function->shared()->IsBuiltin()) { |
| 121 return; | 137 return; |
| 122 } | 138 } |
| 123 | 139 |
| 124 // If the code is not optimizable, don't try OSR. | 140 // If the code is not optimizable, don't try OSR. |
| 125 if (shared->optimization_disabled()) return; | 141 if (shared->optimization_disabled()) return; |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 232 generic_percentage <= FLAG_generic_ic_threshold) { | 248 generic_percentage <= FLAG_generic_ic_threshold) { |
| 233 Optimize(function, "small function"); | 249 Optimize(function, "small function"); |
| 234 } else { | 250 } else { |
| 235 shared_code->set_profiler_ticks(ticks + 1); | 251 shared_code->set_profiler_ticks(ticks + 1); |
| 236 } | 252 } |
| 237 } else { | 253 } else { |
| 238 shared_code->set_profiler_ticks(ticks + 1); | 254 shared_code->set_profiler_ticks(ticks + 1); |
| 239 } | 255 } |
| 240 } | 256 } |
| 241 | 257 |
| 242 void RuntimeProfiler::MaybeOptimizeIgnition(JSFunction* function, | 258 void RuntimeProfiler::MaybeOptimizeIgnition(JSFunction* function) { |
| 243 bool frame_optimized) { | |
| 244 if (function->IsInOptimizationQueue()) return; | 259 if (function->IsInOptimizationQueue()) return; |
| 245 | 260 |
| 246 SharedFunctionInfo* shared = function->shared(); | 261 SharedFunctionInfo* shared = function->shared(); |
| 247 int ticks = shared->profiler_ticks(); | 262 int ticks = shared->profiler_ticks(); |
| 248 | 263 |
| 249 // TODO(rmcilroy): Also ensure we only OSR top-level code if it is smaller | 264 // TODO(rmcilroy): Also ensure we only OSR top-level code if it is smaller |
| 250 // than kMaxToplevelSourceSize. | 265 // than kMaxToplevelSourceSize. |
| 251 // TODO(rmcilroy): Consider whether we should optimize small functions when | 266 // TODO(rmcilroy): Consider whether we should optimize small functions when |
| 252 // they are first seen on the stack (e.g., kMaxSizeEarlyOpt). | 267 // they are first seen on the stack (e.g., kMaxSizeEarlyOpt). |
| 253 | 268 |
| 254 if (!frame_optimized && (function->IsMarkedForBaseline() || | 269 if (function->IsMarkedForBaseline() || function->IsMarkedForOptimization() || |
| 255 function->IsMarkedForOptimization() || | 270 function->IsMarkedForConcurrentOptimization() || |
| 256 function->IsMarkedForConcurrentOptimization() || | 271 function->IsOptimized()) { |
| 257 function->IsOptimized())) { | |
| 258 // TODO(rmcilroy): Support OSR in these cases. | 272 // TODO(rmcilroy): Support OSR in these cases. |
| 259 | |
| 260 return; | 273 return; |
| 261 } | 274 } |
| 262 | 275 |
| 263 // Do not optimize non-optimizable functions. | 276 if (shared->optimization_disabled() && |
| 264 if (shared->optimization_disabled()) { | 277 shared->disable_optimization_reason() == kOptimizationDisabledForTest) { |
| 265 if (shared->deopt_count() >= FLAG_max_opt_count) { | 278 // Don't baseline functions which have been marked by NeverOptimizeFunction |
| 266 // If optimization was disabled due to many deoptimizations, | 279 // in a test. |
| 267 // then check if the function is hot and try to reenable optimization. | |
| 268 if (ticks >= kProfilerTicksBeforeReenablingOptimization) { | |
| 269 shared->set_profiler_ticks(0); | |
| 270 shared->TryReenableOptimization(); | |
| 271 } | |
| 272 } | |
| 273 return; | 280 return; |
| 274 } | 281 } |
| 275 | 282 |
| 276 if (function->IsOptimized()) return; | 283 if (ticks >= kProfilerTicksBeforeBaseline) { |
| 277 | 284 Baseline(function, "hot enough for baseline"); |
| 278 if (ticks >= kProfilerTicksBeforeOptimization) { | |
| 279 int typeinfo, generic, total, type_percentage, generic_percentage; | |
| 280 GetICCounts(shared, &typeinfo, &generic, &total, &type_percentage, | |
| 281 &generic_percentage); | |
| 282 if (type_percentage >= FLAG_type_info_threshold && | |
| 283 generic_percentage <= FLAG_generic_ic_threshold) { | |
| 284 // If this particular function hasn't had any ICs patched for enough | |
| 285 // ticks, optimize it now. | |
| 286 Optimize(function, "hot and stable"); | |
| 287 } else if (ticks >= kTicksWhenNotEnoughTypeInfo) { | |
| 288 Optimize(function, "not much type info but very hot"); | |
| 289 } else { | |
| 290 if (FLAG_trace_opt_verbose) { | |
| 291 PrintF("[not yet optimizing "); | |
| 292 function->PrintName(); | |
| 293 PrintF(", not enough type info: %d/%d (%d%%)]\n", typeinfo, total, | |
| 294 type_percentage); | |
| 295 } | |
| 296 } | |
| 297 } | 285 } |
| 298 } | 286 } |
| 299 | 287 |
| 300 void RuntimeProfiler::MarkCandidatesForOptimization() { | 288 void RuntimeProfiler::MarkCandidatesForOptimization() { |
| 301 HandleScope scope(isolate_); | 289 HandleScope scope(isolate_); |
| 302 | 290 |
| 303 if (!isolate_->use_crankshaft()) return; | 291 if (!isolate_->use_crankshaft()) return; |
| 304 | 292 |
| 305 DisallowHeapAllocation no_gc; | 293 DisallowHeapAllocation no_gc; |
| 306 | 294 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 319 frame->GetFunctions(&functions); | 307 frame->GetFunctions(&functions); |
| 320 for (int i = functions.length(); --i >= 0; ) { | 308 for (int i = functions.length(); --i >= 0; ) { |
| 321 SharedFunctionInfo* shared_function_info = functions[i]->shared(); | 309 SharedFunctionInfo* shared_function_info = functions[i]->shared(); |
| 322 int ticks = shared_function_info->profiler_ticks(); | 310 int ticks = shared_function_info->profiler_ticks(); |
| 323 if (ticks < Smi::kMaxValue) { | 311 if (ticks < Smi::kMaxValue) { |
| 324 shared_function_info->set_profiler_ticks(ticks + 1); | 312 shared_function_info->set_profiler_ticks(ticks + 1); |
| 325 } | 313 } |
| 326 } | 314 } |
| 327 | 315 |
| 328 if (frame->is_interpreted()) { | 316 if (frame->is_interpreted()) { |
| 329 MaybeOptimizeIgnition(function, frame->is_optimized()); | 317 DCHECK(!frame->is_optimized()); |
| 318 MaybeOptimizeIgnition(function); |
| 330 } else { | 319 } else { |
| 331 MaybeOptimizeFullCodegen(function, frame_count, frame->is_optimized()); | 320 MaybeOptimizeFullCodegen(function, frame_count, frame->is_optimized()); |
| 332 } | 321 } |
| 333 } | 322 } |
| 334 any_ic_changed_ = false; | 323 any_ic_changed_ = false; |
| 335 } | 324 } |
| 336 | 325 |
| 337 | 326 |
| 338 } // namespace internal | 327 } // namespace internal |
| 339 } // namespace v8 | 328 } // namespace v8 |
| OLD | NEW |