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 |