Introduce helper functions to test parallel recompilation.
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 16 Nov 2012 10:57:50 +0000 (10:57 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 16 Nov 2012 10:57:50 +0000 (10:57 +0000)
BUG=

Review URL: https://chromiumcodereview.appspot.com/11419012

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12986 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/execution.cc
src/flag-definitions.h
src/optimizing-compiler-thread.cc
src/optimizing-compiler-thread.h
src/runtime-profiler.cc
src/runtime.cc
src/runtime.h
test/mjsunit/manual-parallel-recompile.js [new file with mode: 0644]

index 89091ba..8942fb3 100644 (file)
@@ -937,7 +937,8 @@ MaybeObject* Execution::HandleStackGuardInterrupt(Isolate* isolate) {
     }
     stack_guard->Continue(CODE_READY);
   }
-  if (!stack_guard->IsTerminateExecution()) {
+  if (!stack_guard->IsTerminateExecution() &&
+      !FLAG_manual_parallel_recompilation) {
     isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
   }
 
index 807fc08..69692c4 100644 (file)
@@ -225,7 +225,7 @@ DEFINE_int(loop_weight, 1, "loop weight for representation inference")
 DEFINE_bool(optimize_for_in, true,
             "optimize functions containing for-in loops")
 DEFINE_bool(opt_safe_uint32_operations, true,
-            "allow uint32 values on optimize frames if they are used only in"
+            "allow uint32 values on optimize frames if they are used only in "
             "safe operations")
 
 DEFINE_bool(parallel_recompilation, false,
@@ -233,6 +233,9 @@ DEFINE_bool(parallel_recompilation, false,
 DEFINE_bool(trace_parallel_recompilation, false, "track parallel recompilation")
 DEFINE_int(parallel_recompilation_queue_length, 2,
            "the length of the parallel compilation queue")
+DEFINE_bool(manual_parallel_recompilation, false,
+            "disable automatic optimization")
+DEFINE_implication(manual_parallel_recompilation, parallel_recompilation)
 
 // Experimental profiler changes.
 DEFINE_bool(experimental_profiler, true, "enable all profiler experiments")
index 06018dd..48ee12c 100644 (file)
@@ -72,7 +72,13 @@ void OptimizingCompilerThread::Run() {
     USE(status);
 
     output_queue_.Enqueue(optimizing_compiler);
-    isolate_->stack_guard()->RequestCodeReadyEvent();
+    if (!FLAG_manual_parallel_recompilation) {
+      isolate_->stack_guard()->RequestCodeReadyEvent();
+    } else {
+      // In manual mode, do not trigger a code ready event.
+      // Instead, wait for the optimized functions to be installed manually.
+      output_queue_semaphore_->Signal();
+    }
 
     if (FLAG_trace_parallel_recompilation) {
       time_spent_compiling_ += OS::Ticks() - compiling_start;
@@ -99,6 +105,9 @@ void OptimizingCompilerThread::InstallOptimizedFunctions() {
   HandleScope handle_scope(isolate_);
   int functions_installed = 0;
   while (!output_queue_.IsEmpty()) {
+    if (FLAG_manual_parallel_recompilation) {
+      output_queue_semaphore_->Wait();
+    }
     OptimizingCompiler* compiler = NULL;
     output_queue_.Dequeue(&compiler);
     Compiler::InstallOptimizedCode(compiler);
@@ -110,6 +119,17 @@ void OptimizingCompilerThread::InstallOptimizedFunctions() {
 }
 
 
+Handle<SharedFunctionInfo>
+    OptimizingCompilerThread::InstallNextOptimizedFunction() {
+  ASSERT(FLAG_manual_parallel_recompilation);
+  output_queue_semaphore_->Wait();
+  OptimizingCompiler* compiler = NULL;
+  output_queue_.Dequeue(&compiler);
+  Compiler::InstallOptimizedCode(compiler);
+  return compiler->info()->shared_info();
+}
+
+
 void OptimizingCompilerThread::QueueForOptimization(
     OptimizingCompiler* optimizing_compiler) {
   input_queue_.Enqueue(optimizing_compiler);
index d562726..8a39b39 100644 (file)
@@ -29,8 +29,8 @@
 #define V8_OPTIMIZING_COMPILER_THREAD_H_
 
 #include "atomicops.h"
-#include "platform.h"
 #include "flags.h"
+#include "platform.h"
 #include "unbound-queue.h"
 
 namespace v8 {
@@ -38,6 +38,7 @@ namespace internal {
 
 class HGraphBuilder;
 class OptimizingCompiler;
+class SharedFunctionInfo;
 
 class OptimizingCompilerThread : public Thread {
  public:
@@ -46,6 +47,7 @@ class OptimizingCompilerThread : public Thread {
       isolate_(isolate),
       stop_semaphore_(OS::CreateSemaphore(0)),
       input_queue_semaphore_(OS::CreateSemaphore(0)),
+      output_queue_semaphore_(OS::CreateSemaphore(0)),
       time_spent_compiling_(0),
       time_spent_total_(0) {
     NoBarrier_Store(&stop_thread_, static_cast<AtomicWord>(false));
@@ -57,6 +59,9 @@ class OptimizingCompilerThread : public Thread {
   void QueueForOptimization(OptimizingCompiler* optimizing_compiler);
   void InstallOptimizedFunctions();
 
+  // Wait for the next optimized function and install it.
+  Handle<SharedFunctionInfo> InstallNextOptimizedFunction();
+
   inline bool IsQueueAvailable() {
     // We don't need a barrier since we have a data dependency right
     // after.
@@ -77,6 +82,7 @@ class OptimizingCompilerThread : public Thread {
 
   ~OptimizingCompilerThread() {
     delete input_queue_semaphore_;
+    delete output_queue_semaphore_;  // Only used for manual mode.
     delete stop_semaphore_;
   }
 
@@ -84,6 +90,7 @@ class OptimizingCompilerThread : public Thread {
   Isolate* isolate_;
   Semaphore* stop_semaphore_;
   Semaphore* input_queue_semaphore_;
+  Semaphore* output_queue_semaphore_;
   UnboundQueue<OptimizingCompiler*> input_queue_;
   UnboundQueue<OptimizingCompiler*> output_queue_;
   volatile AtomicWord stop_thread_;
index 23f41fa..5b27333 100644 (file)
@@ -140,6 +140,9 @@ static void GetICCounts(JSFunction* function,
 
 void RuntimeProfiler::Optimize(JSFunction* function, const char* reason) {
   ASSERT(function->IsOptimizable());
+  // If we are in manual mode, don't auto-optimize anything.
+  if (FLAG_manual_parallel_recompilation) return;
+
   if (FLAG_trace_opt) {
     PrintF("[marking ");
     function->PrintName();
index bd2a7a2..323508a 100644 (file)
@@ -7990,7 +7990,36 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ParallelRecompile) {
   HandleScope handle_scope(isolate);
   ASSERT(FLAG_parallel_recompilation);
   Compiler::RecompileParallel(args.at<JSFunction>(0));
-  return *isolate->factory()->undefined_value();
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ForceParallelRecompile) {
+  HandleScope handle_scope(isolate);
+  ASSERT(FLAG_parallel_recompilation && FLAG_manual_parallel_recompilation);
+  if (!isolate->optimizing_compiler_thread()->IsQueueAvailable()) {
+    return isolate->Throw(
+        *isolate->factory()->LookupAsciiSymbol("Recompile queue is full."));
+  }
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
+  fun->ReplaceCode(isolate->builtins()->builtin(Builtins::kParallelRecompile));
+  Compiler::RecompileParallel(fun);
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_InstallRecompiledCode) {
+  HandleScope handle_scope(isolate);
+  ASSERT(FLAG_parallel_recompilation && FLAG_manual_parallel_recompilation);
+  CONVERT_ARG_HANDLE_CHECKED(HeapObject, arg, 0);
+  OptimizingCompilerThread* opt_thread = isolate->optimizing_compiler_thread();
+  if (!arg->IsJSFunction()) {
+    opt_thread->InstallOptimizedFunctions();
+  } else if (!JSFunction::cast(*arg)->IsOptimized()) {
+    Handle<SharedFunctionInfo> shared(JSFunction::cast(*arg)->shared());
+    while (*opt_thread->InstallNextOptimizedFunction() != *shared) { }
+  }
+  return isolate->heap()->undefined_value();
 }
 
 
index caed34b..146b8dc 100644 (file)
@@ -85,7 +85,9 @@ namespace internal {
   F(NewStrictArgumentsFast, 3, 1) \
   F(LazyCompile, 1, 1) \
   F(LazyRecompile, 1, 1) \
-  F(ParallelRecompile, 1, 1)     \
+  F(ParallelRecompile, 1, 1) \
+  F(ForceParallelRecompile, 1, 1) \
+  F(InstallRecompiledCode, 1, 1) \
   F(NotifyDeoptimized, 1, 1) \
   F(NotifyOSR, 0, 1) \
   F(DeoptimizeFunction, 1, 1) \
diff --git a/test/mjsunit/manual-parallel-recompile.js b/test/mjsunit/manual-parallel-recompile.js
new file mode 100644 (file)
index 0000000..7eb2696
--- /dev/null
@@ -0,0 +1,80 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --expose-gc
+// Flags: --parallel-recompilation --manual-parallel-recompilation
+
+function assertOptimized(fun) {
+  // This assertion takes --always-opt and --nocrankshaft flags into account.
+  assertTrue(%GetOptimizationStatus(fun) != 2);
+}
+
+function assertUnoptimized(fun) {
+  assertTrue(%GetOptimizationStatus(fun) != 1);
+}
+
+function f(x) {
+  var xx = x * x;
+  var xxstr = xx.toString();
+  return xxstr.length;
+}
+
+function g(x) {
+  var xxx = Math.sqrt(x) | 0;
+  var xxxstr = xxx.toString();
+  return xxxstr.length;
+}
+
+function k(x) {
+  return x * x;
+}
+
+f(g(1));
+f(g(2));
+assertUnoptimized(f);
+assertUnoptimized(g);
+
+%ForceParallelRecompile(f);
+%ForceParallelRecompile(g);
+assertUnoptimized(f);
+assertUnoptimized(g);
+
+var sum = 0;
+for (var i = 0; i < 10000; i++) sum += f(i) + g(i);
+gc();
+
+assertEquals(95274, sum);
+assertUnoptimized(f);
+assertUnoptimized(g);
+
+%InstallRecompiledCode(f);
+assertOptimized(f);
+assertUnoptimized(g);
+
+%InstallRecompiledCode("the rest");
+assertOptimized(g);
+