Revision: 8472
Author:   [email protected]
Date:     Wed Jun 29 07:56:08 2011
Log:      Suspend runtime profiler as soon as we exit JS.

Lots of web pages have really frequently firing timers that keep the
profiler thread spinning if we require a period of JS inactivity
before suspending the profiler. While it's possible to throttle it by
increasing the sleep delay and adjusting the duration of the required
inactive period, it seemed much simpler to just stop it immediately on
exiting JS.

Stopping the profiler this way effectively turned off two optimization
heuristics: 1) eager optimization (it's reset on waking up the
profiler and now the profiler wakes up much more frequently) and 2)
optimization throttling based on JS to non-JS state ratio (the ratio
is now 100%). I removed these two heuristics and found no performance
regressions so far.

[email protected]
BUG=crbug.com/77625
TEST=none

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

Modified:
 /branches/bleeding_edge/src/compilation-cache.cc
 /branches/bleeding_edge/src/compilation-cache.h
 /branches/bleeding_edge/src/compiler.cc
 /branches/bleeding_edge/src/isolate.cc
 /branches/bleeding_edge/src/isolate.h
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/runtime-profiler.cc
 /branches/bleeding_edge/src/runtime-profiler.h
 /branches/bleeding_edge/src/runtime.cc

=======================================
--- /branches/bleeding_edge/src/compilation-cache.cc Mon Mar 21 03:22:57 2011 +++ /branches/bleeding_edge/src/compilation-cache.cc Wed Jun 29 07:56:08 2011
@@ -52,8 +52,7 @@
       eval_global_(isolate, kEvalGlobalGenerations),
       eval_contextual_(isolate, kEvalContextualGenerations),
       reg_exp_(isolate, kRegExpGenerations),
-      enabled_(true),
-      eager_optimizing_set_(NULL) {
+      enabled_(true) {
   CompilationSubCache* subcaches[kSubCacheCount] =
     {&script_, &eval_global_, &eval_contextual_, &reg_exp_};
   for (int i = 0; i < kSubCacheCount; ++i) {
@@ -62,10 +61,7 @@
 }


-CompilationCache::~CompilationCache() {
-  delete eager_optimizing_set_;
-  eager_optimizing_set_ = NULL;
-}
+CompilationCache::~CompilationCache() {}


static Handle<CompilationCacheTable> AllocateTable(Isolate* isolate, int size) {
@@ -455,47 +451,6 @@

   reg_exp_.Put(source, flags, data);
 }
-
-
-static bool SourceHashCompare(void* key1, void* key2) {
-  return key1 == key2;
-}
-
-
-HashMap* CompilationCache::EagerOptimizingSet() {
-  if (eager_optimizing_set_ == NULL) {
-    eager_optimizing_set_ = new HashMap(&SourceHashCompare);
-  }
-  return eager_optimizing_set_;
-}
-
-
-bool CompilationCache::ShouldOptimizeEagerly(Handle<JSFunction> function) {
-  if (FLAG_opt_eagerly) return true;
-  uint32_t hash = function->SourceHash();
-  void* key = reinterpret_cast<void*>(hash);
-  return EagerOptimizingSet()->Lookup(key, hash, false) != NULL;
-}
-
-
-void CompilationCache::MarkForEagerOptimizing(Handle<JSFunction> function) {
-  uint32_t hash = function->SourceHash();
-  void* key = reinterpret_cast<void*>(hash);
-  EagerOptimizingSet()->Lookup(key, hash, true);
-}
-
-
-void CompilationCache::MarkForLazyOptimizing(Handle<JSFunction> function) {
-  uint32_t hash = function->SourceHash();
-  void* key = reinterpret_cast<void*>(hash);
-  EagerOptimizingSet()->Remove(key, hash);
-}
-
-
-void CompilationCache::ResetEagerOptimizingData() {
-  HashMap* set = EagerOptimizingSet();
-  if (set->occupancy() > 0) set->Clear();
-}


 void CompilationCache::Clear() {
=======================================
--- /branches/bleeding_edge/src/compilation-cache.h     Mon Mar 21 03:22:57 2011
+++ /branches/bleeding_edge/src/compilation-cache.h     Wed Jun 29 07:56:08 2011
@@ -223,14 +223,6 @@
                  JSRegExp::Flags flags,
                  Handle<FixedArray> data);

-  // Support for eager optimization tracking.
-  bool ShouldOptimizeEagerly(Handle<JSFunction> function);
-  void MarkForEagerOptimizing(Handle<JSFunction> function);
-  void MarkForLazyOptimizing(Handle<JSFunction> function);
-
-  // Reset the eager optimization tracking data.
-  void ResetEagerOptimizingData();
-
   // Clear the cache - also used to initialize the cache at startup.
   void Clear();

@@ -274,8 +266,6 @@
   // Current enable state of the compilation cache.
   bool enabled_;

-  HashMap* eager_optimizing_set_;
-
   friend class Isolate;

   DISALLOW_COPY_AND_ASSIGN(CompilationCache);
=======================================
--- /branches/bleeding_edge/src/compiler.cc     Wed Jun 29 06:02:00 2011
+++ /branches/bleeding_edge/src/compiler.cc     Wed Jun 29 07:56:08 2011
@@ -109,8 +109,6 @@
 void CompilationInfo::AbortOptimization() {
   Handle<Code> code(shared_info()->code());
   SetCode(code);
-  Isolate* isolate = code->GetIsolate();
-  isolate->compilation_cache()->MarkForLazyOptimizing(closure());
 }


@@ -660,9 +658,6 @@
             CompilationInfo optimized(function);
             optimized.SetOptimizing(AstNode::kNoNumber);
             return CompileLazy(&optimized);
-          } else if (isolate->compilation_cache()->ShouldOptimizeEagerly(
-              function)) {
-            isolate->runtime_profiler()->OptimizeSoon(*function);
           }
         }
       }
