de48d23997bda3ce95426d4e565a60c7b1bb7ad0
[platform/upstream/v8.git] / src / heap / gc-tracer.h
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_MARK,
102       MC_SWEEP,
103       MC_SWEEP_NEWSPACE,
104       MC_SWEEP_OLDSPACE,
105       MC_SWEEP_CODE,
106       MC_SWEEP_CELL,
107       MC_SWEEP_MAP,
108       MC_EVACUATE_PAGES,
109       MC_UPDATE_NEW_TO_NEW_POINTERS,
110       MC_UPDATE_ROOT_TO_NEW_POINTERS,
111       MC_UPDATE_OLD_TO_NEW_POINTERS,
112       MC_UPDATE_POINTERS_TO_EVACUATED,
113       MC_UPDATE_POINTERS_BETWEEN_EVACUATED,
114       MC_UPDATE_MISC_POINTERS,
115       MC_INCREMENTAL_WEAKCLOSURE,
116       MC_WEAKCLOSURE,
117       MC_WEAKCOLLECTION_PROCESS,
118       MC_WEAKCOLLECTION_CLEAR,
119       MC_WEAKCOLLECTION_ABORT,
120       MC_WEAKCELL,
121       MC_NONLIVEREFERENCES,
122       MC_FLUSH_CODE,
123       SCAVENGER_CODE_FLUSH_CANDIDATES,
124       SCAVENGER_OBJECT_GROUPS,
125       SCAVENGER_OLD_TO_NEW_POINTERS,
126       SCAVENGER_ROOTS,
127       SCAVENGER_SCAVENGE,
128       SCAVENGER_SEMISPACE,
129       SCAVENGER_WEAK,
130       NUMBER_OF_SCOPES
131     };
132
133     Scope(GCTracer* tracer, ScopeId scope) : tracer_(tracer), scope_(scope) {
134       start_time_ = base::OS::TimeCurrentMillis();
135     }
136
137     ~Scope() {
138       DCHECK(scope_ < NUMBER_OF_SCOPES);  // scope_ is unsigned.
139       tracer_->current_.scopes[scope_] +=
140           base::OS::TimeCurrentMillis() - start_time_;
141     }
142
143    private:
144     GCTracer* tracer_;
145     ScopeId scope_;
146     double start_time_;
147
148     DISALLOW_COPY_AND_ASSIGN(Scope);
149   };
150
151
152   class AllocationEvent {
153    public:
154     // Default constructor leaves the event uninitialized.
155     AllocationEvent() {}
156
157     AllocationEvent(double duration, size_t allocation_in_bytes);
158
159     // Time spent in the mutator during the end of the last sample to the
160     // beginning of the next sample.
161     double duration_;
162
163     // Memory allocated in the new space during the end of the last sample
164     // to the beginning of the next sample
165     size_t allocation_in_bytes_;
166   };
167
168
169   class ContextDisposalEvent {
170    public:
171     // Default constructor leaves the event uninitialized.
172     ContextDisposalEvent() {}
173
174     explicit ContextDisposalEvent(double time);
175
176     // Time when context disposal event happened.
177     double time_;
178   };
179
180
181   class SurvivalEvent {
182    public:
183     // Default constructor leaves the event uninitialized.
184     SurvivalEvent() {}
185
186     explicit SurvivalEvent(double survival_ratio);
187
188     double promotion_ratio_;
189   };
190
191
192   class Event {
193    public:
194     enum Type {
195       SCAVENGER = 0,
196       MARK_COMPACTOR = 1,
197       INCREMENTAL_MARK_COMPACTOR = 2,
198       START = 3
199     };
200
201     // Default constructor leaves the event uninitialized.
202     Event() {}
203
204     Event(Type type, const char* gc_reason, const char* collector_reason);
205
206     // Returns a string describing the event type.
207     const char* TypeName(bool short_name) const;
208
209     // Type of event
210     Type type;
211
212     const char* gc_reason;
213     const char* collector_reason;
214
215     // Timestamp set in the constructor.
216     double start_time;
217
218     // Timestamp set in the destructor.
219     double end_time;
220
221     // Size of objects in heap set in constructor.
222     intptr_t start_object_size;
223
224     // Size of objects in heap set in destructor.
225     intptr_t end_object_size;
226
227     // Size of memory allocated from OS set in constructor.
228     intptr_t start_memory_size;
229
230     // Size of memory allocated from OS set in destructor.
231     intptr_t end_memory_size;
232
233     // Total amount of space either wasted or contained in one of free lists
234     // before the current GC.
235     intptr_t start_holes_size;
236
237     // Total amount of space either wasted or contained in one of free lists
238     // after the current GC.
239     intptr_t end_holes_size;
240
241     // Size of new space objects in constructor.
242     intptr_t new_space_object_size;
243     // Size of survived new space objects in desctructor.
244     intptr_t survived_new_space_object_size;
245
246     // Number of incremental marking steps since creation of tracer.
247     // (value at start of event)
248     int cumulative_incremental_marking_steps;
249
250     // Incremental marking steps since
251     // - last event for SCAVENGER events
252     // - last INCREMENTAL_MARK_COMPACTOR event for INCREMENTAL_MARK_COMPACTOR
253     // events
254     int incremental_marking_steps;
255
256     // Bytes marked since creation of tracer (value at start of event).
257     intptr_t cumulative_incremental_marking_bytes;
258
259     // Bytes marked since
260     // - last event for SCAVENGER events
261     // - last INCREMENTAL_MARK_COMPACTOR event for INCREMENTAL_MARK_COMPACTOR
262     // events
263     intptr_t incremental_marking_bytes;
264
265     // Cumulative duration of incremental marking steps since creation of
266     // tracer. (value at start of event)
267     double cumulative_incremental_marking_duration;
268
269     // Duration of incremental marking steps since
270     // - last event for SCAVENGER events
271     // - last INCREMENTAL_MARK_COMPACTOR event for INCREMENTAL_MARK_COMPACTOR
272     // events
273     double incremental_marking_duration;
274
275     // Cumulative pure duration of incremental marking steps since creation of
276     // tracer. (value at start of event)
277     double cumulative_pure_incremental_marking_duration;
278
279     // Duration of pure incremental marking steps since
280     // - last event for SCAVENGER events
281     // - last INCREMENTAL_MARK_COMPACTOR event for INCREMENTAL_MARK_COMPACTOR
282     // events
283     double pure_incremental_marking_duration;
284
285     // Longest incremental marking step since start of marking.
286     // (value at start of event)
287     double longest_incremental_marking_step;
288
289     // Amounts of time spent in different scopes during GC.
290     double scopes[Scope::NUMBER_OF_SCOPES];
291   };
292
293   static const size_t kRingBufferMaxSize = 10;
294
295   typedef RingBuffer<Event, kRingBufferMaxSize> EventBuffer;
296
297   typedef RingBuffer<AllocationEvent, kRingBufferMaxSize> AllocationEventBuffer;
298
299   typedef RingBuffer<ContextDisposalEvent, kRingBufferMaxSize>
300       ContextDisposalEventBuffer;
301
302   typedef RingBuffer<SurvivalEvent, kRingBufferMaxSize> SurvivalEventBuffer;
303
304   static const int kThroughputTimeFrameMs = 5000;
305
306   explicit GCTracer(Heap* heap);
307
308   // Start collecting data.
309   void Start(GarbageCollector collector, const char* gc_reason,
310              const char* collector_reason);
311
312   // Stop collecting data and print results.
313   void Stop(GarbageCollector collector);
314
315   // Sample and accumulate bytes allocated since the last GC.
316   void SampleAllocation(double current_ms, size_t new_space_counter_bytes,
317                         size_t old_generation_counter_bytes);
318
319   // Log the accumulated new space allocation bytes.
320   void AddAllocation(double current_ms);
321
322   void AddContextDisposalTime(double time);
323
324   void AddSurvivalRatio(double survival_ratio);
325
326   // Log an incremental marking step.
327   void AddIncrementalMarkingStep(double duration, intptr_t bytes);
328
329   // Log time spent in marking.
330   void AddMarkingTime(double duration) {
331     cumulative_marking_duration_ += duration;
332   }
333
334   // Time spent in marking.
335   double cumulative_marking_duration() const {
336     return cumulative_marking_duration_;
337   }
338
339   // Log time spent in sweeping on main thread.
340   void AddSweepingTime(double duration) {
341     cumulative_sweeping_duration_ += duration;
342   }
343
344   // Time spent in sweeping on main thread.
345   double cumulative_sweeping_duration() const {
346     return cumulative_sweeping_duration_;
347   }
348
349   // Compute the mean duration of the last scavenger events. Returns 0 if no
350   // events have been recorded.
351   double MeanScavengerDuration() const {
352     return MeanDuration(scavenger_events_);
353   }
354
355   // Compute the max duration of the last scavenger events. Returns 0 if no
356   // events have been recorded.
357   double MaxScavengerDuration() const { return MaxDuration(scavenger_events_); }
358
359   // Compute the mean duration of the last mark compactor events. Returns 0 if
360   // no events have been recorded.
361   double MeanMarkCompactorDuration() const {
362     return MeanDuration(mark_compactor_events_);
363   }
364
365   // Compute the max duration of the last mark compactor events. Return 0 if no
366   // events have been recorded.
367   double MaxMarkCompactorDuration() const {
368     return MaxDuration(mark_compactor_events_);
369   }
370
371   // Compute the mean duration of the last incremental mark compactor
372   // events. Returns 0 if no events have been recorded.
373   double MeanIncrementalMarkCompactorDuration() const {
374     return MeanDuration(incremental_mark_compactor_events_);
375   }
376
377   // Compute the mean step duration of the last incremental marking round.
378   // Returns 0 if no incremental marking round has been completed.
379   double MeanIncrementalMarkingDuration() const;
380
381   // Compute the max step duration of the last incremental marking round.
382   // Returns 0 if no incremental marking round has been completed.
383   double MaxIncrementalMarkingDuration() const;
384
385   // Compute the average incremental marking speed in bytes/millisecond.
386   // Returns 0 if no events have been recorded.
387   intptr_t IncrementalMarkingSpeedInBytesPerMillisecond() const;
388
389   // Compute the average scavenge speed in bytes/millisecond.
390   // Returns 0 if no events have been recorded.
391   intptr_t ScavengeSpeedInBytesPerMillisecond(
392       ScavengeSpeedMode mode = kForAllObjects) const;
393
394   // Compute the average mark-sweep speed in bytes/millisecond.
395   // Returns 0 if no events have been recorded.
396   intptr_t MarkCompactSpeedInBytesPerMillisecond() const;
397
398   // Compute the average incremental mark-sweep finalize speed in
399   // bytes/millisecond.
400   // Returns 0 if no events have been recorded.
401   intptr_t FinalIncrementalMarkCompactSpeedInBytesPerMillisecond() const;
402
403   // Compute the overall mark compact speed including incremental steps
404   // and the final mark-compact step.
405   double CombinedMarkCompactSpeedInBytesPerMillisecond();
406
407   // Allocation throughput in the new space in bytes/millisecond.
408   // Returns 0 if no allocation events have been recorded.
409   size_t NewSpaceAllocationThroughputInBytesPerMillisecond(
410       double time_ms = 0) const;
411
412   // Allocation throughput in the old generation in bytes/millisecond in the
413   // last time_ms milliseconds.
414   // Returns 0 if no allocation events have been recorded.
415   size_t OldGenerationAllocationThroughputInBytesPerMillisecond(
416       double time_ms = 0) const;
417
418   // Allocation throughput in heap in bytes/millisecond in the last time_ms
419   // milliseconds.
420   // Returns 0 if no allocation events have been recorded.
421   size_t AllocationThroughputInBytesPerMillisecond(double time_ms) const;
422
423   // Allocation throughput in heap in bytes/milliseconds in the last
424   // kThroughputTimeFrameMs seconds.
425   // Returns 0 if no allocation events have been recorded.
426   size_t CurrentAllocationThroughputInBytesPerMillisecond() const;
427
428   // Allocation throughput in old generation in bytes/milliseconds in the last
429   // kThroughputTimeFrameMs seconds.
430   // Returns 0 if no allocation events have been recorded.
431   size_t CurrentOldGenerationAllocationThroughputInBytesPerMillisecond() const;
432
433   // Computes the context disposal rate in milliseconds. It takes the time
434   // frame of the first recorded context disposal to the current time and
435   // divides it by the number of recorded events.
436   // Returns 0 if no events have been recorded.
437   double ContextDisposalRateInMilliseconds() const;
438
439   // Computes the average survival ratio based on the last recorded survival
440   // events.
441   // Returns 0 if no events have been recorded.
442   double AverageSurvivalRatio() const;
443
444   // Returns true if at least one survival event was recorded.
445   bool SurvivalEventsRecorded() const;
446
447   // Discard all recorded survival events.
448   void ResetSurvivalEvents();
449
450  private:
451   // Print one detailed trace line in name=value format.
452   // TODO(ernstm): Move to Heap.
453   void PrintNVP() const;
454
455   // Print one trace line.
456   // TODO(ernstm): Move to Heap.
457   void Print() const;
458
459   // Prints a line and also adds it to the heap's ring buffer so that
460   // it can be included in later crash dumps.
461   void Output(const char* format, ...) const;
462
463   // Compute the mean duration of the events in the given ring buffer.
464   double MeanDuration(const EventBuffer& events) const;
465
466   // Compute the max duration of the events in the given ring buffer.
467   double MaxDuration(const EventBuffer& events) const;
468
469   void ClearMarkCompactStatistics() {
470     cumulative_incremental_marking_steps_ = 0;
471     cumulative_incremental_marking_bytes_ = 0;
472     cumulative_incremental_marking_duration_ = 0;
473     cumulative_pure_incremental_marking_duration_ = 0;
474     longest_incremental_marking_step_ = 0;
475     cumulative_marking_duration_ = 0;
476     cumulative_sweeping_duration_ = 0;
477   }
478
479   // Pointer to the heap that owns this tracer.
480   Heap* heap_;
481
482   // Current tracer event. Populated during Start/Stop cycle. Valid after Stop()
483   // has returned.
484   Event current_;
485
486   // Previous tracer event.
487   Event previous_;
488
489   // Previous INCREMENTAL_MARK_COMPACTOR event.
490   Event previous_incremental_mark_compactor_event_;
491
492   // RingBuffers for SCAVENGER events.
493   EventBuffer scavenger_events_;
494
495   // RingBuffers for MARK_COMPACTOR events.
496   EventBuffer mark_compactor_events_;
497
498   // RingBuffers for INCREMENTAL_MARK_COMPACTOR events.
499   EventBuffer incremental_mark_compactor_events_;
500
501   // RingBuffer for allocation events.
502   AllocationEventBuffer new_space_allocation_events_;
503   AllocationEventBuffer old_generation_allocation_events_;
504
505   // RingBuffer for context disposal events.
506   ContextDisposalEventBuffer context_disposal_events_;
507
508   // RingBuffer for survival events.
509   SurvivalEventBuffer survival_events_;
510
511   // Cumulative number of incremental marking steps since creation of tracer.
512   int cumulative_incremental_marking_steps_;
513
514   // Cumulative size of incremental marking steps (in bytes) since creation of
515   // tracer.
516   intptr_t cumulative_incremental_marking_bytes_;
517
518   // Cumulative duration of incremental marking steps since creation of tracer.
519   double cumulative_incremental_marking_duration_;
520
521   // Cumulative duration of pure incremental marking steps since creation of
522   // tracer.
523   double cumulative_pure_incremental_marking_duration_;
524
525   // Longest incremental marking step since start of marking.
526   double longest_incremental_marking_step_;
527
528   // Total marking time.
529   // This timer is precise when run with --print-cumulative-gc-stat
530   double cumulative_marking_duration_;
531
532   // Total sweeping time on the main thread.
533   // This timer is precise when run with --print-cumulative-gc-stat
534   // TODO(hpayer): Account for sweeping time on sweeper threads. Add a
535   // different field for that.
536   // TODO(hpayer): This timer right now just holds the sweeping time
537   // of the initial atomic sweeping pause. Make sure that it accumulates
538   // all sweeping operations performed on the main thread.
539   double cumulative_sweeping_duration_;
540
541   // Timestamp and allocation counter at the last sampled allocation event.
542   double allocation_time_ms_;
543   size_t new_space_allocation_counter_bytes_;
544   size_t old_generation_allocation_counter_bytes_;
545
546   // Accumulated duration and allocated bytes since the last GC.
547   double allocation_duration_since_gc_;
548   size_t new_space_allocation_in_bytes_since_gc_;
549   size_t old_generation_allocation_in_bytes_since_gc_;
550
551   double combined_mark_compact_speed_cache_;
552
553   // Counts how many tracers were started without stopping.
554   int start_counter_;
555
556   DISALLOW_COPY_AND_ASSIGN(GCTracer);
557 };
558 }
559 }  // namespace v8::internal
560
561 #endif  // V8_HEAP_GC_TRACER_H_