| 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 17 matching lines...) Expand all Loading... |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #include "runtime-profiler.h" | 30 #include "runtime-profiler.h" |
| 31 | 31 |
| 32 #include "assembler.h" | 32 #include "assembler.h" |
| 33 #include "code-stubs.h" | 33 #include "code-stubs.h" |
| 34 #include "compilation-cache.h" | 34 #include "compilation-cache.h" |
| 35 #include "deoptimizer.h" | 35 #include "deoptimizer.h" |
| 36 #include "execution.h" | 36 #include "execution.h" |
| 37 #include "global-handles.h" | 37 #include "global-handles.h" |
| 38 #include "mark-compact.h" |
| 38 #include "scopeinfo.h" | 39 #include "scopeinfo.h" |
| 39 #include "top.h" | 40 #include "top.h" |
| 40 | 41 |
| 41 namespace v8 { | 42 namespace v8 { |
| 42 namespace internal { | 43 namespace internal { |
| 43 | 44 |
| 44 | 45 |
| 45 class PendingListNode : public Malloced { | 46 class PendingListNode : public Malloced { |
| 46 public: | 47 public: |
| 47 explicit PendingListNode(JSFunction* function); | 48 explicit PendingListNode(JSFunction* function); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 93 | 94 |
| 94 static int sampler_threshold = kSamplerThresholdInit; | 95 static int sampler_threshold = kSamplerThresholdInit; |
| 95 static int sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit; | 96 static int sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit; |
| 96 | 97 |
| 97 static int sampler_ticks_until_threshold_adjustment = | 98 static int sampler_ticks_until_threshold_adjustment = |
| 98 kSamplerTicksBetweenThresholdAdjustment; | 99 kSamplerTicksBetweenThresholdAdjustment; |
| 99 | 100 |
| 100 // The ratio of ticks spent in JS code in percent. | 101 // The ratio of ticks spent in JS code in percent. |
| 101 static Atomic32 js_ratio; | 102 static Atomic32 js_ratio; |
| 102 | 103 |
| 103 // The JSFunctions in the sampler window are not GC safe. Old-space | |
| 104 // pointers are not cleared during mark-sweep collection and therefore | |
| 105 // the window might contain stale pointers. The window is updated on | |
| 106 // scavenges and (parts of it) cleared on mark-sweep and | |
| 107 // mark-sweep-compact. | |
| 108 static Object* sampler_window[kSamplerWindowSize] = { NULL, }; | 104 static Object* sampler_window[kSamplerWindowSize] = { NULL, }; |
| 109 static int sampler_window_position = 0; | 105 static int sampler_window_position = 0; |
| 110 static int sampler_window_weight[kSamplerWindowSize] = { 0, }; | 106 static int sampler_window_weight[kSamplerWindowSize] = { 0, }; |
| 111 | 107 |
| 112 | 108 |
| 113 // Support for pending 'optimize soon' requests. | 109 // Support for pending 'optimize soon' requests. |
| 114 static PendingListNode* optimize_soon_list = NULL; | 110 static PendingListNode* optimize_soon_list = NULL; |
| 115 | 111 |
| 116 | 112 |
| 117 PendingListNode::PendingListNode(JSFunction* function) : next_(NULL) { | 113 PendingListNode::PendingListNode(JSFunction* function) : next_(NULL) { |
| 118 function_ = GlobalHandles::Create(function); | 114 function_ = GlobalHandles::Create(function); |
| 119 start_ = OS::Ticks(); | 115 start_ = OS::Ticks(); |
| 120 GlobalHandles::MakeWeak(function_.location(), this, &WeakCallback); | 116 GlobalHandles::MakeWeak(function_.location(), this, &WeakCallback); |
| 121 } | 117 } |
| 122 | 118 |
| 123 | 119 |
| 124 void PendingListNode::Destroy() { | 120 void PendingListNode::Destroy() { |
| 125 if (!IsValid()) return; | 121 if (!IsValid()) return; |
| 126 GlobalHandles::Destroy(function_.location()); | 122 GlobalHandles::Destroy(function_.location()); |
| 127 function_= Handle<Object>::null(); | 123 function_= Handle<Object>::null(); |
| 128 } | 124 } |
| 129 | 125 |
| 130 | 126 |
| 131 void PendingListNode::WeakCallback(v8::Persistent<v8::Value>, void* data) { | 127 void PendingListNode::WeakCallback(v8::Persistent<v8::Value>, void* data) { |
| 132 reinterpret_cast<PendingListNode*>(data)->Destroy(); | 128 reinterpret_cast<PendingListNode*>(data)->Destroy(); |
| 133 } | 129 } |
| 134 | 130 |
| 135 | 131 |
| 136 static bool IsOptimizable(JSFunction* function) { | 132 static bool IsOptimizable(JSFunction* function) { |
| 137 if (Heap::InNewSpace(function)) return false; | |
| 138 Code* code = function->code(); | 133 Code* code = function->code(); |
| 139 return code->kind() == Code::FUNCTION && code->optimizable(); | 134 return code->kind() == Code::FUNCTION && code->optimizable(); |
| 140 } | 135 } |
| 141 | 136 |
| 142 | 137 |
| 143 static void Optimize(JSFunction* function, bool eager, int delay) { | 138 static void Optimize(JSFunction* function, bool eager, int delay) { |
| 144 ASSERT(IsOptimizable(function)); | 139 ASSERT(IsOptimizable(function)); |
| 145 if (FLAG_trace_opt) { | 140 if (FLAG_trace_opt) { |
| 146 PrintF("[marking (%s) ", eager ? "eagerly" : "lazily"); | 141 PrintF("[marking (%s) ", eager ? "eagerly" : "lazily"); |
| 147 function->PrintName(); | 142 function->PrintName(); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 201 | 196 |
| 202 | 197 |
| 203 static void ClearSampleBuffer() { | 198 static void ClearSampleBuffer() { |
| 204 for (int i = 0; i < kSamplerWindowSize; i++) { | 199 for (int i = 0; i < kSamplerWindowSize; i++) { |
| 205 sampler_window[i] = NULL; | 200 sampler_window[i] = NULL; |
| 206 sampler_window_weight[i] = 0; | 201 sampler_window_weight[i] = 0; |
| 207 } | 202 } |
| 208 } | 203 } |
| 209 | 204 |
| 210 | 205 |
| 211 static void ClearSampleBufferNewSpaceEntries() { | |
| 212 for (int i = 0; i < kSamplerWindowSize; i++) { | |
| 213 if (Heap::InNewSpace(sampler_window[i])) { | |
| 214 sampler_window[i] = NULL; | |
| 215 sampler_window_weight[i] = 0; | |
| 216 } | |
| 217 } | |
| 218 } | |
| 219 | |
| 220 | |
| 221 static int LookupSample(JSFunction* function) { | 206 static int LookupSample(JSFunction* function) { |
| 222 int weight = 0; | 207 int weight = 0; |
| 223 for (int i = 0; i < kSamplerWindowSize; i++) { | 208 for (int i = 0; i < kSamplerWindowSize; i++) { |
| 224 Object* sample = sampler_window[i]; | 209 Object* sample = sampler_window[i]; |
| 225 if (sample != NULL) { | 210 if (sample != NULL) { |
| 226 if (function == sample) { | 211 if (function == sample) { |
| 227 weight += sampler_window_weight[i]; | 212 weight += sampler_window_weight[i]; |
| 228 } | 213 } |
| 229 } | 214 } |
| 230 } | 215 } |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 365 // Record state sample. | 350 // Record state sample. |
| 366 SamplerState state = Top::IsInJSState() | 351 SamplerState state = Top::IsInJSState() |
| 367 ? IN_JS_STATE | 352 ? IN_JS_STATE |
| 368 : IN_NON_JS_STATE; | 353 : IN_NON_JS_STATE; |
| 369 UpdateStateRatio(state); | 354 UpdateStateRatio(state); |
| 370 StackGuard::RequestRuntimeProfilerTick(); | 355 StackGuard::RequestRuntimeProfilerTick(); |
| 371 #endif | 356 #endif |
| 372 } | 357 } |
| 373 | 358 |
| 374 | 359 |
| 375 void RuntimeProfiler::MarkCompactPrologue(bool is_compacting) { | |
| 376 if (is_compacting) { | |
| 377 // Clear all samples before mark-sweep-compact because every | |
| 378 // function might move. | |
| 379 ClearSampleBuffer(); | |
| 380 } else { | |
| 381 // Clear only new space entries on mark-sweep since none of the | |
| 382 // old-space functions will move. | |
| 383 ClearSampleBufferNewSpaceEntries(); | |
| 384 } | |
| 385 } | |
| 386 | |
| 387 | |
| 388 bool IsEqual(void* first, void* second) { | |
| 389 return first == second; | |
| 390 } | |
| 391 | |
| 392 | |
| 393 void RuntimeProfiler::Setup() { | 360 void RuntimeProfiler::Setup() { |
| 394 ClearSampleBuffer(); | 361 ClearSampleBuffer(); |
| 395 // If the ticker hasn't already started, make sure to do so to get | 362 // If the ticker hasn't already started, make sure to do so to get |
| 396 // the ticks for the runtime profiler. | 363 // the ticks for the runtime profiler. |
| 397 if (IsEnabled()) Logger::EnsureTickerStarted(); | 364 if (IsEnabled()) Logger::EnsureTickerStarted(); |
| 398 } | 365 } |
| 399 | 366 |
| 400 | 367 |
| 401 void RuntimeProfiler::Reset() { | 368 void RuntimeProfiler::Reset() { |
| 402 sampler_threshold = kSamplerThresholdInit; | 369 sampler_threshold = kSamplerThresholdInit; |
| 403 sampler_ticks_until_threshold_adjustment = | 370 sampler_ticks_until_threshold_adjustment = |
| 404 kSamplerTicksBetweenThresholdAdjustment; | 371 kSamplerTicksBetweenThresholdAdjustment; |
| 405 sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit; | 372 sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit; |
| 406 } | 373 } |
| 407 | 374 |
| 408 | 375 |
| 409 void RuntimeProfiler::TearDown() { | 376 void RuntimeProfiler::TearDown() { |
| 410 // Nothing to do. | 377 // Nothing to do. |
| 411 } | 378 } |
| 412 | 379 |
| 413 | 380 |
| 414 Object** RuntimeProfiler::SamplerWindowAddress() { | |
| 415 return sampler_window; | |
| 416 } | |
| 417 | |
| 418 | |
| 419 int RuntimeProfiler::SamplerWindowSize() { | 381 int RuntimeProfiler::SamplerWindowSize() { |
| 420 return kSamplerWindowSize; | 382 return kSamplerWindowSize; |
| 421 } | 383 } |
| 422 | 384 |
| 423 | 385 |
| 386 // Update the pointers in the sampler window after a GC. |
| 387 void RuntimeProfiler::UpdateSamplesAfterScavenge() { |
| 388 for (int i = 0; i < kSamplerWindowSize; i++) { |
| 389 Object* function = sampler_window[i]; |
| 390 if (function != NULL && Heap::InNewSpace(function)) { |
| 391 MapWord map_word = HeapObject::cast(function)->map_word(); |
| 392 if (map_word.IsForwardingAddress()) { |
| 393 sampler_window[i] = map_word.ToForwardingAddress(); |
| 394 } else { |
| 395 sampler_window[i] = NULL; |
| 396 } |
| 397 } |
| 398 } |
| 399 } |
| 400 |
| 401 |
| 402 void RuntimeProfiler::RemoveDeadSamples() { |
| 403 for (int i = 0; i < kSamplerWindowSize; i++) { |
| 404 Object* function = sampler_window[i]; |
| 405 if (function != NULL && !HeapObject::cast(function)->IsMarked()) { |
| 406 sampler_window[i] = NULL; |
| 407 } |
| 408 } |
| 409 } |
| 410 |
| 411 |
| 412 void RuntimeProfiler::UpdateSamplesAfterCompact(ObjectVisitor* visitor) { |
| 413 for (int i = 0; i < kSamplerWindowSize; i++) { |
| 414 visitor->VisitPointer(&sampler_window[i]); |
| 415 } |
| 416 } |
| 417 |
| 418 |
| 424 bool RuntimeProfilerRateLimiter::SuspendIfNecessary() { | 419 bool RuntimeProfilerRateLimiter::SuspendIfNecessary() { |
| 425 #ifdef ENABLE_LOGGING_AND_PROFILING | 420 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 426 static const int kNonJSTicksThreshold = 100; | 421 static const int kNonJSTicksThreshold = 100; |
| 427 // We suspend the runtime profiler thread when not running | 422 // We suspend the runtime profiler thread when not running |
| 428 // JavaScript. If the CPU profiler is active we must not do this | 423 // JavaScript. If the CPU profiler is active we must not do this |
| 429 // because it samples both JavaScript and C++ code. | 424 // because it samples both JavaScript and C++ code. |
| 430 if (RuntimeProfiler::IsEnabled() && | 425 if (RuntimeProfiler::IsEnabled() && |
| 431 !CpuProfiler::is_profiling() && | 426 !CpuProfiler::is_profiling() && |
| 432 !(FLAG_prof && FLAG_prof_auto)) { | 427 !(FLAG_prof && FLAG_prof_auto)) { |
| 433 if (Top::IsInJSState()) { | 428 if (Top::IsInJSState()) { |
| 434 non_js_ticks_ = 0; | 429 non_js_ticks_ = 0; |
| 435 } else { | 430 } else { |
| 436 if (non_js_ticks_ < kNonJSTicksThreshold) { | 431 if (non_js_ticks_ < kNonJSTicksThreshold) { |
| 437 ++non_js_ticks_; | 432 ++non_js_ticks_; |
| 438 } else { | 433 } else { |
| 439 if (Top::WaitForJSState()) return true; | 434 if (Top::WaitForJSState()) return true; |
| 440 } | 435 } |
| 441 } | 436 } |
| 442 } | 437 } |
| 443 #endif | 438 #endif |
| 444 return false; | 439 return false; |
| 445 } | 440 } |
| 446 | 441 |
| 447 | 442 |
| 448 } } // namespace v8::internal | 443 } } // namespace v8::internal |
| OLD | NEW |