=======================================
--- /branches/bleeding_edge/src/isolate.cc      Fri Jun 24 04:38:47 2011
+++ /branches/bleeding_edge/src/isolate.cc      Wed Jun 29 07:56:08 2011
@@ -1853,11 +1853,6 @@
// Reinit the current thread for the isolate it was running before this one.
   SetIsolateThreadLocals(previous_isolate, previous_thread_data);
 }
-
-
-void Isolate::ResetEagerOptimizingData() {
-  compilation_cache_->ResetEagerOptimizingData();
-}


 #ifdef DEBUG
=======================================
--- /branches/bleeding_edge/src/isolate.h       Fri Jun 24 04:38:47 2011
+++ /branches/bleeding_edge/src/isolate.h       Wed Jun 29 07:56:08 2011
@@ -978,8 +978,6 @@
   }
 #endif

-  void ResetEagerOptimizingData();
-
   void SetData(void* data) { embedder_data_ = data; }
   void* GetData() { return embedder_data_; }

=======================================
--- /branches/bleeding_edge/src/objects.cc      Wed Jun 29 06:17:02 2011
+++ /branches/bleeding_edge/src/objects.cc      Wed Jun 29 07:56:08 2011
@@ -6285,19 +6285,6 @@
   Builtins* builtins = GetIsolate()->builtins();
   ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
 }
