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 #include "src/globals.h"
     10 
     11 namespace v8 {
     12 namespace internal {
     13 
     14 // A simple ring buffer class with maximum size known at compile time.
     15 // The class only implements the functionality required in GCTracer.
     16 template <typename T, size_t MAX_SIZE>
     17 class RingBuffer {
     18  public:
     19   class const_iterator {
     20    public:
     21     const_iterator() : index_(0), elements_(NULL) {}
     22 
     23     const_iterator(size_t index, const T* elements)
     24         : index_(index), elements_(elements) {}
     25 
     26     bool operator==(const const_iterator& rhs) const {
     27       return elements_ == rhs.elements_ && index_ == rhs.index_;
     28     }
     29 
     30     bool operator!=(const const_iterator& rhs) const {
     31       return elements_ != rhs.elements_ || index_ != rhs.index_;
     32     }
     33 
     34     operator const T*() const { return elements_ + index_; }
     35 
     36     const T* operator->() const { return elements_ + index_; }
     37 
     38     const T& operator*() const { return elements_[index_]; }
     39 
     40     const_iterator& operator++() {
     41       index_ = (index_ + 1) % (MAX_SIZE + 1);
     42       return *this;
     43     }
     44 
     45     const_iterator& operator--() {
     46       index_ = (index_ + MAX_SIZE) % (MAX_SIZE + 1);
     47       return *this;
     48     }
     49 
     50    private:
     51     size_t index_;
     52     const T* elements_;
     53   };
     54 
     55   RingBuffer() : begin_(0), end_(0) {}
     56 
     57   bool empty() const { return begin_ == end_; }
     58   size_t size() const {
     59     return (end_ - begin_ + MAX_SIZE + 1) % (MAX_SIZE + 1);
     60   }
     61   const_iterator begin() const { return const_iterator(begin_, elements_); }
     62   const_iterator end() const { return const_iterator(end_, elements_); }
     63   const_iterator back() const { return --end(); }
     64   void push_back(const T& element) {
     65     elements_[end_] = element;
     66     end_ = (end_ + 1) % (MAX_SIZE + 1);
     67     if (end_ == begin_) begin_ = (begin_ + 1) % (MAX_SIZE + 1);
     68   }
     69   void push_front(const T& element) {
     70     begin_ = (begin_ + MAX_SIZE) % (MAX_SIZE + 1);
     71     if (begin_ == end_) end_ = (end_ + MAX_SIZE) % (MAX_SIZE + 1);
     72     elements_[begin_] = element;
     73   }
     74 
     75   void reset() {
     76     begin_ = 0;
     77     end_ = 0;
     78   }
     79 
     80  private:
     81   T elements_[MAX_SIZE + 1];
     82   size_t begin_;
     83   size_t end_;
     84 
     85   DISALLOW_COPY_AND_ASSIGN(RingBuffer);
     86 };
     87 
     88 
     89 enum ScavengeSpeedMode { kForAllObjects, kForSurvivedObjects };
     90 
     91 
     92 // GCTracer collects and prints ONE line after each garbage collector
     93 // invocation IFF --trace_gc is used.
     94 // TODO(ernstm): Unit tests.
     95 class GCTracer {
     96  public:
     97   class Scope {
     98    public:
     99     enum ScopeId {
    100       EXTERNAL,
    101       MC_CLEAR,
    102       MC_CLEAR_CODE_FLUSH,
    103       MC_CLEAR_DEPENDENT_CODE,
    104       MC_CLEAR_GLOBAL_HANDLES,
    105       MC_CLEAR_MAPS,
    106       MC_CLEAR_SLOTS_BUFFER,
    107       MC_CLEAR_STORE_BUFFER,
    108       MC_CLEAR_STRING_TABLE,
    109       MC_CLEAR_WEAK_CELLS,
    110       MC_CLEAR_WEAK_COLLECTIONS,
    111       MC_CLEAR_WEAK_LISTS,
    112       MC_EVACUATE,
    113       MC_EVACUATE_CANDIDATES,
    114       MC_EVACUATE_CLEAN_UP,
    115       MC_EVACUATE_NEW_SPACE,
    116       MC_EVACUATE_UPDATE_POINTERS,
    117       MC_EVACUATE_UPDATE_POINTERS_BETWEEN_EVACUATED,
    118       MC_EVACUATE_UPDATE_POINTERS_TO_EVACUATED,
    119       MC_EVACUATE_UPDATE_POINTERS_TO_NEW,
    120       MC_EVACUATE_UPDATE_POINTERS_WEAK,
    121       MC_FINISH,
    122       MC_INCREMENTAL_FINALIZE,
    123       MC_MARK,
    124       MC_MARK_FINISH_INCREMENTAL,
    125       MC_MARK_PREPARE_CODE_FLUSH,
    126       MC_MARK_ROOTS,
    127       MC_MARK_WEAK_CLOSURE,
    128       MC_SWEEP,
    129       MC_SWEEP_CODE,
    130       MC_SWEEP_MAP,
    131       MC_SWEEP_OLD,
    132       SCAVENGER_CODE_FLUSH_CANDIDATES,
    133       SCAVENGER_OBJECT_GROUPS,
    134       SCAVENGER_OLD_TO_NEW_POINTERS,
    135       SCAVENGER_ROOTS,
    136       SCAVENGER_SCAVENGE,
    137       SCAVENGER_SEMISPACE,
    138       SCAVENGER_WEAK,
    139       NUMBER_OF_SCOPES
    140     };
    141 
    142     Scope(GCTracer* tracer, ScopeId scope);
    143     ~Scope();
    144 
    145    private:
    146     GCTracer* tracer_;
    147     ScopeId scope_;
    148     double start_time_;
    149 
    150     DISALLOW_COPY_AND_ASSIGN(Scope);
    151   };
    152 
    153 
    154   class AllocationEvent {
    155    public:
    156     // Default constructor leaves the event uninitialized.
    157     AllocationEvent() {}
    158 
    159     AllocationEvent(double duration, size_t allocation_in_bytes);
    160 
    161     // Time spent in the mutator during the end of the last sample to the
    162     // beginning of the next sample.
    163     double duration_;
    164 
    165     // Memory allocated in the new space during the end of the last sample
    166     // to the beginning of the next sample
    167     size_t allocation_in_bytes_;
    168   };
    169 
    170 
    171   class CompactionEvent {
    172    public:
    173     CompactionEvent() : duration(0), live_bytes_compacted(0) {}
    174 
    175     CompactionEvent(double duration, intptr_t live_bytes_compacted)
    176         : duration(duration), live_bytes_compacted(live_bytes_compacted) {}
    177 
    178     double duration;
    179     intptr_t live_bytes_compacted;
    180   };
    181 
    182 
    183   class ContextDisposalEvent {
    184    public:
    185     // Default constructor leaves the event uninitialized.
    186     ContextDisposalEvent() {}
    187 
    188     explicit ContextDisposalEvent(double time);
    189 
    190     // Time when context disposal event happened.
    191     double time_;
    192   };
    193 
    194 
    195   class SurvivalEvent {
    196    public:
    197     // Default constructor leaves the event uninitialized.
    198     SurvivalEvent() {}
    199 
    200     explicit SurvivalEvent(double survival_ratio);
    201 
    202     double promotion_ratio_;
    203   };
    204 
    205 
    206   class Event {
    207    public:
    208     enum Type {
    209       SCAVENGER = 0,
    210       MARK_COMPACTOR = 1,
    211       INCREMENTAL_MARK_COMPACTOR = 2,
    212       START = 3
    213     };
    214 
    215     // Default constructor leaves the event uninitialized.
    216     Event() {}
    217 
    218     Event(Type type, const char* gc_reason, const char* collector_reason);
    219 
    220     // Returns a string describing the event type.
    221     const char* TypeName(bool short_name) const;
    222 
    223     // Type of event
    224     Type type;
    225 
    226     const char* gc_reason;
    227     const char* collector_reason;
    228 
    229     // Timestamp set in the constructor.
    230     double start_time;
    231 
    232     // Timestamp set in the destructor.
    233     double end_time;
    234 
    235     // Memory reduction flag set.
    236     bool reduce_memory;
    237 
    238     // Size of objects in heap set in constructor.
    239     intptr_t start_object_size;
    240 
    241     // Size of objects in heap set in destructor.
    242     intptr_t end_object_size;
    243 
    244     // Size of memory allocated from OS set in constructor.
    245     intptr_t start_memory_size;
    246 
    247     // Size of memory allocated from OS set in destructor.
    248     intptr_t end_memory_size;
    249 
    250     // Total amount of space either wasted or contained in one of free lists
    251     // before the current GC.
    252     intptr_t start_holes_size;
    253 
    254     // Total amount of space either wasted or contained in one of free lists
    255     // after the current GC.
    256     intptr_t end_holes_size;
    257 
    258     // Size of new space objects in constructor.
    259     intptr_t new_space_object_size;
    260     // Size of survived new space objects in desctructor.
    261     intptr_t survived_new_space_object_size;
    262 
    263     // Number of incremental marking steps since creation of tracer.
    264     // (value at start of event)
    265     int cumulative_incremental_marking_steps;
    266 
    267     // Incremental marking steps since
    268     // - last event for SCAVENGER events
    269     // - last INCREMENTAL_MARK_COMPACTOR event for INCREMENTAL_MARK_COMPACTOR
    270     // events
    271     int incremental_marking_steps;
    272 
    273     // Bytes marked since creation of tracer (value at start of event).
    274     intptr_t cumulative_incremental_marking_bytes;
    275 
    276     // Bytes marked since
    277     // - last event for SCAVENGER events
    278     // - last INCREMENTAL_MARK_COMPACTOR event for INCREMENTAL_MARK_COMPACTOR
    279     // events
    280     intptr_t incremental_marking_bytes;
    281 
    282     // Cumulative duration of incremental marking steps since creation of
    283     // tracer. (value at start of event)
    284     double cumulative_incremental_marking_duration;
    285 
    286     // Duration of incremental marking steps since
    287     // - last event for SCAVENGER events
    288     // - last INCREMENTAL_MARK_COMPACTOR event for INCREMENTAL_MARK_COMPACTOR
    289     // events
    290     double incremental_marking_duration;
    291 
    292     // Cumulative pure duration of incremental marking steps since creation of
    293     // tracer. (value at start of event)
    294     double cumulative_pure_incremental_marking_duration;
    295 
    296     // Duration of pure incremental marking steps since
    297     // - last event for SCAVENGER events
    298     // - last INCREMENTAL_MARK_COMPACTOR event for INCREMENTAL_MARK_COMPACTOR
    299     // events
    300     double pure_incremental_marking_duration;
    301 
    302     // Longest incremental marking step since start of marking.
    303     // (value at start of event)
    304     double longest_incremental_marking_step;
    305 
    306     // Amounts of time spent in different scopes during GC.
    307     double scopes[Scope::NUMBER_OF_SCOPES];
    308   };
    309 
    310   static const size_t kRingBufferMaxSize = 10;
    311 
    312   typedef RingBuffer<Event, kRingBufferMaxSize> EventBuffer;
    313 
    314   typedef RingBuffer<AllocationEvent, kRingBufferMaxSize> AllocationEventBuffer;
    315 
    316   typedef RingBuffer<ContextDisposalEvent, kRingBufferMaxSize>
    317       ContextDisposalEventBuffer;
    318 
    319   typedef RingBuffer<CompactionEvent, kRingBufferMaxSize> CompactionEventBuffer;
    320 
    321   typedef RingBuffer<SurvivalEvent, kRingBufferMaxSize> SurvivalEventBuffer;
    322 
    323   static const int kThroughputTimeFrameMs = 5000;
    324 
    325   explicit GCTracer(Heap* heap);
    326 
    327   // Start collecting data.
    328   void Start(GarbageCollector collector, const char* gc_reason,
    329              const char* collector_reason);
    330 
    331   // Stop collecting data and print results.
    332   void Stop(GarbageCollector collector);
    333 
    334   // Sample and accumulate bytes allocated since the last GC.
    335   void SampleAllocation(double current_ms, size_t new_space_counter_bytes,
    336                         size_t old_generation_counter_bytes);
    337 
    338   // Log the accumulated new space allocation bytes.
    339   void AddAllocation(double current_ms);
    340 
    341   void AddContextDisposalTime(double time);
    342 
    343   void AddCompactionEvent(double duration, intptr_t live_bytes_compacted);
    344 
    345   void AddSurvivalRatio(double survival_ratio);
    346 
    347   // Log an incremental marking step.
    348   void AddIncrementalMarkingStep(double duration, intptr_t bytes);
    349 
    350   void AddIncrementalMarkingFinalizationStep(double duration);
    351 
    352   // Log time spent in marking.
    353   void AddMarkingTime(double duration) {
    354     cumulative_marking_duration_ += duration;
    355   }
    356 
    357   // Time spent in marking.
    358   double cumulative_marking_duration() const {
    359     return cumulative_marking_duration_;
    360   }
    361 
    362   // Log time spent in sweeping on main thread.
    363   void AddSweepingTime(double duration) {
    364     cumulative_sweeping_duration_ += duration;
    365   }
    366 
    367   // Time spent in sweeping on main thread.
    368   double cumulative_sweeping_duration() const {
    369     return cumulative_sweeping_duration_;
    370   }
    371 
    372   // Compute the mean duration of the last scavenger events. Returns 0 if no
    373   // events have been recorded.
    374   double MeanScavengerDuration() const {
    375     return MeanDuration(scavenger_events_);
    376   }
    377 
    378   // Compute the max duration of the last scavenger events. Returns 0 if no
    379   // events have been recorded.
    380   double MaxScavengerDuration() const { return MaxDuration(scavenger_events_); }
    381 
    382   // Compute the mean duration of the last mark compactor events. Returns 0 if
    383   // no events have been recorded.
    384   double MeanMarkCompactorDuration() const {
    385     return MeanDuration(mark_compactor_events_);
    386   }
    387 
    388   // Compute the max duration of the last mark compactor events. Return 0 if no
    389   // events have been recorded.
    390   double MaxMarkCompactorDuration() const {
    391     return MaxDuration(mark_compactor_events_);
    392   }
    393 
    394   // Compute the mean duration of the last incremental mark compactor
    395   // events. Returns 0 if no events have been recorded.
    396   double MeanIncrementalMarkCompactorDuration() const {
    397     return MeanDuration(incremental_mark_compactor_events_);
    398   }
    399 
    400   // Compute the mean step duration of the last incremental marking round.
    401   // Returns 0 if no incremental marking round has been completed.
    402   double MeanIncrementalMarkingDuration() const;
    403 
    404   // Compute the max step duration of the last incremental marking round.
    405   // Returns 0 if no incremental marking round has been completed.
    406   double MaxIncrementalMarkingDuration() const;
    407 
    408   // Compute the average incremental marking speed in bytes/millisecond.
    409   // Returns 0 if no events have been recorded.
    410   intptr_t IncrementalMarkingSpeedInBytesPerMillisecond() const;
    411 
    412   // Compute the average scavenge speed in bytes/millisecond.
    413   // Returns 0 if no events have been recorded.
    414   intptr_t ScavengeSpeedInBytesPerMillisecond(
    415       ScavengeSpeedMode mode = kForAllObjects) const;
    416 
    417   // Compute the average compaction speed in bytes/millisecond.
    418   // Returns 0 if not enough events have been recorded.
    419   intptr_t CompactionSpeedInBytesPerMillisecond() const;
    420 
    421   // Compute the average mark-sweep speed in bytes/millisecond.
    422   // Returns 0 if no events have been recorded.
    423   intptr_t MarkCompactSpeedInBytesPerMillisecond() const;
    424 
    425   // Compute the average incremental mark-sweep finalize speed in
    426   // bytes/millisecond.
    427   // Returns 0 if no events have been recorded.
    428   intptr_t FinalIncrementalMarkCompactSpeedInBytesPerMillisecond() const;
    429 
    430   // Compute the overall mark compact speed including incremental steps
    431   // and the final mark-compact step.
    432   double CombinedMarkCompactSpeedInBytesPerMillisecond();
    433 
    434   // Allocation throughput in the new space in bytes/millisecond.
    435   // Returns 0 if no allocation events have been recorded.
    436   size_t NewSpaceAllocationThroughputInBytesPerMillisecond(
    437       double time_ms = 0) const;
    438 
    439   // Allocation throughput in the old generation in bytes/millisecond in the
    440   // last time_ms milliseconds.
    441   // Returns 0 if no allocation events have been recorded.
    442   size_t OldGenerationAllocationThroughputInBytesPerMillisecond(
    443       double time_ms = 0) const;
    444 
    445   // Allocation throughput in heap in bytes/millisecond in the last time_ms
    446   // milliseconds.
    447   // Returns 0 if no allocation events have been recorded.
    448   size_t AllocationThroughputInBytesPerMillisecond(double time_ms) const;
    449 
    450   // Allocation throughput in heap in bytes/milliseconds in the last
    451   // kThroughputTimeFrameMs seconds.
    452   // Returns 0 if no allocation events have been recorded.
    453   size_t CurrentAllocationThroughputInBytesPerMillisecond() const;
    454 
    455   // Allocation throughput in old generation in bytes/milliseconds in the last
    456   // kThroughputTimeFrameMs seconds.
    457   // Returns 0 if no allocation events have been recorded.
    458   size_t CurrentOldGenerationAllocationThroughputInBytesPerMillisecond() const;
    459 
    460   // Computes the context disposal rate in milliseconds. It takes the time
    461   // frame of the first recorded context disposal to the current time and
    462   // divides it by the number of recorded events.
    463   // Returns 0 if no events have been recorded.
    464   double ContextDisposalRateInMilliseconds() const;
    465 
    466   // Computes the average survival ratio based on the last recorded survival
    467   // events.
    468   // Returns 0 if no events have been recorded.
    469   double AverageSurvivalRatio() const;
    470 
    471   // Returns true if at least one survival event was recorded.
    472   bool SurvivalEventsRecorded() const;
    473 
    474   // Discard all recorded survival events.
    475   void ResetSurvivalEvents();
    476 
    477  private:
    478   // Print one detailed trace line in name=value format.
    479   // TODO(ernstm): Move to Heap.
    480   void PrintNVP() const;
    481 
    482   // Print one trace line.
    483   // TODO(ernstm): Move to Heap.
    484   void Print() const;
    485 
    486   // Prints a line and also adds it to the heap's ring buffer so that
    487   // it can be included in later crash dumps.
    488   void Output(const char* format, ...) const;
    489 
    490   // Compute the mean duration of the events in the given ring buffer.
    491   double MeanDuration(const EventBuffer& events) const;
    492 
    493   // Compute the max duration of the events in the given ring buffer.
    494   double MaxDuration(const EventBuffer& events) const;
    495 
    496   void ClearMarkCompactStatistics() {
    497     cumulative_incremental_marking_steps_ = 0;
    498     cumulative_incremental_marking_bytes_ = 0;
    499     cumulative_incremental_marking_duration_ = 0;
    500     cumulative_pure_incremental_marking_duration_ = 0;
    501     longest_incremental_marking_step_ = 0;
    502     cumulative_incremental_marking_finalization_steps_ = 0;
    503     cumulative_incremental_marking_finalization_duration_ = 0;
    504     longest_incremental_marking_finalization_step_ = 0;
    505     cumulative_marking_duration_ = 0;
    506     cumulative_sweeping_duration_ = 0;
    507   }
    508 
    509   // Pointer to the heap that owns this tracer.
    510   Heap* heap_;
    511 
    512   // Current tracer event. Populated during Start/Stop cycle. Valid after Stop()
    513   // has returned.
    514   Event current_;
    515 
    516   // Previous tracer event.
    517   Event previous_;
    518 
    519   // Previous INCREMENTAL_MARK_COMPACTOR event.
    520   Event previous_incremental_mark_compactor_event_;
    521 
    522   // RingBuffers for SCAVENGER events.
    523   EventBuffer scavenger_events_;
    524 
    525   // RingBuffers for MARK_COMPACTOR events.
    526   EventBuffer mark_compactor_events_;
    527 
    528   // RingBuffers for INCREMENTAL_MARK_COMPACTOR events.
    529   EventBuffer incremental_mark_compactor_events_;
    530 
    531   // RingBuffer for allocation events.
    532   AllocationEventBuffer new_space_allocation_events_;
    533   AllocationEventBuffer old_generation_allocation_events_;
    534 
    535   // RingBuffer for context disposal events.
    536   ContextDisposalEventBuffer context_disposal_events_;
    537 
    538   // RingBuffer for compaction events.
    539   CompactionEventBuffer compaction_events_;
    540 
    541   // RingBuffer for survival events.
    542   SurvivalEventBuffer survival_events_;
    543 
    544   // Cumulative number of incremental marking steps since creation of tracer.
    545   int cumulative_incremental_marking_steps_;
    546 
    547   // Cumulative size of incremental marking steps (in bytes) since creation of
    548   // tracer.
    549   intptr_t cumulative_incremental_marking_bytes_;
    550 
    551   // Cumulative duration of incremental marking steps since creation of tracer.
    552   double cumulative_incremental_marking_duration_;
    553 
    554   // Cumulative duration of pure incremental marking steps since creation of
    555   // tracer.
    556   double cumulative_pure_incremental_marking_duration_;
    557 
    558   // Longest incremental marking step since start of marking.
    559   double longest_incremental_marking_step_;
    560 
    561   // Cumulative number of incremental marking finalization steps since creation
    562   // of tracer.
    563   int cumulative_incremental_marking_finalization_steps_;
    564 
    565   // Cumulative duration of incremental marking finalization steps since
    566   // creation of tracer.
    567   double cumulative_incremental_marking_finalization_duration_;
    568 
    569   // Longest incremental marking finalization step since start of marking.
    570   double longest_incremental_marking_finalization_step_;
    571 
    572   // Total marking time.
    573   // This timer is precise when run with --print-cumulative-gc-stat
    574   double cumulative_marking_duration_;
    575 
    576   // Total sweeping time on the main thread.
    577   // This timer is precise when run with --print-cumulative-gc-stat
    578   // TODO(hpayer): Account for sweeping time on sweeper threads. Add a
    579   // different field for that.
    580   // TODO(hpayer): This timer right now just holds the sweeping time
    581   // of the initial atomic sweeping pause. Make sure that it accumulates
    582   // all sweeping operations performed on the main thread.
    583   double cumulative_sweeping_duration_;
    584 
    585   // Timestamp and allocation counter at the last sampled allocation event.
    586   double allocation_time_ms_;
    587   size_t new_space_allocation_counter_bytes_;
    588   size_t old_generation_allocation_counter_bytes_;
    589 
    590   // Accumulated duration and allocated bytes since the last GC.
    591   double allocation_duration_since_gc_;
    592   size_t new_space_allocation_in_bytes_since_gc_;
    593   size_t old_generation_allocation_in_bytes_since_gc_;
    594 
    595   double combined_mark_compact_speed_cache_;
    596 
    597   // Counts how many tracers were started without stopping.
    598   int start_counter_;
    599 
    600   DISALLOW_COPY_AND_ASSIGN(GCTracer);
    601 };
    602 }  // namespace internal
    603 }  // namespace v8
    604 
    605 #endif  // V8_HEAP_GC_TRACER_H_
    606