Home | History | Annotate | Download | only in src
      1 // Copyright 2010 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #ifndef V8_RUNTIME_PROFILER_H_
     29 #define V8_RUNTIME_PROFILER_H_
     30 
     31 #include "allocation.h"
     32 #include "atomicops.h"
     33 
     34 namespace v8 {
     35 namespace internal {
     36 
     37 class Isolate;
     38 class JSFunction;
     39 class Object;
     40 class PendingListNode;
     41 class Semaphore;
     42 
     43 class RuntimeProfiler {
     44  public:
     45   explicit RuntimeProfiler(Isolate* isolate);
     46 
     47   static void GlobalSetup();
     48 
     49   static inline bool IsEnabled() {
     50     ASSERT(has_been_globally_setup_);
     51     return enabled_;
     52   }
     53 
     54   void OptimizeNow();
     55   void OptimizeSoon(JSFunction* function);
     56 
     57   void NotifyTick();
     58 
     59   void Setup();
     60   void Reset();
     61   void TearDown();
     62 
     63   Object** SamplerWindowAddress();
     64   int SamplerWindowSize();
     65 
     66   // Rate limiting support.
     67 
     68   // VM thread interface.
     69   //
     70   // Called by isolates when their states change.
     71   static inline void IsolateEnteredJS(Isolate* isolate);
     72   static inline void IsolateExitedJS(Isolate* isolate);
     73 
     74   // Profiler thread interface.
     75   //
     76   // IsSomeIsolateInJS():
     77   // The profiler thread can query whether some isolate is currently
     78   // running JavaScript code.
     79   //
     80   // WaitForSomeIsolateToEnterJS():
     81   // When no isolates are running JavaScript code for some time the
     82   // profiler thread suspends itself by calling the wait function. The
     83   // wait function returns true after it waited or false immediately.
     84   // While the function was waiting the profiler may have been
     85   // disabled so it *must check* whether it is allowed to continue.
     86   static bool IsSomeIsolateInJS();
     87   static bool WaitForSomeIsolateToEnterJS();
     88 
     89   // When shutting down we join the profiler thread. Doing so while
     90   // it's waiting on a semaphore will cause a deadlock, so we have to
     91   // wake it up first.
     92   static void WakeUpRuntimeProfilerThreadBeforeShutdown();
     93 
     94   void UpdateSamplesAfterScavenge();
     95   void RemoveDeadSamples();
     96   void UpdateSamplesAfterCompact(ObjectVisitor* visitor);
     97 
     98  private:
     99   static const int kSamplerWindowSize = 16;
    100   static const int kStateWindowSize = 128;
    101 
    102   enum SamplerState {
    103     IN_NON_JS_STATE = 0,
    104     IN_JS_STATE = 1
    105   };
    106 
    107   static void HandleWakeUp(Isolate* isolate);
    108 
    109   void Optimize(JSFunction* function, bool eager, int delay);
    110 
    111   void AttemptOnStackReplacement(JSFunction* function);
    112 
    113   void ClearSampleBuffer();
    114 
    115   void ClearSampleBufferNewSpaceEntries();
    116 
    117   int LookupSample(JSFunction* function);
    118 
    119   void AddSample(JSFunction* function, int weight);
    120 
    121 #ifdef ENABLE_LOGGING_AND_PROFILING
    122   void UpdateStateRatio(SamplerState current_state);
    123 #endif
    124 
    125   Isolate* isolate_;
    126 
    127   int sampler_threshold_;
    128   int sampler_threshold_size_factor_;
    129   int sampler_ticks_until_threshold_adjustment_;
    130 
    131   // The ratio of ticks spent in JS code in percent.
    132   Atomic32 js_ratio_;
    133 
    134   Object* sampler_window_[kSamplerWindowSize];
    135   int sampler_window_position_;
    136   int sampler_window_weight_[kSamplerWindowSize];
    137 
    138   // Support for pending 'optimize soon' requests.
    139   PendingListNode* optimize_soon_list_;
    140 
    141   SamplerState state_window_[kStateWindowSize];
    142   int state_window_position_;
    143   int state_window_ticks_;
    144   int state_counts_[2];
    145 
    146   // Possible state values:
    147   //   -1            => the profiler thread is waiting on the semaphore
    148   //   0 or positive => the number of isolates running JavaScript code.
    149   static Atomic32 state_;
    150   static Semaphore* semaphore_;
    151 
    152 #ifdef DEBUG
    153   static bool has_been_globally_setup_;
    154 #endif
    155   static bool enabled_;
    156 };
    157 
    158 
    159 // Rate limiter intended to be used in the profiler thread.
    160 class RuntimeProfilerRateLimiter BASE_EMBEDDED {
    161  public:
    162   RuntimeProfilerRateLimiter() : non_js_ticks_(0) { }
    163 
    164   // Suspends the current thread (which must be the profiler thread)
    165   // when not executing JavaScript to minimize CPU usage. Returns
    166   // whether the thread was suspended (and so must check whether
    167   // profiling is still active.)
    168   //
    169   // Does nothing when runtime profiling is not enabled.
    170   bool SuspendIfNecessary();
    171 
    172  private:
    173   int non_js_ticks_;
    174 
    175   DISALLOW_COPY_AND_ASSIGN(RuntimeProfilerRateLimiter);
    176 };
    177 
    178 
    179 // Implementation of RuntimeProfiler inline functions.
    180 
    181 void RuntimeProfiler::IsolateEnteredJS(Isolate* isolate) {
    182   Atomic32 new_state = NoBarrier_AtomicIncrement(&state_, 1);
    183   if (new_state == 0) {
    184     // Just incremented from -1 to 0. -1 can only be set by the
    185     // profiler thread before it suspends itself and starts waiting on
    186     // the semaphore.
    187     HandleWakeUp(isolate);
    188   }
    189   ASSERT(new_state >= 0);
    190 }
    191 
    192 
    193 void RuntimeProfiler::IsolateExitedJS(Isolate* isolate) {
    194   Atomic32 new_state = NoBarrier_AtomicIncrement(&state_, -1);
    195   ASSERT(new_state >= 0);
    196   USE(new_state);
    197 }
    198 
    199 } }  // namespace v8::internal
    200 
    201 #endif  // V8_RUNTIME_PROFILER_H_
    202