-
-
-uint32_t JSFunction::SourceHash() {
-  uint32_t hash = 0;
-  Object* script = shared()->script();
-  if (!script->IsUndefined()) {
-    Object* source = Script::cast(script)->source();
-    if (source->IsUndefined()) hash = String::cast(source)->Hash();
-  }
-  hash ^= ComputeIntegerHash(shared()->start_position_and_type());
-  hash += ComputeIntegerHash(shared()->end_position());
-  return hash;
-}


 bool JSFunction::IsInlineable() {
=======================================
--- /branches/bleeding_edge/src/objects.h       Wed Jun 29 06:17:02 2011
+++ /branches/bleeding_edge/src/objects.h       Wed Jun 29 07:56:08 2011
@@ -4924,9 +4924,6 @@
   // recompilation.
   inline bool IsMarkedForLazyRecompilation();

-  // Compute a hash code for the source code of this function.
-  uint32_t SourceHash();
-
   // Check whether or not this function is inlineable.
   bool IsInlineable();

=======================================
--- /branches/bleeding_edge/src/runtime-profiler.cc     Thu Jun 16 07:12:58 2011
+++ /branches/bleeding_edge/src/runtime-profiler.cc     Wed Jun 29 07:56:08 2011
@@ -43,32 +43,6 @@
 namespace internal {


-class PendingListNode : public Malloced {
- public:
-  explicit PendingListNode(JSFunction* function);
-  ~PendingListNode() { Destroy(); }
-
-  PendingListNode* next() const { return next_; }
-  void set_next(PendingListNode* node) { next_ = node; }
- Handle<JSFunction> function() { return Handle<JSFunction>::cast(function_); }
-
-  // If the function is garbage collected before we've had the chance
-  // to optimize it the weak handle will be null.
-  bool IsValid() { return !function_.is_null(); }
-
-  // Returns the number of microseconds this node has been pending.
-  int Delay() const { return static_cast<int>(OS::Ticks() - start_); }
-
- private:
-  void Destroy();
-  static void WeakCallback(v8::Persistent<v8::Value> object, void* data);
-
-  PendingListNode* next_;
-  Handle<Object> function_;  // Weak handle.
-  int64_t start_;
-};
-
-
 // Optimization sampler constants.
 static const int kSamplerFrameCount = 2;
 static const int kSamplerFrameWeight[kSamplerFrameCount] = { 2, 1 };
@@ -80,33 +54,10 @@
 static const int kSamplerThresholdDelta = 1;

 static const int kSamplerThresholdSizeFactorInit = 3;
-static const int kSamplerThresholdSizeFactorMin = 1;
-static const int kSamplerThresholdSizeFactorDelta = 1;

 static const int kSizeLimit = 1500;


-PendingListNode::PendingListNode(JSFunction* function) : next_(NULL) {
-  GlobalHandles* global_handles = Isolate::Current()->global_handles();
-  function_ = global_handles->Create(function);
-  start_ = OS::Ticks();
-  global_handles->MakeWeak(function_.location(), this, &WeakCallback);
-}
-
-
-void PendingListNode::Destroy() {
-  if (!IsValid()) return;
-  GlobalHandles* global_handles = Isolate::Current()->global_handles();
-  global_handles->Destroy(function_.location());
-  function_= Handle<Object>::null();
-}
-
-
-void PendingListNode::WeakCallback(v8::Persistent<v8::Value>, void* data) {
-  reinterpret_cast<PendingListNode*>(data)->Destroy();
-}
-
-
 Atomic32 RuntimeProfiler::state_ = 0;
 // TODO(isolates): Create the semaphore lazily and clean it up when no
 // longer required.
@@ -125,16 +76,8 @@
       sampler_threshold_(kSamplerThresholdInit),
       sampler_threshold_size_factor_(kSamplerThresholdSizeFactorInit),
       sampler_ticks_until_threshold_adjustment_(
-        kSamplerTicksBetweenThresholdAdjustment),
-      js_ratio_(0),
-      sampler_window_position_(0),
-      optimize_soon_list_(NULL),
-      state_window_position_(0),
-      state_window_ticks_(0) {
-  state_counts_[IN_NON_JS_STATE] = kStateWindowSize;
-  state_counts_[IN_JS_STATE] = 0;
-  STATIC_ASSERT(IN_NON_JS_STATE == 0);
-  memset(state_window_, 0, sizeof(state_window_));
+          kSamplerTicksBetweenThresholdAdjustment),
+      sampler_window_position_(0) {
   ClearSampleBuffer();
 }

@@ -148,16 +91,13 @@
 }


-void RuntimeProfiler::Optimize(JSFunction* function, bool eager, int delay) {
+void RuntimeProfiler::Optimize(JSFunction* function) {
   ASSERT(function->IsOptimizable());
   if (FLAG_trace_opt) {
-    PrintF("[marking (%s) ", eager ? "eagerly" : "lazily");
+    PrintF("[marking ");
     function->PrintName();
PrintF(" 0x%" V8PRIxPTR, reinterpret_cast<intptr_t>(function->address()));
     PrintF(" for recompilation");
-    if (delay > 0) {
-      PrintF(" (delayed %0.3f ms)", static_cast<double>(delay) / 1000);
-    }
     PrintF("]\n");
   }

@@ -243,20 +183,6 @@

 void RuntimeProfiler::OptimizeNow() {
   HandleScope scope(isolate_);
-  PendingListNode* current = optimize_soon_list_;
-  while (current != NULL) {
-    PendingListNode* next = current->next();
-    if (current->IsValid()) {
-      Handle<JSFunction> function = current->function();
-      int delay = current->Delay();
-      if (function->IsOptimizable()) {
-        Optimize(*function, true, delay);
-      }
-    }
-    delete current;
-    current = next;
-  }
-  optimize_soon_list_ = NULL;

   // Run through the JavaScript frames and collect them. If we already
   // have a sample of the function, we mark it for optimizations
@@ -303,24 +229,9 @@
         : 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);
-      isolate_->compilation_cache()->MarkForEagerOptimizing(
-          Handle<JSFunction>(function));
+      Optimize(function);
     }
   }

@@ -333,40 +244,8 @@
 }


-void RuntimeProfiler::OptimizeSoon(JSFunction* function) {
-  if (!function->IsOptimizable()) return;
-  PendingListNode* node = new PendingListNode(function);
-  node->set_next(optimize_soon_list_);
-  optimize_soon_list_ = node;
-}
-
-
-#ifdef ENABLE_LOGGING_AND_PROFILING
-void RuntimeProfiler::UpdateStateRatio(SamplerState current_state) {
-  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);
-  // Note: to calculate correct ratio we have to track how many valid
-  // ticks are actually in the state window, because on profiler
-  // startup this number can be less than the window size.
-  state_window_ticks_ = Min(kStateWindowSize, state_window_ticks_ + 1);
-  NoBarrier_Store(&js_ratio_, state_counts_[IN_JS_STATE] * 100 /
-                  state_window_ticks_);
-}
-#endif
-
-
 void RuntimeProfiler::NotifyTick() {
 #ifdef ENABLE_LOGGING_AND_PROFILING
-  // Record state sample.
-  SamplerState state = IsSomeIsolateInJS()
-      ? IN_JS_STATE
-      : IN_NON_JS_STATE;
-  UpdateStateRatio(state);
   isolate_->stack_guard()->RequestRuntimeProfilerTick();
 #endif
 }
