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 | |
77 // Optimization sampler constants. | 71 // Optimization sampler constants. |
78 static const int kSamplerFrameCount = 2; | 72 static const int kSamplerFrameCount = 2; |
79 static const int kSamplerFrameWeight[kSamplerFrameCount] = { 2, 1 }; | 73 static const int kSamplerFrameWeight[kSamplerFrameCount] = { 2, 1 }; |
80 static const int kSamplerWindowSize = 16; | 74 static const int kSamplerWindowSize = 16; |
81 | 75 |
82 static const int kSamplerTicksBetweenThresholdAdjustment = 32; | 76 static const int kSamplerTicksDelta = 32; |
83 | 77 |
84 static const int kSamplerThresholdInit = 3; | 78 static const int kSamplerThresholdInit = 3; |
85 static const int kSamplerThresholdMin = 1; | 79 static const int kSamplerThresholdMin = 1; |
86 static const int kSamplerThresholdDelta = 1; | 80 static const int kSamplerThresholdDelta = 1; |
87 | 81 |
88 static const int kSamplerThresholdSizeFactorInit = 3; | 82 static const int kSamplerThresholdSizeFactorInit = 3; |
89 static const int kSamplerThresholdSizeFactorMin = 1; | 83 static const int kSamplerThresholdSizeFactorMin = 1; |
90 static const int kSamplerThresholdSizeFactorDelta = 1; | 84 static const int kSamplerThresholdSizeFactorDelta = 1; |
91 | 85 |
92 static const int kSizeLimit = 1500; | 86 static const int kSizeLimit = 1500; |
93 | 87 |
94 static int sampler_threshold = kSamplerThresholdInit; | 88 static int sampler_threshold = kSamplerThresholdInit; |
95 static int sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit; | 89 static int sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit; |
96 | 90 |
97 static int sampler_ticks_until_threshold_adjustment = | |
98 kSamplerTicksBetweenThresholdAdjustment; | |
99 | |
100 // The ratio of ticks spent in JS code in percent. | |
101 static Atomic32 js_ratio; | |
102 | 91 |
103 // The JSFunctions in the sampler window are not GC safe. Old-space | 92 // The JSFunctions in the sampler window are not GC safe. Old-space |
104 // pointers are not cleared during mark-sweep collection and therefore | 93 // pointers are not cleared during mark-sweep collection and therefore |
105 // the window might contain stale pointers. The window is updated on | 94 // the window might contain stale pointers. The window is updated on |
106 // scavenges and (parts of it) cleared on mark-sweep and | 95 // scavenges and (parts of it) cleared on mark-sweep and |
107 // mark-sweep-compact. | 96 // mark-sweep-compact. |
108 static Object* sampler_window[kSamplerWindowSize] = { NULL, }; | 97 static Object* sampler_window[kSamplerWindowSize] = { NULL, }; |
109 static int sampler_window_position = 0; | 98 static int sampler_window_position = 0; |
110 static int sampler_window_weight[kSamplerWindowSize] = { 0, }; | 99 static int sampler_window_weight[kSamplerWindowSize] = { 0, }; |
111 | 100 |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
265 } | 254 } |
266 delete current; | 255 delete current; |
267 current = next; | 256 current = next; |
268 } | 257 } |
269 optimize_soon_list = NULL; | 258 optimize_soon_list = NULL; |
270 | 259 |
271 // Run through the JavaScript frames and collect them. If we already | 260 // Run through the JavaScript frames and collect them. If we already |
272 // have a sample of the function, we mark it for optimizations | 261 // have a sample of the function, we mark it for optimizations |
273 // (eagerly or lazily). | 262 // (eagerly or lazily). |
274 JSFunction* samples[kSamplerFrameCount]; | 263 JSFunction* samples[kSamplerFrameCount]; |
275 int sample_count = 0; | 264 int count = 0; |
276 int frame_count = 0; | |
277 for (JavaScriptFrameIterator it; | 265 for (JavaScriptFrameIterator it; |
278 frame_count++ < kSamplerFrameCount && !it.done(); | 266 count < kSamplerFrameCount && !it.done(); |
279 it.Advance()) { | 267 it.Advance()) { |
280 JavaScriptFrame* frame = it.frame(); | 268 JavaScriptFrame* frame = it.frame(); |
281 JSFunction* function = JSFunction::cast(frame->function()); | 269 JSFunction* function = JSFunction::cast(frame->function()); |
282 | 270 int function_size = function->shared()->SourceSize(); |
283 // Adjust threshold each time we have processed | 271 int threshold_size_factor; |
284 // a certain number of ticks. | 272 if (function_size > kSizeLimit) { |
285 if (sampler_ticks_until_threshold_adjustment > 0) { | 273 threshold_size_factor = sampler_threshold_size_factor; |
286 sampler_ticks_until_threshold_adjustment--; | 274 } else { |
287 if (sampler_ticks_until_threshold_adjustment <= 0) { | 275 threshold_size_factor = 1; |
288 // If the threshold is not already at the minimum | |
289 // modify and reset the ticks until next adjustment. | |
290 if (sampler_threshold > kSamplerThresholdMin) { | |
291 sampler_threshold -= kSamplerThresholdDelta; | |
292 sampler_ticks_until_threshold_adjustment = | |
293 kSamplerTicksBetweenThresholdAdjustment; | |
294 } | |
295 } | |
296 } | 276 } |
297 | 277 |
| 278 int threshold = sampler_threshold * threshold_size_factor; |
| 279 samples[count++] = function; |
298 if (function->IsMarkedForLazyRecompilation()) { | 280 if (function->IsMarkedForLazyRecompilation()) { |
299 Code* unoptimized = function->shared()->code(); | 281 Code* unoptimized = function->shared()->code(); |
300 int nesting = unoptimized->allow_osr_at_loop_nesting_level(); | 282 int nesting = unoptimized->allow_osr_at_loop_nesting_level(); |
301 if (nesting == 0) AttemptOnStackReplacement(function); | 283 if (nesting == 0) AttemptOnStackReplacement(function); |
302 int new_nesting = Min(nesting + 1, Code::kMaxLoopNestingMarker); | 284 int new_nesting = Min(nesting + 1, Code::kMaxLoopNestingMarker); |
303 unoptimized->set_allow_osr_at_loop_nesting_level(new_nesting); | 285 unoptimized->set_allow_osr_at_loop_nesting_level(new_nesting); |
304 } | 286 } else if (LookupSample(function) >= threshold) { |
305 | 287 if (IsOptimizable(function)) { |
306 // Do not record non-optimizable functions. | 288 Optimize(function, false, 0); |
307 if (!IsOptimizable(function)) continue; | 289 CompilationCache::MarkForEagerOptimizing(Handle<JSFunction>(function)); |
308 samples[sample_count++] = function; | 290 } |
309 | |
310 int function_size = function->shared()->SourceSize(); | |
311 int threshold_size_factor = (function_size > kSizeLimit) | |
312 ? sampler_threshold_size_factor | |
313 : 1; | |
314 | |
315 int threshold = sampler_threshold * threshold_size_factor; | |
316 int current_js_ratio = NoBarrier_Load(&js_ratio); | |
317 | |
318 // Adjust threshold depending on the ratio of time spent | |
319 // in JS code. | |
320 if (current_js_ratio < 20) { | |
321 // If we spend less than 20% of the time in JS code, | |
322 // do not optimize. | |
323 continue; | |
324 } else if (current_js_ratio < 75) { | |
325 // Below 75% of time spent in JS code, only optimize very | |
326 // frequently used functions. | |
327 threshold *= 3; | |
328 } | |
329 | |
330 if (LookupSample(function) >= threshold) { | |
331 Optimize(function, false, 0); | |
332 CompilationCache::MarkForEagerOptimizing(Handle<JSFunction>(function)); | |
333 } | 291 } |
334 } | 292 } |
335 | 293 |
336 // Add the collected functions as samples. It's important not to do | 294 // Add the collected functions as samples. It's important not to do |
337 // this as part of collecting them because this will interfere with | 295 // this as part of collecting them because this will interfere with |
338 // the sample lookup in case of recursive functions. | 296 // the sample lookup in case of recursive functions. |
339 for (int i = 0; i < sample_count; i++) { | 297 for (int i = 0; i < count; i++) { |
340 AddSample(samples[i], kSamplerFrameWeight[i]); | 298 AddSample(samples[i], kSamplerFrameWeight[i]); |
341 } | 299 } |
342 } | 300 } |
343 | 301 |
344 | 302 |
345 void RuntimeProfiler::OptimizeSoon(JSFunction* function) { | 303 void RuntimeProfiler::OptimizeSoon(JSFunction* function) { |
346 if (!IsOptimizable(function)) return; | 304 if (!IsOptimizable(function)) return; |
347 PendingListNode* node = new PendingListNode(function); | 305 PendingListNode* node = new PendingListNode(function); |
348 node->set_next(optimize_soon_list); | 306 node->set_next(optimize_soon_list); |
349 optimize_soon_list = node; | 307 optimize_soon_list = node; |
350 } | 308 } |
351 | 309 |
352 | 310 |
353 static void UpdateStateRatio(SamplerState current_state) { | |
354 static const int kStateWindowSize = 128; | |
355 static SamplerState state_window[kStateWindowSize]; | |
356 static int state_window_position = 0; | |
357 static int state_counts[2] = { kStateWindowSize, 0 }; | |
358 | |
359 SamplerState old_state = state_window[state_window_position]; | |
360 state_counts[old_state]--; | |
361 state_window[state_window_position] = current_state; | |
362 state_counts[current_state]++; | |
363 ASSERT(IsPowerOf2(kStateWindowSize)); | |
364 state_window_position = (state_window_position + 1) & | |
365 (kStateWindowSize - 1); | |
366 NoBarrier_Store(&js_ratio, state_counts[IN_JS_STATE] * 100 / | |
367 kStateWindowSize); | |
368 } | |
369 | |
370 | |
371 void RuntimeProfiler::NotifyTick() { | 311 void RuntimeProfiler::NotifyTick() { |
372 // Record state sample. | |
373 SamplerState state = Top::IsInJSState() | |
374 ? IN_JS_STATE | |
375 : IN_NON_JS_STATE; | |
376 UpdateStateRatio(state); | |
377 StackGuard::RequestRuntimeProfilerTick(); | 312 StackGuard::RequestRuntimeProfilerTick(); |
378 } | 313 } |
379 | 314 |
380 | 315 |
381 void RuntimeProfiler::MarkCompactPrologue(bool is_compacting) { | 316 void RuntimeProfiler::MarkCompactPrologue(bool is_compacting) { |
382 if (is_compacting) { | 317 if (is_compacting) { |
383 // Clear all samples before mark-sweep-compact because every | 318 // Clear all samples before mark-sweep-compact because every |
384 // function might move. | 319 // function might move. |
385 ClearSampleBuffer(); | 320 ClearSampleBuffer(); |
386 } else { | 321 } else { |
(...skipping 12 matching lines...) Expand all Loading... |
399 void RuntimeProfiler::Setup() { | 334 void RuntimeProfiler::Setup() { |
400 ClearSampleBuffer(); | 335 ClearSampleBuffer(); |
401 // If the ticker hasn't already started, make sure to do so to get | 336 // If the ticker hasn't already started, make sure to do so to get |
402 // the ticks for the runtime profiler. | 337 // the ticks for the runtime profiler. |
403 if (IsEnabled()) Logger::EnsureTickerStarted(); | 338 if (IsEnabled()) Logger::EnsureTickerStarted(); |
404 } | 339 } |
405 | 340 |
406 | 341 |
407 void RuntimeProfiler::Reset() { | 342 void RuntimeProfiler::Reset() { |
408 sampler_threshold = kSamplerThresholdInit; | 343 sampler_threshold = kSamplerThresholdInit; |
409 sampler_ticks_until_threshold_adjustment = | |
410 kSamplerTicksBetweenThresholdAdjustment; | |
411 sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit; | 344 sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit; |
412 } | 345 } |
413 | 346 |
414 | 347 |
415 void RuntimeProfiler::TearDown() { | 348 void RuntimeProfiler::TearDown() { |
416 // Nothing to do. | 349 // Nothing to do. |
417 } | 350 } |
418 | 351 |
419 | 352 |
420 Object** RuntimeProfiler::SamplerWindowAddress() { | 353 Object** RuntimeProfiler::SamplerWindowAddress() { |
(...skipping 22 matching lines...) Expand all Loading... |
443 } else { | 376 } else { |
444 if (Top::WaitForJSState()) return true; | 377 if (Top::WaitForJSState()) return true; |
445 } | 378 } |
446 } | 379 } |
447 } | 380 } |
448 return false; | 381 return false; |
449 } | 382 } |
450 | 383 |
451 | 384 |
452 } } // namespace v8::internal | 385 } } // namespace v8::internal |
OLD | NEW |