From 71ba8c5fb4ddb7be53a2c9221bbf3447121329d0 Mon Sep 17 00:00:00 2001 From: "yangguo@chromium.org" Date: Mon, 14 Oct 2013 14:15:22 +0000 Subject: [PATCH] Retire concurrent recompilation delay for non-stress testing. Instead, we block concurrent recompilation until unblocked. This makes affected tests more predictable and run shorter. R=jkummerow@chromium.org BUG= Review URL: https://codereview.chromium.org/26758003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17199 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/flag-definitions.h | 2 ++ src/optimizing-compiler-thread.cc | 17 ++++++++++++++++- src/optimizing-compiler-thread.h | 6 +++++- src/runtime.cc | 7 +++++++ src/runtime.h | 1 + .../concurrent-invalidate-transition-map.js} | 10 +++++++--- ...oto-change.js => concurrent-proto-change.js} | 12 +++++++----- .../manual-concurrent-recompile.js} | 11 +++++++---- ...s => concurrent-initial-prototype-change.js} | 11 +++++++---- .../regress/regress-embedded-cons-string.js | 10 ++++++---- .../regress/regress-opt-after-debug-deopt.js | 8 +++++++- .../regress-prepare-break-while-recompile.js | 11 ++++++++--- 12 files changed, 80 insertions(+), 26 deletions(-) rename test/mjsunit/{parallel-invalidate-transition-map.js => compiler/concurrent-invalidate-transition-map.js} (86%) rename test/mjsunit/compiler/{parallel-proto-change.js => concurrent-proto-change.js} (87%) rename test/mjsunit/{manual-parallel-recompile.js => compiler/manual-concurrent-recompile.js} (87%) rename test/mjsunit/{parallel-initial-prototype-change.js => concurrent-initial-prototype-change.js} (86%) diff --git a/src/flag-definitions.h b/src/flag-definitions.h index 7450ef9167..63cf4a6aef 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -328,6 +328,8 @@ DEFINE_int(concurrent_recompilation_queue_length, 8, "the length of the concurrent compilation queue") DEFINE_int(concurrent_recompilation_delay, 0, "artificial compilation delay in ms") +DEFINE_bool(block_concurrent_recompilation, false, + "block queued jobs until released") DEFINE_bool(concurrent_osr, false, "concurrent on-stack replacement") DEFINE_implication(concurrent_osr, concurrent_recompilation) diff --git a/src/optimizing-compiler-thread.cc b/src/optimizing-compiler-thread.cc index 202e6e5c57..0053148a02 100644 --- a/src/optimizing-compiler-thread.cc +++ b/src/optimizing-compiler-thread.cc @@ -168,6 +168,7 @@ void OptimizingCompilerThread::FlushOsrBuffer(bool restore_function_code) { void OptimizingCompilerThread::Flush() { ASSERT(!IsOptimizerThread()); Release_Store(&stop_thread_, static_cast(FLUSH)); + if (FLAG_block_concurrent_recompilation) Unblock(); input_queue_semaphore_.Signal(); stop_semaphore_.Wait(); FlushOutputQueue(true); @@ -181,6 +182,7 @@ void OptimizingCompilerThread::Flush() { void OptimizingCompilerThread::Stop() { ASSERT(!IsOptimizerThread()); Release_Store(&stop_thread_, static_cast(STOP)); + if (FLAG_block_concurrent_recompilation) Unblock(); input_queue_semaphore_.Signal(); stop_semaphore_.Wait(); @@ -252,7 +254,20 @@ void OptimizingCompilerThread::QueueForOptimization(RecompileJob* job) { info->closure()->MarkInRecompileQueue(); } input_queue_.Enqueue(job); - input_queue_semaphore_.Signal(); + if (FLAG_block_concurrent_recompilation) { + blocked_jobs_++; + } else { + input_queue_semaphore_.Signal(); + } +} + + +void OptimizingCompilerThread::Unblock() { + ASSERT(!IsOptimizerThread()); + while (blocked_jobs_ > 0) { + input_queue_semaphore_.Signal(); + blocked_jobs_--; + } } diff --git a/src/optimizing-compiler-thread.h b/src/optimizing-compiler-thread.h index d98a8b2b7e..89921423ab 100644 --- a/src/optimizing-compiler-thread.h +++ b/src/optimizing-compiler-thread.h @@ -55,7 +55,8 @@ class OptimizingCompilerThread : public Thread { input_queue_semaphore_(0), osr_cursor_(0), osr_hits_(0), - osr_attempts_(0) { + osr_attempts_(0), + blocked_jobs_(0) { NoBarrier_Store(&stop_thread_, static_cast(CONTINUE)); NoBarrier_Store(&queue_length_, static_cast(0)); if (FLAG_concurrent_osr) { @@ -73,6 +74,7 @@ class OptimizingCompilerThread : public Thread { void Stop(); void Flush(); void QueueForOptimization(RecompileJob* optimizing_compiler); + void Unblock(); void InstallOptimizedFunctions(); RecompileJob* FindReadyOSRCandidate(Handle function, uint32_t osr_pc_offset); @@ -141,6 +143,8 @@ class OptimizingCompilerThread : public Thread { int osr_hits_; int osr_attempts_; + + int blocked_jobs_; }; } } // namespace v8::internal diff --git a/src/runtime.cc b/src/runtime.cc index 77014b1771..be0281b846 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -8579,6 +8579,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) { } +RUNTIME_FUNCTION(MaybeObject*, Runtime_UnblockConcurrentRecompilation) { + RUNTIME_ASSERT(FLAG_block_concurrent_recompilation); + isolate->optimizing_compiler_thread()->Unblock(); + return isolate->heap()->undefined_value(); +} + + RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) { HandleScope scope(isolate); ASSERT(args.length() == 1); diff --git a/src/runtime.h b/src/runtime.h index 5566226198..1b7e32e7a1 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -99,6 +99,7 @@ namespace internal { F(NeverOptimizeFunction, 1, 1) \ F(GetOptimizationStatus, -1, 1) \ F(GetOptimizationCount, 1, 1) \ + F(UnblockConcurrentRecompilation, 0, 1) \ F(CompileForOnStackReplacement, 2, 1) \ F(SetAllocationTimeout, 2, 1) \ F(AllocateInNewSpace, 1, 1) \ diff --git a/test/mjsunit/parallel-invalidate-transition-map.js b/test/mjsunit/compiler/concurrent-invalidate-transition-map.js similarity index 86% rename from test/mjsunit/parallel-invalidate-transition-map.js rename to test/mjsunit/compiler/concurrent-invalidate-transition-map.js index 9a5d31003f..699534f665 100644 --- a/test/mjsunit/parallel-invalidate-transition-map.js +++ b/test/mjsunit/compiler/concurrent-invalidate-transition-map.js @@ -26,7 +26,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Flags: --track-fields --track-double-fields --allow-natives-syntax -// Flags: --concurrent-recompilation --concurrent-recompilation-delay=100 +// Flags: --concurrent-recompilation --block-concurrent-recompilation if (!%IsConcurrentRecompilationSupported()) { print("Concurrent recompilation is disabled. Skipping this test."); @@ -49,9 +49,13 @@ add_field(new_object()); %OptimizeFunctionOnNextCall(add_field, "concurrent"); var o = new_object(); -// Trigger optimization in the background thread. +// Kick off recompilation. add_field(o); -// Invalidate transition map while optimization is underway. +// Invalidate transition map after compile graph has been created. o.c = 2.2; +// In the mean time, concurrent recompiling is still blocked. +assertUnoptimized(add_field, "no sync"); +// Let concurrent recompilation proceed. +%UnblockConcurrentRecompilation(); // Sync with background thread to conclude optimization that bailed out. assertUnoptimized(add_field, "sync"); diff --git a/test/mjsunit/compiler/parallel-proto-change.js b/test/mjsunit/compiler/concurrent-proto-change.js similarity index 87% rename from test/mjsunit/compiler/parallel-proto-change.js rename to test/mjsunit/compiler/concurrent-proto-change.js index 7602279893..e126465a95 100644 --- a/test/mjsunit/compiler/parallel-proto-change.js +++ b/test/mjsunit/compiler/concurrent-proto-change.js @@ -26,7 +26,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Flags: --allow-natives-syntax -// Flags: --concurrent-recompilation --concurrent-recompilation-delay=50 +// Flags: --concurrent-recompilation --block-concurrent-recompilation if (!%IsConcurrentRecompilationSupported()) { print("Concurrent recompilation is disabled. Skipping this test."); @@ -43,12 +43,14 @@ assertEquals(1, f(o)); // Mark for concurrent optimization. %OptimizeFunctionOnNextCall(f, "concurrent"); -// Trigger optimization in the background thread. +// Kick off recompilation. assertEquals(1, f(o)); -// While concurrent recompilation is running, optimization not yet done. -assertUnoptimized(f, "no sync"); -// Change the prototype chain during optimization to trigger map invalidation. +// Change the prototype chain after compile graph has been created. o.__proto__.__proto__ = { bar: function() { return 2; } }; +// At this point, concurrent recompilation thread has not yet done its job. +assertUnoptimized(f, "no sync"); +// Let the background thread proceed. +%UnblockConcurrentRecompilation(); // Optimization eventually bails out due to map dependency. assertUnoptimized(f, "sync"); assertEquals(2, f(o)); diff --git a/test/mjsunit/manual-parallel-recompile.js b/test/mjsunit/compiler/manual-concurrent-recompile.js similarity index 87% rename from test/mjsunit/manual-parallel-recompile.js rename to test/mjsunit/compiler/manual-concurrent-recompile.js index 0a0e61d524..b2b63988ba 100644 --- a/test/mjsunit/manual-parallel-recompile.js +++ b/test/mjsunit/compiler/manual-concurrent-recompile.js @@ -26,7 +26,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Flags: --allow-natives-syntax --expose-gc -// Flags: --concurrent-recompilation --concurrent-recompilation-delay=50 +// Flags: --concurrent-recompilation --block-concurrent-recompilation if (!%IsConcurrentRecompilationSupported()) { print("Concurrent recompilation is disabled. Skipping this test."); @@ -55,10 +55,13 @@ assertUnoptimized(g); %OptimizeFunctionOnNextCall(f, "concurrent"); %OptimizeFunctionOnNextCall(g, "concurrent"); -f(g(2)); // Trigger optimization. +f(g(2)); // Kick off recompilation. -assertUnoptimized(f, "no sync"); // Not yet optimized while background thread -assertUnoptimized(g, "no sync"); // is running. +assertUnoptimized(f, "no sync"); // Not yet optimized since recompilation +assertUnoptimized(g, "no sync"); // is still blocked. + +// Let concurrent recompilation proceed. +%UnblockConcurrentRecompilation(); assertOptimized(f, "sync"); // Optimized once we sync with the assertOptimized(g, "sync"); // background thread. diff --git a/test/mjsunit/parallel-initial-prototype-change.js b/test/mjsunit/concurrent-initial-prototype-change.js similarity index 86% rename from test/mjsunit/parallel-initial-prototype-change.js rename to test/mjsunit/concurrent-initial-prototype-change.js index 625b590fcc..d5b1b99491 100644 --- a/test/mjsunit/parallel-initial-prototype-change.js +++ b/test/mjsunit/concurrent-initial-prototype-change.js @@ -26,7 +26,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Flags: --allow-natives-syntax -// Flags: --concurrent-recompilation --concurrent-recompilation-delay=100 +// Flags: --concurrent-recompilation --block-concurrent-recompilation if (!%IsConcurrentRecompilationSupported()) { print("Concurrent recompilation is disabled. Skipping this test."); @@ -43,12 +43,15 @@ assertEquals(0.5, f1(arr, 0)); // Optimized code of f1 depends on initial object and array maps. %OptimizeFunctionOnNextCall(f1, "concurrent"); -// Trigger optimization in the background thread +// Kick off recompilation; assertEquals(0.5, f1(arr, 0)); -Object.prototype[1] = 1.5; // Invalidate current initial object map. +// Invalidate current initial object map after compile graph has been created. +Object.prototype[1] = 1.5; assertEquals(2, f1(arr, 1)); -// Not yet optimized while background thread is running. +// Not yet optimized since concurrent recompilation is blocked. assertUnoptimized(f1, "no sync"); +// Let concurrent recompilation proceed. +%UnblockConcurrentRecompilation(); // Sync with background thread to conclude optimization, which bails out // due to map dependency. assertUnoptimized(f1, "sync"); diff --git a/test/mjsunit/regress/regress-embedded-cons-string.js b/test/mjsunit/regress/regress-embedded-cons-string.js index 32b900b15b..b08a94257c 100644 --- a/test/mjsunit/regress/regress-embedded-cons-string.js +++ b/test/mjsunit/regress/regress-embedded-cons-string.js @@ -27,7 +27,7 @@ // Flags: --fold-constants --nodead-code-elimination // Flags: --expose-gc --allow-natives-syntax -// Flags: --concurrent-recompilation --concurrent-recompilation-delay=600 +// Flags: --concurrent-recompilation --block-concurrent-recompilation if (!%IsConcurrentRecompilationSupported()) { print("Concurrent recompilation is disabled. Skipping this test."); @@ -39,12 +39,14 @@ function test(fun) { fun(); // Mark for concurrent optimization. %OptimizeFunctionOnNextCall(fun, "concurrent"); - //Trigger optimization in the background. + // Kick off recompilation. fun(); - //Tenure cons string. + // Tenure cons string after compile graph has been created. gc(); - // In the mean time, concurrent recompiling is not complete yet. + // In the mean time, concurrent recompiling is still blocked. assertUnoptimized(fun, "no sync"); + // Let concurrent recompilation proceed. + %UnblockConcurrentRecompilation(); // Concurrent recompilation eventually finishes, embeds tenured cons string. assertOptimized(fun, "sync"); // Visit embedded cons string during mark compact. diff --git a/test/mjsunit/regress/regress-opt-after-debug-deopt.js b/test/mjsunit/regress/regress-opt-after-debug-deopt.js index 8bf95ec5aa..c637be5497 100644 --- a/test/mjsunit/regress/regress-opt-after-debug-deopt.js +++ b/test/mjsunit/regress/regress-opt-after-debug-deopt.js @@ -26,7 +26,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Flags: --expose-debug-as debug --allow-natives-syntax -// Flags: --concurrent-recompilation --concurrent-recompilation-delay=100 +// Flags: --concurrent-recompilation --block-concurrent-recompilation if (!%IsConcurrentRecompilationSupported()) { print("Concurrent recompilation is disabled. Skipping this test."); @@ -60,8 +60,14 @@ f(); %OptimizeFunctionOnNextCall(f, "concurrent"); // Mark with builtin. f(); // Kick off concurrent recompilation. +// After compile graph has been created... Debug.setListener(listener); // Activate debugger. Debug.setBreakPoint(f, 2, 0); // Force deopt. + +// At this point, concurrent recompilation is still being blocked. +assertUnoptimized(f, "no sync"); +// Let concurrent recompilation proceed. +%UnblockConcurrentRecompilation(); // Sync with optimization thread. But no optimized code is installed. assertUnoptimized(f, "sync"); diff --git a/test/mjsunit/regress/regress-prepare-break-while-recompile.js b/test/mjsunit/regress/regress-prepare-break-while-recompile.js index 2fad5ca0d2..a9c20ec844 100644 --- a/test/mjsunit/regress/regress-prepare-break-while-recompile.js +++ b/test/mjsunit/regress/regress-prepare-break-while-recompile.js @@ -26,7 +26,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Flags: --expose-debug-as debug --allow-natives-syntax -// Flags: --concurrent-recompilation-delay=300 +// Flags: --block-concurrent-recompilation if (!%IsConcurrentRecompilationSupported()) { print("Concurrent recompilation is disabled. Skipping this test."); @@ -46,17 +46,22 @@ function bar() { } foo(); -// Mark and trigger concurrent optimization. +// Mark and kick off recompilation. %OptimizeFunctionOnNextCall(foo, "concurrent"); foo(); // Set break points on an unrelated function. This clears both optimized // and (shared) unoptimized code on foo, and sets both to lazy-compile builtin. // Clear the break point immediately after to deactivate the debugger. +// Do all of this after compile graph has been created. Debug.setBreakPoint(bar, 0, 0); Debug.clearAllBreakPoints(); +// At this point, concurrent recompilation is still blocked. +assertUnoptimized(foo, "no sync"); +// Let concurrent recompilation proceed. +%UnblockConcurrentRecompilation(); + // Install optimized code when concurrent optimization finishes. // This needs to be able to deal with shared code being a builtin. assertUnoptimized(foo, "sync"); -