@@ -424,7 +303,6 @@
   // to get the right count of active isolates.
   NoBarrier_AtomicIncrement(&state_, 1);
   semaphore_->Signal();
-  isolate->ResetEagerOptimizingData();
 #endif
 }

@@ -471,15 +349,8 @@

 bool RuntimeProfilerRateLimiter::SuspendIfNecessary() {
 #ifdef ENABLE_LOGGING_AND_PROFILING
-  static const int kNonJSTicksThreshold = 100;
-  if (RuntimeProfiler::IsSomeIsolateInJS()) {
-    non_js_ticks_ = 0;
-  } else {
-    if (non_js_ticks_ < kNonJSTicksThreshold) {
-      ++non_js_ticks_;
-    } else {
-      return RuntimeProfiler::WaitForSomeIsolateToEnterJS();
-    }
+  if (!RuntimeProfiler::IsSomeIsolateInJS()) {
+    return RuntimeProfiler::WaitForSomeIsolateToEnterJS();
   }
 #endif
   return false;
=======================================
--- /branches/bleeding_edge/src/runtime-profiler.h      Tue Apr 12 12:15:53 2011
+++ /branches/bleeding_edge/src/runtime-profiler.h      Wed Jun 29 07:56:08 2011
@@ -37,7 +37,6 @@
 class Isolate;
 class JSFunction;
 class Object;
-class PendingListNode;
 class Semaphore;

 class RuntimeProfiler {
@@ -52,7 +51,6 @@
   }

   void OptimizeNow();
-  void OptimizeSoon(JSFunction* function);

   void NotifyTick();

@@ -106,7 +104,7 @@

   static void HandleWakeUp(Isolate* isolate);

-  void Optimize(JSFunction* function, bool eager, int delay);
+  void Optimize(JSFunction* function);

   void AttemptOnStackReplacement(JSFunction* function);

@@ -118,31 +116,16 @@

   void AddSample(JSFunction* function, int weight);

-#ifdef ENABLE_LOGGING_AND_PROFILING
-  void UpdateStateRatio(SamplerState current_state);
-#endif
-
   Isolate* isolate_;

   int sampler_threshold_;
   int sampler_threshold_size_factor_;
   int sampler_ticks_until_threshold_adjustment_;

-  // The ratio of ticks spent in JS code in percent.
-  Atomic32 js_ratio_;
-
   Object* sampler_window_[kSamplerWindowSize];
   int sampler_window_position_;
   int sampler_window_weight_[kSamplerWindowSize];

-  // Support for pending 'optimize soon' requests.
-  PendingListNode* optimize_soon_list_;
-
-  SamplerState state_window_[kStateWindowSize];
-  int state_window_position_;
-  int state_window_ticks_;
-  int state_counts_[2];
-
   // Possible state values:
   //   -1            => the profiler thread is waiting on the semaphore
   //   0 or positive => the number of isolates running JavaScript code.
@@ -159,7 +142,7 @@
 // Rate limiter intended to be used in the profiler thread.
 class RuntimeProfilerRateLimiter BASE_EMBEDDED {
  public:
-  RuntimeProfilerRateLimiter() : non_js_ticks_(0) { }
+  RuntimeProfilerRateLimiter() {}

   // Suspends the current thread (which must be the profiler thread)
   // when not executing JavaScript to minimize CPU usage. Returns
@@ -170,8 +153,6 @@
   bool SuspendIfNecessary();

  private:
-  int non_js_ticks_;
-
   DISALLOW_COPY_AND_ASSIGN(RuntimeProfilerRateLimiter);
 };

=======================================
--- /branches/bleeding_edge/src/runtime.cc      Wed Jun 29 06:02:00 2011
+++ /branches/bleeding_edge/src/runtime.cc      Wed Jun 29 07:56:08 2011
@@ -7821,7 +7821,6 @@
     }
   }

-  isolate->compilation_cache()->MarkForLazyOptimizing(function);
   if (type == Deoptimizer::EAGER) {
     RUNTIME_ASSERT(function->IsOptimized());
   } else {

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

Reply via email to