| 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 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 // Optimization sampler constants. | 71 // Optimization sampler constants. |
| 72 static const int kSamplerFrameCount = 2; | 72 static const int kSamplerFrameCount = 2; |
| 73 static const int kSamplerFrameWeight[kSamplerFrameCount] = { 2, 1 }; | 73 static const int kSamplerFrameWeight[kSamplerFrameCount] = { 2, 1 }; |
| 74 | 74 |
| 75 static const int kSamplerTicksDelta = 32; | 75 static const int kSamplerTicksBetweenThresholdAdjustment = 32; |
| 76 | 76 |
| 77 static const int kSamplerThresholdInit = 3; | 77 static const int kSamplerThresholdInit = 3; |
| 78 static const int kSamplerThresholdMin = 1; | 78 static const int kSamplerThresholdMin = 1; |
| 79 static const int kSamplerThresholdDelta = 1; | 79 static const int kSamplerThresholdDelta = 1; |
| 80 | 80 |
| 81 static const int kSamplerThresholdSizeFactorInit = 3; | 81 static const int kSamplerThresholdSizeFactorInit = 3; |
| 82 static const int kSamplerThresholdSizeFactorMin = 1; | 82 static const int kSamplerThresholdSizeFactorMin = 1; |
| 83 static const int kSamplerThresholdSizeFactorDelta = 1; | 83 static const int kSamplerThresholdSizeFactorDelta = 1; |
| 84 | 84 |
| 85 static const int kSizeLimit = 1500; | 85 static const int kSizeLimit = 1500; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 108 | 108 |
| 109 static bool IsOptimizable(JSFunction* function) { | 109 static bool IsOptimizable(JSFunction* function) { |
| 110 Code* code = function->code(); | 110 Code* code = function->code(); |
| 111 return code->kind() == Code::FUNCTION && code->optimizable(); | 111 return code->kind() == Code::FUNCTION && code->optimizable(); |
| 112 } | 112 } |
| 113 | 113 |
| 114 | 114 |
| 115 Atomic32 RuntimeProfiler::state_ = 0; | 115 Atomic32 RuntimeProfiler::state_ = 0; |
| 116 // TODO(isolates): Create the semaphore lazily and clean it up when no | 116 // TODO(isolates): Create the semaphore lazily and clean it up when no |
| 117 // longer required. | 117 // longer required. |
| 118 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 118 Semaphore* RuntimeProfiler::semaphore_ = OS::CreateSemaphore(0); | 119 Semaphore* RuntimeProfiler::semaphore_ = OS::CreateSemaphore(0); |
| 120 #endif |
| 119 | 121 |
| 120 | 122 |
| 121 RuntimeProfiler::RuntimeProfiler(Isolate* isolate) | 123 RuntimeProfiler::RuntimeProfiler(Isolate* isolate) |
| 122 : isolate_(isolate), | 124 : isolate_(isolate), |
| 123 sampler_threshold_(kSamplerThresholdInit), | 125 sampler_threshold_(kSamplerThresholdInit), |
| 124 sampler_threshold_size_factor_(kSamplerThresholdSizeFactorInit), | 126 sampler_threshold_size_factor_(kSamplerThresholdSizeFactorInit), |
| 127 sampler_ticks_until_threshold_adjustment_( |
| 128 kSamplerTicksBetweenThresholdAdjustment), |
| 129 js_ratio_(0), |
| 125 sampler_window_position_(0), | 130 sampler_window_position_(0), |
| 126 optimize_soon_list_(NULL) { | 131 optimize_soon_list_(NULL), |
| 132 state_window_position_(0) { |
| 133 state_counts_[0] = kStateWindowSize; |
| 134 state_counts_[1] = 0; |
| 135 memset(state_window_, 0, sizeof(state_window_)); |
| 127 ClearSampleBuffer(); | 136 ClearSampleBuffer(); |
| 128 } | 137 } |
| 129 | 138 |
| 130 | 139 |
| 131 bool RuntimeProfiler::IsEnabled() { | 140 bool RuntimeProfiler::IsEnabled() { |
| 132 return V8::UseCrankshaft() && FLAG_opt; | 141 return V8::UseCrankshaft() && FLAG_opt; |
| 133 } | 142 } |
| 134 | 143 |
| 135 | 144 |
| 136 void RuntimeProfiler::Optimize(JSFunction* function, bool eager, int delay) { | 145 void RuntimeProfiler::Optimize(JSFunction* function, bool eager, int delay) { |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 } | 269 } |
| 261 delete current; | 270 delete current; |
| 262 current = next; | 271 current = next; |
| 263 } | 272 } |
| 264 optimize_soon_list_ = NULL; | 273 optimize_soon_list_ = NULL; |
| 265 | 274 |
| 266 // Run through the JavaScript frames and collect them. If we already | 275 // Run through the JavaScript frames and collect them. If we already |
| 267 // have a sample of the function, we mark it for optimizations | 276 // have a sample of the function, we mark it for optimizations |
| 268 // (eagerly or lazily). | 277 // (eagerly or lazily). |
| 269 JSFunction* samples[kSamplerFrameCount]; | 278 JSFunction* samples[kSamplerFrameCount]; |
| 270 int count = 0; | 279 int sample_count = 0; |
| 280 int frame_count = 0; |
| 271 for (JavaScriptFrameIterator it; | 281 for (JavaScriptFrameIterator it; |
| 272 count < kSamplerFrameCount && !it.done(); | 282 frame_count++ < kSamplerFrameCount && !it.done(); |
| 273 it.Advance()) { | 283 it.Advance()) { |
| 274 JavaScriptFrame* frame = it.frame(); | 284 JavaScriptFrame* frame = it.frame(); |
| 275 JSFunction* function = JSFunction::cast(frame->function()); | 285 JSFunction* function = JSFunction::cast(frame->function()); |
| 276 int function_size = function->shared()->SourceSize(); | 286 |
| 277 int threshold_size_factor; | 287 // Adjust threshold each time we have processed |
| 278 if (function_size > kSizeLimit) { | 288 // a certain number of ticks. |
| 279 threshold_size_factor = sampler_threshold_size_factor_; | 289 if (sampler_ticks_until_threshold_adjustment_ > 0) { |
| 280 } else { | 290 sampler_ticks_until_threshold_adjustment_--; |
| 281 threshold_size_factor = 1; | 291 if (sampler_ticks_until_threshold_adjustment_ <= 0) { |
| 292 // If the threshold is not already at the minimum |
| 293 // modify and reset the ticks until next adjustment. |
| 294 if (sampler_threshold_ > kSamplerThresholdMin) { |
| 295 sampler_threshold_ -= kSamplerThresholdDelta; |
| 296 sampler_ticks_until_threshold_adjustment_ = |
| 297 kSamplerTicksBetweenThresholdAdjustment; |
| 298 } |
| 299 } |
| 282 } | 300 } |
| 283 | 301 |
| 284 int threshold = sampler_threshold_ * threshold_size_factor; | |
| 285 samples[count++] = function; | |
| 286 if (function->IsMarkedForLazyRecompilation()) { | 302 if (function->IsMarkedForLazyRecompilation()) { |
| 287 Code* unoptimized = function->shared()->code(); | 303 Code* unoptimized = function->shared()->code(); |
| 288 int nesting = unoptimized->allow_osr_at_loop_nesting_level(); | 304 int nesting = unoptimized->allow_osr_at_loop_nesting_level(); |
| 289 if (nesting == 0) AttemptOnStackReplacement(function); | 305 if (nesting == 0) AttemptOnStackReplacement(function); |
| 290 int new_nesting = Min(nesting + 1, Code::kMaxLoopNestingMarker); | 306 int new_nesting = Min(nesting + 1, Code::kMaxLoopNestingMarker); |
| 291 unoptimized->set_allow_osr_at_loop_nesting_level(new_nesting); | 307 unoptimized->set_allow_osr_at_loop_nesting_level(new_nesting); |
| 292 } else if (LookupSample(function) >= threshold) { | 308 } |
| 293 if (IsOptimizable(function)) { | 309 |
| 294 Optimize(function, false, 0); | 310 // Do not record non-optimizable functions. |
| 295 isolate_->compilation_cache()->MarkForEagerOptimizing( | 311 if (!IsOptimizable(function)) continue; |
| 296 Handle<JSFunction>(function, isolate_)); | 312 samples[sample_count++] = function; |
| 297 } | 313 |
| 314 int function_size = function->shared()->SourceSize(); |
| 315 int threshold_size_factor = (function_size > kSizeLimit) |
| 316 ? sampler_threshold_size_factor_ |
| 317 : 1; |
| 318 |
| 319 int threshold = sampler_threshold_ * threshold_size_factor; |
| 320 int current_js_ratio = NoBarrier_Load(&js_ratio_); |
| 321 |
| 322 // Adjust threshold depending on the ratio of time spent |
| 323 // in JS code. |
| 324 if (current_js_ratio < 20) { |
| 325 // If we spend less than 20% of the time in JS code, |
| 326 // do not optimize. |
| 327 continue; |
| 328 } else if (current_js_ratio < 75) { |
| 329 // Below 75% of time spent in JS code, only optimize very |
| 330 // frequently used functions. |
| 331 threshold *= 3; |
| 332 } |
| 333 |
| 334 if (LookupSample(function) >= threshold) { |
| 335 Optimize(function, false, 0); |
| 336 isolate_->compilation_cache()->MarkForEagerOptimizing( |
| 337 Handle<JSFunction>(function)); |
| 298 } | 338 } |
| 299 } | 339 } |
| 300 | 340 |
| 301 // Add the collected functions as samples. It's important not to do | 341 // Add the collected functions as samples. It's important not to do |
| 302 // this as part of collecting them because this will interfere with | 342 // this as part of collecting them because this will interfere with |
| 303 // the sample lookup in case of recursive functions. | 343 // the sample lookup in case of recursive functions. |
| 304 for (int i = 0; i < count; i++) { | 344 for (int i = 0; i < sample_count; i++) { |
| 305 AddSample(samples[i], kSamplerFrameWeight[i]); | 345 AddSample(samples[i], kSamplerFrameWeight[i]); |
| 306 } | 346 } |
| 307 } | 347 } |
| 308 | 348 |
| 309 | 349 |
| 310 void RuntimeProfiler::OptimizeSoon(JSFunction* function) { | 350 void RuntimeProfiler::OptimizeSoon(JSFunction* function) { |
| 311 if (!IsOptimizable(function)) return; | 351 if (!IsOptimizable(function)) return; |
| 312 PendingListNode* node = new PendingListNode(function); | 352 PendingListNode* node = new PendingListNode(function); |
| 313 node->set_next(optimize_soon_list_); | 353 node->set_next(optimize_soon_list_); |
| 314 optimize_soon_list_ = node; | 354 optimize_soon_list_ = node; |
| 315 } | 355 } |
| 316 | 356 |
| 317 | 357 |
| 358 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 359 void RuntimeProfiler::UpdateStateRatio(SamplerState current_state) { |
| 360 SamplerState old_state = state_window_[state_window_position_]; |
| 361 state_counts_[old_state]--; |
| 362 state_window_[state_window_position_] = current_state; |
| 363 state_counts_[current_state]++; |
| 364 ASSERT(IsPowerOf2(kStateWindowSize)); |
| 365 state_window_position_ = (state_window_position_ + 1) & |
| 366 (kStateWindowSize - 1); |
| 367 NoBarrier_Store(&js_ratio_, state_counts_[IN_JS_STATE] * 100 / |
| 368 kStateWindowSize); |
| 369 } |
| 370 #endif |
| 371 |
| 372 |
| 318 void RuntimeProfiler::NotifyTick() { | 373 void RuntimeProfiler::NotifyTick() { |
| 374 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 375 // Record state sample. |
| 376 SamplerState state = IsSomeIsolateInJS() |
| 377 ? IN_JS_STATE |
| 378 : IN_NON_JS_STATE; |
| 379 UpdateStateRatio(state); |
| 319 isolate_->stack_guard()->RequestRuntimeProfilerTick(); | 380 isolate_->stack_guard()->RequestRuntimeProfilerTick(); |
| 381 #endif |
| 320 } | 382 } |
| 321 | 383 |
| 322 | 384 |
| 323 void RuntimeProfiler::MarkCompactPrologue(bool is_compacting) { | 385 void RuntimeProfiler::MarkCompactPrologue(bool is_compacting) { |
| 324 if (is_compacting) { | 386 if (is_compacting) { |
| 325 // Clear all samples before mark-sweep-compact because every | 387 // Clear all samples before mark-sweep-compact because every |
| 326 // function might move. | 388 // function might move. |
| 327 ClearSampleBuffer(); | 389 ClearSampleBuffer(); |
| 328 } else { | 390 } else { |
| 329 // Clear only new space entries on mark-sweep since none of the | 391 // Clear only new space entries on mark-sweep since none of the |
| 330 // old-space functions will move. | 392 // old-space functions will move. |
| 331 ClearSampleBufferNewSpaceEntries(); | 393 ClearSampleBufferNewSpaceEntries(); |
| 332 } | 394 } |
| 333 } | 395 } |
| 334 | 396 |
| 335 | 397 |
| 336 void RuntimeProfiler::Setup() { | 398 void RuntimeProfiler::Setup() { |
| 337 ClearSampleBuffer(); | 399 ClearSampleBuffer(); |
| 338 // If the ticker hasn't already started, make sure to do so to get | 400 // If the ticker hasn't already started, make sure to do so to get |
| 339 // the ticks for the runtime profiler. | 401 // the ticks for the runtime profiler. |
| 340 if (IsEnabled()) isolate_->logger()->EnsureTickerStarted(); | 402 if (IsEnabled()) isolate_->logger()->EnsureTickerStarted(); |
| 341 } | 403 } |
| 342 | 404 |
| 343 | 405 |
| 344 void RuntimeProfiler::Reset() { | 406 void RuntimeProfiler::Reset() { |
| 345 sampler_threshold_ = kSamplerThresholdInit; | 407 sampler_threshold_ = kSamplerThresholdInit; |
| 346 sampler_threshold_size_factor_ = kSamplerThresholdSizeFactorInit; | 408 sampler_threshold_size_factor_ = kSamplerThresholdSizeFactorInit; |
| 409 sampler_ticks_until_threshold_adjustment_ = |
| 410 kSamplerTicksBetweenThresholdAdjustment; |
| 347 } | 411 } |
| 348 | 412 |
| 349 | 413 |
| 350 void RuntimeProfiler::TearDown() { | 414 void RuntimeProfiler::TearDown() { |
| 351 // Nothing to do. | 415 // Nothing to do. |
| 352 } | 416 } |
| 353 | 417 |
| 354 | 418 |
| 355 Object** RuntimeProfiler::SamplerWindowAddress() { | 419 Object** RuntimeProfiler::SamplerWindowAddress() { |
| 356 return sampler_window_; | 420 return sampler_window_; |
| 357 } | 421 } |
| 358 | 422 |
| 359 | 423 |
| 360 int RuntimeProfiler::SamplerWindowSize() { | 424 int RuntimeProfiler::SamplerWindowSize() { |
| 361 return kSamplerWindowSize; | 425 return kSamplerWindowSize; |
| 362 } | 426 } |
| 363 | 427 |
| 364 | 428 |
| 365 void RuntimeProfiler::HandleWakeUp(Isolate* isolate) { | 429 void RuntimeProfiler::HandleWakeUp(Isolate* isolate) { |
| 430 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 366 // The profiler thread must still be waiting. | 431 // The profiler thread must still be waiting. |
| 367 ASSERT(NoBarrier_Load(&state_) >= 0); | 432 ASSERT(NoBarrier_Load(&state_) >= 0); |
| 368 // In IsolateEnteredJS we have already incremented the counter and | 433 // In IsolateEnteredJS we have already incremented the counter and |
| 369 // undid the decrement done by the profiler thread. Increment again | 434 // undid the decrement done by the profiler thread. Increment again |
| 370 // to get the right count of active isolates. | 435 // to get the right count of active isolates. |
| 371 NoBarrier_AtomicIncrement(&state_, 1); | 436 NoBarrier_AtomicIncrement(&state_, 1); |
| 372 semaphore_->Signal(); | 437 semaphore_->Signal(); |
| 373 isolate->ResetEagerOptimizingData(); | 438 isolate->ResetEagerOptimizingData(); |
| 439 #endif |
| 374 } | 440 } |
| 375 | 441 |
| 376 | 442 |
| 377 bool RuntimeProfiler::IsSomeIsolateInJS() { | 443 bool RuntimeProfiler::IsSomeIsolateInJS() { |
| 378 return NoBarrier_Load(&state_) > 0; | 444 return NoBarrier_Load(&state_) > 0; |
| 379 } | 445 } |
| 380 | 446 |
| 381 | 447 |
| 382 bool RuntimeProfiler::WaitForSomeIsolateToEnterJS() { | 448 bool RuntimeProfiler::WaitForSomeIsolateToEnterJS() { |
| 449 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 383 Atomic32 old_state = NoBarrier_CompareAndSwap(&state_, 0, -1); | 450 Atomic32 old_state = NoBarrier_CompareAndSwap(&state_, 0, -1); |
| 384 ASSERT(old_state >= -1); | 451 ASSERT(old_state >= -1); |
| 385 if (old_state != 0) return false; | 452 if (old_state != 0) return false; |
| 386 semaphore_->Wait(); | 453 semaphore_->Wait(); |
| 454 #endif |
| 387 return true; | 455 return true; |
| 388 } | 456 } |
| 389 | 457 |
| 390 | 458 |
| 391 void RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown() { | 459 void RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown() { |
| 460 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 392 semaphore_->Signal(); | 461 semaphore_->Signal(); |
| 462 #endif |
| 393 } | 463 } |
| 394 | 464 |
| 395 | 465 |
| 396 bool RuntimeProfilerRateLimiter::SuspendIfNecessary() { | 466 bool RuntimeProfilerRateLimiter::SuspendIfNecessary() { |
| 397 if (!RuntimeProfiler::IsEnabled()) return false; | 467 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 398 static const int kNonJSTicksThreshold = 100; | 468 static const int kNonJSTicksThreshold = 100; |
| 399 if (RuntimeProfiler::IsSomeIsolateInJS()) { | 469 if (RuntimeProfiler::IsSomeIsolateInJS()) { |
| 400 non_js_ticks_ = 0; | 470 non_js_ticks_ = 0; |
| 401 } else { | 471 } else { |
| 402 if (non_js_ticks_ < kNonJSTicksThreshold) { | 472 if (non_js_ticks_ < kNonJSTicksThreshold) { |
| 403 ++non_js_ticks_; | 473 ++non_js_ticks_; |
| 404 } else { | 474 } else { |
| 405 return RuntimeProfiler::WaitForSomeIsolateToEnterJS(); | 475 return RuntimeProfiler::WaitForSomeIsolateToEnterJS(); |
| 406 } | 476 } |
| 407 } | 477 } |
| 478 #endif |
| 408 return false; | 479 return false; |
| 409 } | 480 } |
| 410 | 481 |
| 411 | 482 |
| 412 } } // namespace v8::internal | 483 } } // namespace v8::internal |
| OLD | NEW |