Push version 3.0.3 to trunk.

Reapplied all changes for version 3.0.1.

Improved debugger protocol for remote debugging.

Added experimental support for using gyp to generate build files for V8.

Fixed implementation of String::Write in the API (issue 975).


git-svn-id: http://v8.googlecode.com/svn/trunk@6061 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/runtime-profiler.cc b/src/runtime-profiler.cc
index 051dc51..c53ddd2 100644
--- a/src/runtime-profiler.cc
+++ b/src/runtime-profiler.cc
@@ -68,12 +68,18 @@
 };
 
 
+enum SamplerState {
+  IN_NON_JS_STATE = 0,
+  IN_JS_STATE = 1
+};
+
+
 // Optimization sampler constants.
 static const int kSamplerFrameCount = 2;
 static const int kSamplerFrameWeight[kSamplerFrameCount] = { 2, 1 };
 static const int kSamplerWindowSize = 16;
 
-static const int kSamplerTicksDelta = 32;
+static const int kSamplerTicksBetweenThresholdAdjustment = 32;
 
 static const int kSamplerThresholdInit = 3;
 static const int kSamplerThresholdMin = 1;
@@ -88,6 +94,11 @@
 static int sampler_threshold = kSamplerThresholdInit;
 static int sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit;
 
+static int sampler_ticks_until_threshold_adjustment =
+    kSamplerTicksBetweenThresholdAdjustment;
+
+// The ratio of ticks spent in JS code in percent.
+static Atomic32 js_ratio;
 
 // The JSFunctions in the sampler window are not GC safe. Old-space
 // pointers are not cleared during mark-sweep collection and therefore
@@ -261,40 +272,71 @@
   // have a sample of the function, we mark it for optimizations
   // (eagerly or lazily).
   JSFunction* samples[kSamplerFrameCount];
-  int count = 0;
+  int sample_count = 0;
+  int frame_count = 0;
   for (JavaScriptFrameIterator it;
-       count < kSamplerFrameCount && !it.done();
+       frame_count++ < kSamplerFrameCount && !it.done();
        it.Advance()) {
     JavaScriptFrame* frame = it.frame();
     JSFunction* function = JSFunction::cast(frame->function());
-    int function_size = function->shared()->SourceSize();
-    int threshold_size_factor;
-    if (function_size > kSizeLimit) {
-      threshold_size_factor = sampler_threshold_size_factor;
-    } else {
-      threshold_size_factor = 1;
+
+    // Adjust threshold each time we have processed
+    // a certain number of ticks.
+    if (sampler_ticks_until_threshold_adjustment > 0) {
+      sampler_ticks_until_threshold_adjustment--;
+      if (sampler_ticks_until_threshold_adjustment <= 0) {
+        // If the threshold is not already at the minimum
+        // modify and reset the ticks until next adjustment.
+        if (sampler_threshold > kSamplerThresholdMin) {
+          sampler_threshold -= kSamplerThresholdDelta;
+          sampler_ticks_until_threshold_adjustment =
+              kSamplerTicksBetweenThresholdAdjustment;
+        }
+      }
     }
 
-    int threshold = sampler_threshold * threshold_size_factor;
-    samples[count++] = function;
     if (function->IsMarkedForLazyRecompilation()) {
       Code* unoptimized = function->shared()->code();
       int nesting = unoptimized->allow_osr_at_loop_nesting_level();
       if (nesting == 0) AttemptOnStackReplacement(function);
       int new_nesting = Min(nesting + 1, Code::kMaxLoopNestingMarker);
       unoptimized->set_allow_osr_at_loop_nesting_level(new_nesting);
-    } else if (LookupSample(function) >= threshold) {
-      if (IsOptimizable(function)) {
-        Optimize(function, false, 0);
-        CompilationCache::MarkForEagerOptimizing(Handle<JSFunction>(function));
-      }
+    }
+
+    // Do not record non-optimizable functions.
+    if (!IsOptimizable(function)) continue;
+    samples[sample_count++] = function;
+
+    int function_size = function->shared()->SourceSize();
+    int threshold_size_factor = (function_size > kSizeLimit)
+        ? sampler_threshold_size_factor
+        : 1;
+
+    int threshold = sampler_threshold * threshold_size_factor;
+    int current_js_ratio = NoBarrier_Load(&js_ratio);
+
+    // Adjust threshold depending on the ratio of time spent
+    // in JS code.
+    if (current_js_ratio < 20) {
+      // If we spend less than 20% of the time in JS code,
+      // do not optimize.
+      continue;
+    } else if (current_js_ratio < 75) {
+      // Below 75% of time spent in JS code, only optimize very
+      // frequently used functions.
+      threshold *= 3;
+    }
+
+    if (LookupSample(function) >= threshold) {
+      Optimize(function, false, 0);
+      CompilationCache::MarkForEagerOptimizing(Handle<JSFunction>(function));
     }
   }
 
   // Add the collected functions as samples. It's important not to do
   // this as part of collecting them because this will interfere with
   // the sample lookup in case of recursive functions.
-  for (int i = 0; i < count; i++) {
+  for (int i = 0; i < sample_count; i++) {
     AddSample(samples[i], kSamplerFrameWeight[i]);
   }
 }
@@ -308,8 +350,35 @@
 }
 
 
+#ifdef ENABLE_LOGGING_AND_PROFILING
+static void UpdateStateRatio(SamplerState current_state) {
+  static const int kStateWindowSize = 128;
+  static SamplerState state_window[kStateWindowSize];
+  static int state_window_position = 0;
+  static int state_counts[2] = { kStateWindowSize, 0 };
+
+  SamplerState old_state = state_window[state_window_position];
+  state_counts[old_state]--;
+  state_window[state_window_position] = current_state;
+  state_counts[current_state]++;
+  ASSERT(IsPowerOf2(kStateWindowSize));
+  state_window_position = (state_window_position + 1) &
+      (kStateWindowSize - 1);
+  NoBarrier_Store(&js_ratio, state_counts[IN_JS_STATE] * 100 /
+                  kStateWindowSize);
+}
+#endif
+
+
 void RuntimeProfiler::NotifyTick() {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  // Record state sample.
+  SamplerState state = Top::IsInJSState()
+      ? IN_JS_STATE
+      : IN_NON_JS_STATE;
+  UpdateStateRatio(state);
   StackGuard::RequestRuntimeProfilerTick();
+#endif
 }
 
 
@@ -341,6 +410,8 @@
 
 void RuntimeProfiler::Reset() {
   sampler_threshold = kSamplerThresholdInit;
+  sampler_ticks_until_threshold_adjustment =
+      kSamplerTicksBetweenThresholdAdjustment;
   sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit;
 }
 
@@ -361,6 +432,7 @@
 
 
 bool RuntimeProfilerRateLimiter::SuspendIfNecessary() {
+#ifdef ENABLE_LOGGING_AND_PROFILING
   static const int kNonJSTicksThreshold = 100;
   // We suspend the runtime profiler thread when not running
   // JavaScript. If the CPU profiler is active we must not do this
@@ -378,6 +450,7 @@
       }
     }
   }
+#endif
   return false;
 }