Home | History | Annotate | Download | only in heap
      1 // Copyright 2014 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef V8_HEAP_GC_TRACER_H_
      6 #define V8_HEAP_GC_TRACER_H_
      7 
      8 #include "src/base/platform/platform.h"
      9 
     10 namespace v8 {
     11 namespace internal {
     12 
     13 // A simple ring buffer class with maximum size known at compile time.
     14 // The class only implements the functionality required in GCTracer.
     15 template <typename T, size_t MAX_SIZE>
     16 class RingBuffer {
     17  public:
     18   class const_iterator {
     19    public:
     20     const_iterator() : index_(0), elements_(NULL) {}
     21 
     22     const_iterator(size_t index, const T* elements)
     23         : index_(index), elements_(elements) {}
     24 
     25     bool operator==(const const_iterator& rhs) const {
     26       return elements_ == rhs.elements_ && index_ == rhs.index_;
     27     }
     28 
     29     bool operator!=(const const_iterator& rhs) const {
     30       return elements_ != rhs.elements_ || index_ != rhs.index_;
     31     }
     32 
     33     operator const T*() const { return elements_ + index_; }
     34 
     35     const T* operator->() const { return elements_ + index_; }
     36 
     37     const T& operator*() const { return elements_[index_]; }
     38 
     39     const_iterator& operator++() {
     40       index_ = (index_ + 1) % (MAX_SIZE + 1);
     41       return *this;
     42     }
     43 
     44     const_iterator& operator--() {
     45       index_ = (index_ + MAX_SIZE) % (MAX_SIZE + 1);
     46       return *this;
     47     }
     48 
     49    private:
     50     size_t index_;
     51     const T* elements_;
     52   };
     53 
     54   RingBuffer() : begin_(0), end_(0) {}
     55 
     56   bool empty() const { return begin_ == end_; }
     57   size_t size() const {
     58     return (end_ - begin_ + MAX_SIZE + 1) % (MAX_SIZE + 1);
     59   }
     60   const_iterator begin() const { return const_iterator(begin_, elements_); }
     61   const_iterator end() const { return const_iterator(end_, elements_); }
     62   const_iterator back() const { return --end(); }
     63   void push_back(const T& element) {
     64     elements_[end_] = element;
     65     end_ = (end_ + 1) % (MAX_SIZE + 1);
     66     if (end_ == begin_) begin_ = (begin_ + 1) % (MAX_SIZE + 1);
     67   }
     68   void push_front(const T& element) {
     69     begin_ = (begin_ + MAX_SIZE) % (MAX_SIZE + 1);
     70     if (begin_ == end_) end_ = (end_ + MAX_SIZE) % (MAX_SIZE + 1);
     71     elements_[begin_] = element;
     72   }
     73 
     74  private:
     75   T elements_[MAX_SIZE + 1];
     76   size_t begin_;
     77   size_t end_;
     78 
     79   DISALLOW_COPY_AND_ASSIGN(RingBuffer);
     80 };
     81 
     82 
     83 // GCTracer collects and prints ONE line after each garbage collector
     84 // invocation IFF --trace_gc is used.
     85 // TODO(ernstm): Unit tests.
     86 class GCTracer {
     87  public:
     88   class Scope {
     89    public:
     90     enum ScopeId {
     91       EXTERNAL,
     92       MC_MARK,
     93       MC_SWEEP,
     94       MC_SWEEP_NEWSPACE,
     95       MC_SWEEP_OLDSPACE,
     96       MC_SWEEP_CODE,
     97       MC_SWEEP_CELL,
     98       MC_SWEEP_MAP,
     99       MC_EVACUATE_PAGES,
    100       MC_UPDATE_NEW_TO_NEW_POINTERS,
    101       MC_UPDATE_ROOT_TO_NEW_POINTERS,
    102       MC_UPDATE_OLD_TO_NEW_POINTERS,
    103       MC_UPDATE_POINTERS_TO_EVACUATED,
    104       MC_UPDATE_POINTERS_BETWEEN_EVACUATED,
    105       MC_UPDATE_MISC_POINTERS,
    106       MC_WEAKCOLLECTION_PROCESS,
    107       MC_WEAKCOLLECTION_CLEAR,
    108       MC_WEAKCOLLECTION_ABORT,
    109       MC_FLUSH_CODE,
    110       NUMBER_OF_SCOPES
    111     };
    112 
    113     Scope(GCTracer* tracer, ScopeId scope) : tracer_(tracer), scope_(scope) {
    114       start_time_ = base::OS::TimeCurrentMillis();
    115     }
    116 
    117     ~Scope() {
    118       DCHECK(scope_ < NUMBER_OF_SCOPES);  // scope_ is unsigned.
    119       tracer_->current_.scopes[scope_] +=
    120           base::OS::TimeCurrentMillis() - start_time_;
    121     }
    122 
    123    private:
    124     GCTracer* tracer_;
    125     ScopeId scope_;
    126     double start_time_;
    127 
    128     DISALLOW_COPY_AND_ASSIGN(Scope);
    129   };
    130 
    131 
    132   class AllocationEvent {
    133    public:
    134     // Default constructor leaves the event uninitialized.
    135     AllocationEvent() {}
    136 
    137     AllocationEvent(double duration, intptr_t allocation_in_bytes);
    138 
    139     // Time spent in the mutator during the end of the last garbage collection
    140     // to the beginning of the next garbage collection.
    141     double duration_;
    142 
    143     // Memory allocated in the new space during the end of the last garbage
    144     // collection to the beginning of the next garbage collection.
    145     intptr_t allocation_in_bytes_;
    146   };
    147 
    148   class Event {
    149    public:
    150     enum Type { SCAVENGER = 0, MARK_COMPACTOR = 1, START = 2 };
    151 
    152     // Default constructor leaves the event uninitialized.
    153     Event() {}
    154 
    155     Event(Type type, const char* gc_reason, const char* collector_reason);
    156 
    157     // Returns a string describing the event type.
    158     const char* TypeName(bool short_name) const;
    159 
    160     // Type of event
    161     Type type;
    162 
    163     const char* gc_reason;
    164     const char* collector_reason;
    165 
    166     // Timestamp set in the constructor.
    167     double start_time;
    168 
    169     // Timestamp set in the destructor.
    170     double end_time;
    171 
    172     // Size of objects in heap set in constructor.
    173     intptr_t start_object_size;
    174 
    175     // Size of objects in heap set in destructor.
    176     intptr_t end_object_size;
    177 
    178     // Size of memory allocated from OS set in constructor.
    179     intptr_t start_memory_size;
    180 
    181     // Size of memory allocated from OS set in destructor.
    182     intptr_t end_memory_size;
    183 
    184     // Total amount of space either wasted or contained in one of free lists
    185     // before the current GC.
    186     intptr_t start_holes_size;
    187 
    188     // Total amount of space either wasted or contained in one of free lists
    189     // after the current GC.
    190     intptr_t end_holes_size;
    191 
    192     // Size of new space objects in constructor.
    193     intptr_t new_space_object_size;
    194 
    195     // Number of incremental marking steps since creation of tracer.
    196     // (value at start of event)
    197     int cumulative_incremental_marking_steps;
    198 
    199     // Incremental marking steps since
    200     // - last event for SCAVENGER events
    201     // - last MARK_COMPACTOR event for MARK_COMPACTOR events
    202     int incremental_marking_steps;
    203 
    204     // Bytes marked since creation of tracer (value at start of event).
    205     intptr_t cumulative_incremental_marking_bytes;
    206 
    207     // Bytes marked since
    208     // - last event for SCAVENGER events
    209     // - last MARK_COMPACTOR event for MARK_COMPACTOR events
    210     intptr_t incremental_marking_bytes;
    211 
    212     // Cumulative duration of incremental marking steps since creation of
    213     // tracer. (value at start of event)
    214     double cumulative_incremental_marking_duration;
    215 
    216     // Duration of incremental marking steps since
    217     // - last event for SCAVENGER events
    218     // - last MARK_COMPACTOR event for MARK_COMPACTOR events
    219     double incremental_marking_duration;
    220 
    221     // Cumulative pure duration of incremental marking steps since creation of
    222     // tracer. (value at start of event)
    223     double cumulative_pure_incremental_marking_duration;
    224 
    225     // Duration of pure incremental marking steps since
    226     // - last event for SCAVENGER events
    227     // - last MARK_COMPACTOR event for MARK_COMPACTOR events
    228     double pure_incremental_marking_duration;
    229 
    230     // Longest incremental marking step since start of marking.
    231     // (value at start of event)
    232     double longest_incremental_marking_step;
    233 
    234     // Amounts of time spent in different scopes during GC.
    235     double scopes[Scope::NUMBER_OF_SCOPES];
    236   };
    237 
    238   static const int kRingBufferMaxSize = 10;
    239 
    240   typedef RingBuffer<Event, kRingBufferMaxSize> EventBuffer;
    241 
    242   typedef RingBuffer<AllocationEvent, kRingBufferMaxSize> AllocationEventBuffer;
    243 
    244   explicit GCTracer(Heap* heap);
    245 
    246   // Start collecting data.
    247   void Start(GarbageCollector collector, const char* gc_reason,
    248              const char* collector_reason);
    249 
    250   // Stop collecting data and print results.
    251   void Stop();
    252 
    253   // Log an allocation throughput event.
    254   void AddNewSpaceAllocationTime(double duration, intptr_t allocation_in_bytes);
    255 
    256   // Log an incremental marking step.
    257   void AddIncrementalMarkingStep(double duration, intptr_t bytes);
    258 
    259   // Log time spent in marking.
    260   void AddMarkingTime(double duration) {
    261     cumulative_marking_duration_ += duration;
    262   }
    263 
    264   // Time spent in marking.
    265   double cumulative_marking_duration() const {
    266     return cumulative_marking_duration_;
    267   }
    268 
    269   // Log time spent in sweeping on main thread.
    270   void AddSweepingTime(double duration) {
    271     cumulative_sweeping_duration_ += duration;
    272   }
    273 
    274   // Time spent in sweeping on main thread.
    275   double cumulative_sweeping_duration() const {
    276     return cumulative_sweeping_duration_;
    277   }
    278 
    279   // Compute the mean duration of the last scavenger events. Returns 0 if no
    280   // events have been recorded.
    281   double MeanScavengerDuration() const {
    282     return MeanDuration(scavenger_events_);
    283   }
    284 
    285   // Compute the max duration of the last scavenger events. Returns 0 if no
    286   // events have been recorded.
    287   double MaxScavengerDuration() const { return MaxDuration(scavenger_events_); }
    288 
    289   // Compute the mean duration of the last mark compactor events. Returns 0 if
    290   // no events have been recorded.
    291   double MeanMarkCompactorDuration() const {
    292     return MeanDuration(mark_compactor_events_);
    293   }
    294 
    295   // Compute the max duration of the last mark compactor events. Return 0 if no
    296   // events have been recorded.
    297   double MaxMarkCompactorDuration() const {
    298     return MaxDuration(mark_compactor_events_);
    299   }
    300 
    301   // Compute the mean step duration of the last incremental marking round.
    302   // Returns 0 if no incremental marking round has been completed.
    303   double MeanIncrementalMarkingDuration() const;
    304 
    305   // Compute the max step duration of the last incremental marking round.
    306   // Returns 0 if no incremental marking round has been completed.
    307   double MaxIncrementalMarkingDuration() const;
    308 
    309   // Compute the average incremental marking speed in bytes/millisecond.
    310   // Returns 0 if no events have been recorded.
    311   intptr_t IncrementalMarkingSpeedInBytesPerMillisecond() const;
    312 
    313   // Compute the average scavenge speed in bytes/millisecond.
    314   // Returns 0 if no events have been recorded.
    315   intptr_t ScavengeSpeedInBytesPerMillisecond() const;
    316 
    317   // Compute the max mark-sweep speed in bytes/millisecond.
    318   // Returns 0 if no events have been recorded.
    319   intptr_t MarkCompactSpeedInBytesPerMillisecond() const;
    320 
    321   // Allocation throughput in the new space in bytes/millisecond.
    322   // Returns 0 if no events have been recorded.
    323   intptr_t NewSpaceAllocationThroughputInBytesPerMillisecond() const;
    324 
    325  private:
    326   // Print one detailed trace line in name=value format.
    327   // TODO(ernstm): Move to Heap.
    328   void PrintNVP() const;
    329 
    330   // Print one trace line.
    331   // TODO(ernstm): Move to Heap.
    332   void Print() const;
    333 
    334   // Compute the mean duration of the events in the given ring buffer.
    335   double MeanDuration(const EventBuffer& events) const;
    336 
    337   // Compute the max duration of the events in the given ring buffer.
    338   double MaxDuration(const EventBuffer& events) const;
    339 
    340   // Pointer to the heap that owns this tracer.
    341   Heap* heap_;
    342 
    343   // Current tracer event. Populated during Start/Stop cycle. Valid after Stop()
    344   // has returned.
    345   Event current_;
    346 
    347   // Previous tracer event.
    348   Event previous_;
    349 
    350   // Previous MARK_COMPACTOR event.
    351   Event previous_mark_compactor_event_;
    352 
    353   // RingBuffers for SCAVENGER events.
    354   EventBuffer scavenger_events_;
    355 
    356   // RingBuffers for MARK_COMPACTOR events.
    357   EventBuffer mark_compactor_events_;
    358 
    359   // RingBuffer for allocation events.
    360   AllocationEventBuffer allocation_events_;
    361 
    362   // Cumulative number of incremental marking steps since creation of tracer.
    363   int cumulative_incremental_marking_steps_;
    364 
    365   // Cumulative size of incremental marking steps (in bytes) since creation of
    366   // tracer.
    367   intptr_t cumulative_incremental_marking_bytes_;
    368 
    369   // Cumulative duration of incremental marking steps since creation of tracer.
    370   double cumulative_incremental_marking_duration_;
    371 
    372   // Cumulative duration of pure incremental marking steps since creation of
    373   // tracer.
    374   double cumulative_pure_incremental_marking_duration_;
    375 
    376   // Longest incremental marking step since start of marking.
    377   double longest_incremental_marking_step_;
    378 
    379   // Total marking time.
    380   // This timer is precise when run with --print-cumulative-gc-stat
    381   double cumulative_marking_duration_;
    382 
    383   // Total sweeping time on the main thread.
    384   // This timer is precise when run with --print-cumulative-gc-stat
    385   // TODO(hpayer): Account for sweeping time on sweeper threads. Add a
    386   // different field for that.
    387   // TODO(hpayer): This timer right now just holds the sweeping time
    388   // of the initial atomic sweeping pause. Make sure that it accumulates
    389   // all sweeping operations performed on the main thread.
    390   double cumulative_sweeping_duration_;
    391 
    392   // Holds the new space top pointer recorded at the end of the last garbage
    393   // collection.
    394   intptr_t new_space_top_after_gc_;
    395 
    396   DISALLOW_COPY_AND_ASSIGN(GCTracer);
    397 };
    398 }
    399 }  // namespace v8::internal
    400 
    401 #endif  // V8_HEAP_GC_TRACER_H_
    402