Revision: 5955
Author: [email protected]
Date: Thu Dec  9 05:12:23 2010
Log: Collect only optimizable function samples.

Keep track of the ratio between JS and non-JS ticks and use this ratio to adjust the lookup threshold. (Also add support to trace compilation statistics.)


Review URL: http://codereview.chromium.org/5633009
http://code.google.com/p/v8/source/detail?r=5955

Modified:
 /branches/bleeding_edge/src/compiler.cc
 /branches/bleeding_edge/src/flag-definitions.h
 /branches/bleeding_edge/src/runtime-profiler.cc

=======================================
--- /branches/bleeding_edge/src/compiler.cc     Tue Dec  7 06:03:59 2010
+++ /branches/bleeding_edge/src/compiler.cc     Thu Dec  9 05:12:23 2010
@@ -116,13 +116,26 @@
static void FinishOptimization(Handle<JSFunction> function, int64_t start) {
   int opt_count = function->shared()->opt_count();
   function->shared()->set_opt_count(opt_count + 1);
-  if (!FLAG_trace_opt) return;
-
   double ms = static_cast<double>(OS::Ticks() - start) / 1000;
-  PrintF("[optimizing: ");
-  function->PrintName();
-  PrintF(" / %" V8PRIxPTR, reinterpret_cast<intptr_t>(*function));
-  PrintF(" - took %0.3f ms]\n", ms);
+  if (FLAG_trace_opt) {
+    PrintF("[optimizing: ");
+    function->PrintName();
+    PrintF(" / %" V8PRIxPTR, reinterpret_cast<intptr_t>(*function));
+    PrintF(" - took %0.3f ms]\n", ms);
+  }
+  if (FLAG_trace_opt_stats) {
+    static double compilation_time = 0.0;
+    static int compiled_functions = 0;
+    static int code_size = 0;
+
+    compilation_time += ms;
+    compiled_functions++;
+    code_size += function->shared()->SourceSize();
+    PrintF("Compiled: %d functions with %d byte source size in %fms.\n",
+           compiled_functions,
+           code_size,
+           compilation_time);
+  }
 }


=======================================
--- /branches/bleeding_edge/src/flag-definitions.h      Tue Dec  7 05:24:22 2010
+++ /branches/bleeding_edge/src/flag-definitions.h      Thu Dec  9 05:12:23 2010
@@ -194,6 +194,7 @@
 // codegen.cc
 DEFINE_bool(lazy, true, "use lazy compilation")
 DEFINE_bool(trace_opt, false, "trace lazy optimization")
+DEFINE_bool(trace_opt_stats, false, "trace lazy optimization statistics")
 DEFINE_bool(opt, true, "use adaptive optimizations")
 DEFINE_bool(opt_eagerly, false, "be more eager when adaptively optimizing")
 DEFINE_bool(always_opt, false, "always try to optimize functions")
=======================================
--- /branches/bleeding_edge/src/runtime-profiler.cc     Tue Dec  7 03:40:36 2010
+++ /branches/bleeding_edge/src/runtime-profiler.cc     Thu Dec  9 05:12:23 2010
@@ -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
@@ -267,27 +278,57 @@
        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[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));
     }
   }

@@ -341,6 +382,8 @@

 void RuntimeProfiler::Reset() {
   sampler_threshold = kSamplerThresholdInit;
+  sampler_ticks_until_threshold_adjustment =
+      kSamplerTicksBetweenThresholdAdjustment;
   sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit;
 }

@@ -358,6 +401,24 @@
 int RuntimeProfiler::SamplerWindowSize() {
   return kSamplerWindowSize;
 }
+
+
+static void AddStateSample(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);
+}


 bool RuntimeProfilerRateLimiter::SuspendIfNecessary() {
@@ -369,8 +430,10 @@
       !CpuProfiler::is_profiling() &&
       !(FLAG_prof && FLAG_prof_auto)) {
     if (Top::IsInJSState()) {
+      AddStateSample(IN_JS_STATE);
       non_js_ticks_ = 0;
     } else {
+      AddStateSample(IN_NON_JS_STATE);
       if (non_js_ticks_ < kNonJSTicksThreshold) {
         ++non_js_ticks_;
       } else {

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to