OLD | NEW |
---|---|
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
61 private: | 61 private: |
62 void Destroy(); | 62 void Destroy(); |
63 static void WeakCallback(v8::Persistent<v8::Value> object, void* data); | 63 static void WeakCallback(v8::Persistent<v8::Value> object, void* data); |
64 | 64 |
65 PendingListNode* next_; | 65 PendingListNode* next_; |
66 Handle<Object> function_; // Weak handle. | 66 Handle<Object> function_; // Weak handle. |
67 int64_t start_; | 67 int64_t start_; |
68 }; | 68 }; |
69 | 69 |
70 | 70 |
71 enum SamplerState { | |
72 IN_NON_JS_STATE = 0, | |
73 IN_JS_STATE = 1 | |
74 }; | |
75 | |
76 | |
71 // Optimization sampler constants. | 77 // Optimization sampler constants. |
72 static const int kSamplerFrameCount = 2; | 78 static const int kSamplerFrameCount = 2; |
73 static const int kSamplerFrameWeight[kSamplerFrameCount] = { 2, 1 }; | 79 static const int kSamplerFrameWeight[kSamplerFrameCount] = { 2, 1 }; |
74 static const int kSamplerWindowSize = 16; | 80 static const int kSamplerWindowSize = 16; |
75 | 81 |
76 static const int kSamplerTicksDelta = 32; | 82 static const int kSamplerTicksBetweenThresholdAdjustment = 32; |
77 | 83 |
78 static const int kSamplerThresholdInit = 3; | 84 static const int kSamplerThresholdInit = 3; |
79 static const int kSamplerThresholdMin = 1; | 85 static const int kSamplerThresholdMin = 1; |
80 static const int kSamplerThresholdDelta = 1; | 86 static const int kSamplerThresholdDelta = 1; |
81 | 87 |
82 static const int kSamplerThresholdSizeFactorInit = 3; | 88 static const int kSamplerThresholdSizeFactorInit = 3; |
83 static const int kSamplerThresholdSizeFactorMin = 1; | 89 static const int kSamplerThresholdSizeFactorMin = 1; |
84 static const int kSamplerThresholdSizeFactorDelta = 1; | 90 static const int kSamplerThresholdSizeFactorDelta = 1; |
85 | 91 |
86 static const int kSizeLimit = 1500; | 92 static const int kSizeLimit = 1500; |
87 | 93 |
88 static int sampler_threshold = kSamplerThresholdInit; | 94 static int sampler_threshold = kSamplerThresholdInit; |
89 static int sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit; | 95 static int sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit; |
90 | 96 |
97 static int sampler_ticks_until_threshold_adjustment = | |
98 kSamplerTicksBetweenThresholdAdjustment; | |
99 | |
100 // The ratio of ticks spent in JS code in percent. | |
101 static int js_ratio; | |
91 | 102 |
92 // The JSFunctions in the sampler window are not GC safe. Old-space | 103 // The JSFunctions in the sampler window are not GC safe. Old-space |
93 // pointers are not cleared during mark-sweep collection and therefore | 104 // pointers are not cleared during mark-sweep collection and therefore |
94 // the window might contain stale pointers. The window is updated on | 105 // the window might contain stale pointers. The window is updated on |
95 // scavenges and (parts of it) cleared on mark-sweep and | 106 // scavenges and (parts of it) cleared on mark-sweep and |
96 // mark-sweep-compact. | 107 // mark-sweep-compact. |
97 static Object* sampler_window[kSamplerWindowSize] = { NULL, }; | 108 static Object* sampler_window[kSamplerWindowSize] = { NULL, }; |
98 static int sampler_window_position = 0; | 109 static int sampler_window_position = 0; |
99 static int sampler_window_weight[kSamplerWindowSize] = { 0, }; | 110 static int sampler_window_weight[kSamplerWindowSize] = { 0, }; |
100 | 111 |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
260 // Run through the JavaScript frames and collect them. If we already | 271 // Run through the JavaScript frames and collect them. If we already |
261 // have a sample of the function, we mark it for optimizations | 272 // have a sample of the function, we mark it for optimizations |
262 // (eagerly or lazily). | 273 // (eagerly or lazily). |
263 JSFunction* samples[kSamplerFrameCount]; | 274 JSFunction* samples[kSamplerFrameCount]; |
264 int count = 0; | 275 int count = 0; |
265 for (JavaScriptFrameIterator it; | 276 for (JavaScriptFrameIterator it; |
266 count < kSamplerFrameCount && !it.done(); | 277 count < kSamplerFrameCount && !it.done(); |
267 it.Advance()) { | 278 it.Advance()) { |
268 JavaScriptFrame* frame = it.frame(); | 279 JavaScriptFrame* frame = it.frame(); |
269 JSFunction* function = JSFunction::cast(frame->function()); | 280 JSFunction* function = JSFunction::cast(frame->function()); |
270 int function_size = function->shared()->SourceSize(); | 281 |
271 int threshold_size_factor; | 282 // Adjust threshold each time we have processed |
272 if (function_size > kSizeLimit) { | 283 // a certain number of ticks. |
273 threshold_size_factor = sampler_threshold_size_factor; | 284 if (sampler_ticks_until_threshold_adjustment > 0) { |
274 } else { | 285 sampler_ticks_until_threshold_adjustment--; |
275 threshold_size_factor = 1; | 286 if (sampler_ticks_until_threshold_adjustment == 0) { |
287 // If the threshold is not already at the minimum | |
288 // modify and reset the ticks until next adjustment. | |
289 if (sampler_threshold > kSamplerThresholdMin) { | |
290 sampler_threshold -= kSamplerThresholdDelta; | |
291 sampler_ticks_until_threshold_adjustment = | |
292 kSamplerTicksBetweenThresholdAdjustment; | |
293 } | |
294 } | |
276 } | 295 } |
277 | 296 |
297 // Do not record non-optimizable functions. If the function | |
298 // is not marked for recompilation, move on to the next frame. | |
299 if (!IsOptimizable(function)) { | |
300 if (!function->IsMarkedForLazyRecompilation()) continue; | |
301 } else { | |
302 samples[count++] = function; | |
303 } | |
304 | |
305 int function_size = function->shared()->SourceSize(); | |
306 int threshold_size_factor = (function_size > kSizeLimit) | |
307 ? sampler_threshold_size_factor | |
308 : 1; | |
309 | |
278 int threshold = sampler_threshold * threshold_size_factor; | 310 int threshold = sampler_threshold * threshold_size_factor; |
279 samples[count++] = function; | 311 |
312 // Adjust threshold depending on the ratio of time spent | |
313 // in JS code. | |
314 if (js_ratio < 20) { | |
315 // If we spent less than 20% of the time in JS, code | |
Kasper Lund
2010/12/09 11:51:51
spent => spend
Karl Klose
2010/12/09 12:49:32
Done.
| |
316 // do not optimize. | |
317 if (!function->IsMarkedForLazyRecompilation()) continue; | |
318 } else if (js_ratio < 75) { | |
319 // Below 75% of time spent in JS code, only optimize very | |
320 // frequently used functions. | |
321 threshold *= 3; | |
322 } | |
323 | |
280 if (function->IsMarkedForLazyRecompilation()) { | 324 if (function->IsMarkedForLazyRecompilation()) { |
Kasper Lund
2010/12/09 11:51:51
Can't you just move this code up to the !IsOptimiz
Karl Klose
2010/12/09 12:49:32
Done.
| |
281 Code* unoptimized = function->shared()->code(); | 325 Code* unoptimized = function->shared()->code(); |
282 int nesting = unoptimized->allow_osr_at_loop_nesting_level(); | 326 int nesting = unoptimized->allow_osr_at_loop_nesting_level(); |
283 if (nesting == 0) AttemptOnStackReplacement(function); | 327 if (nesting == 0) AttemptOnStackReplacement(function); |
284 int new_nesting = Min(nesting + 1, Code::kMaxLoopNestingMarker); | 328 int new_nesting = Min(nesting + 1, Code::kMaxLoopNestingMarker); |
285 unoptimized->set_allow_osr_at_loop_nesting_level(new_nesting); | 329 unoptimized->set_allow_osr_at_loop_nesting_level(new_nesting); |
286 } else if (LookupSample(function) >= threshold) { | 330 } else if (LookupSample(function) >= threshold) { |
287 if (IsOptimizable(function)) { | 331 Optimize(function, false, 0); |
288 Optimize(function, false, 0); | 332 CompilationCache::MarkForEagerOptimizing(Handle<JSFunction>(function)); |
289 CompilationCache::MarkForEagerOptimizing(Handle<JSFunction>(function)); | |
290 } | |
291 } | 333 } |
292 } | 334 } |
293 | 335 |
294 // Add the collected functions as samples. It's important not to do | 336 // Add the collected functions as samples. It's important not to do |
295 // this as part of collecting them because this will interfere with | 337 // this as part of collecting them because this will interfere with |
296 // the sample lookup in case of recursive functions. | 338 // the sample lookup in case of recursive functions. |
297 for (int i = 0; i < count; i++) { | 339 for (int i = 0; i < count; i++) { |
298 AddSample(samples[i], kSamplerFrameWeight[i]); | 340 AddSample(samples[i], kSamplerFrameWeight[i]); |
299 } | 341 } |
300 } | 342 } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
334 void RuntimeProfiler::Setup() { | 376 void RuntimeProfiler::Setup() { |
335 ClearSampleBuffer(); | 377 ClearSampleBuffer(); |
336 // If the ticker hasn't already started, make sure to do so to get | 378 // If the ticker hasn't already started, make sure to do so to get |
337 // the ticks for the runtime profiler. | 379 // the ticks for the runtime profiler. |
338 if (IsEnabled()) Logger::EnsureTickerStarted(); | 380 if (IsEnabled()) Logger::EnsureTickerStarted(); |
339 } | 381 } |
340 | 382 |
341 | 383 |
342 void RuntimeProfiler::Reset() { | 384 void RuntimeProfiler::Reset() { |
343 sampler_threshold = kSamplerThresholdInit; | 385 sampler_threshold = kSamplerThresholdInit; |
386 sampler_ticks_until_threshold_adjustment = | |
387 kSamplerTicksBetweenThresholdAdjustment; | |
344 sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit; | 388 sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit; |
345 } | 389 } |
346 | 390 |
347 | 391 |
348 void RuntimeProfiler::TearDown() { | 392 void RuntimeProfiler::TearDown() { |
349 // Nothing to do. | 393 // Nothing to do. |
350 } | 394 } |
351 | 395 |
352 | 396 |
353 Object** RuntimeProfiler::SamplerWindowAddress() { | 397 Object** RuntimeProfiler::SamplerWindowAddress() { |
354 return sampler_window; | 398 return sampler_window; |
355 } | 399 } |
356 | 400 |
357 | 401 |
358 int RuntimeProfiler::SamplerWindowSize() { | 402 int RuntimeProfiler::SamplerWindowSize() { |
359 return kSamplerWindowSize; | 403 return kSamplerWindowSize; |
360 } | 404 } |
361 | 405 |
362 | 406 |
407 static void AddStateSample(SamplerState current_state) { | |
408 static const int kStateWindowSize = 128; | |
409 static SamplerState state_window[kStateWindowSize]; | |
410 static int state_window_position = 0; | |
411 static int state_counts[2] = { kStateWindowSize, 0 }; | |
412 | |
413 SamplerState old_state = state_window[state_window_position]; | |
414 state_counts[old_state]--; | |
415 state_window[state_window_position] = current_state; | |
416 state_counts[current_state]++; | |
417 ASSERT(IsPowerOf2(kStateWindowSize)); | |
418 state_window_position = (state_window_position + 1) & | |
419 (kStateWindowSize - 1); | |
420 js_ratio = state_counts[IN_JS_STATE]*100 / kStateWindowSize; | |
Kasper Lund
2010/12/09 11:51:51
Spaces around *. Consider changing the type of js_
Karl Klose
2010/12/09 12:49:32
Done.
| |
421 } | |
422 | |
423 | |
363 bool RuntimeProfilerRateLimiter::SuspendIfNecessary() { | 424 bool RuntimeProfilerRateLimiter::SuspendIfNecessary() { |
364 static const int kNonJSTicksThreshold = 100; | 425 static const int kNonJSTicksThreshold = 100; |
365 // We suspend the runtime profiler thread when not running | 426 // We suspend the runtime profiler thread when not running |
366 // JavaScript. If the CPU profiler is active we must not do this | 427 // JavaScript. If the CPU profiler is active we must not do this |
367 // because it samples both JavaScript and C++ code. | 428 // because it samples both JavaScript and C++ code. |
368 if (RuntimeProfiler::IsEnabled() && | 429 if (RuntimeProfiler::IsEnabled() && |
369 !CpuProfiler::is_profiling() && | 430 !CpuProfiler::is_profiling() && |
370 !(FLAG_prof && FLAG_prof_auto)) { | 431 !(FLAG_prof && FLAG_prof_auto)) { |
371 if (Top::IsInJSState()) { | 432 if (Top::IsInJSState()) { |
433 AddStateSample(IN_JS_STATE); | |
372 non_js_ticks_ = 0; | 434 non_js_ticks_ = 0; |
373 } else { | 435 } else { |
436 AddStateSample(IN_NON_JS_STATE); | |
374 if (non_js_ticks_ < kNonJSTicksThreshold) { | 437 if (non_js_ticks_ < kNonJSTicksThreshold) { |
375 ++non_js_ticks_; | 438 ++non_js_ticks_; |
376 } else { | 439 } else { |
377 if (Top::WaitForJSState()) return true; | 440 if (Top::WaitForJSState()) return true; |
378 } | 441 } |
379 } | 442 } |
380 } | 443 } |
381 return false; | 444 return false; |
382 } | 445 } |
383 | 446 |
384 | 447 |
385 } } // namespace v8::internal | 448 } } // namespace v8::internal |
OLD | NEW |