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 |