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:
const_iterator()20     const_iterator() : index_(0), elements_(NULL) {}
21 
const_iterator(size_t index,const T * elements)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 
RingBuffer()54   RingBuffer() : begin_(0), end_(0) {}
55 
empty()56   bool empty() const { return begin_ == end_; }
size()57   size_t size() const {
58     return (end_ - begin_ + MAX_SIZE + 1) % (MAX_SIZE + 1);
59   }
begin()60   const_iterator begin() const { return const_iterator(begin_, elements_); }
end()61   const_iterator end() const { return const_iterator(end_, elements_); }
back()62   const_iterator back() const { return --end(); }
push_back(const T & element)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   }
push_front(const T & element)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 
Scope(GCTracer * tracer,ScopeId scope)113     Scope(GCTracer* tracer, ScopeId scope) : tracer_(tracer), scope_(scope) {
114       start_time_ = base::OS::TimeCurrentMillis();
115     }
116 
~Scope()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.
AllocationEvent()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.
Event()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.
AddMarkingTime(double duration)260   void AddMarkingTime(double duration) {
261     cumulative_marking_duration_ += duration;
262   }
263 
264   // Time spent in marking.
cumulative_marking_duration()265   double cumulative_marking_duration() const {
266     return cumulative_marking_duration_;
267   }
268 
269   // Log time spent in sweeping on main thread.
AddSweepingTime(double duration)270   void AddSweepingTime(double duration) {
271     cumulative_sweeping_duration_ += duration;
272   }
273 
274   // Time spent in sweeping on main thread.
cumulative_sweeping_duration()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.
MeanScavengerDuration()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.
MaxScavengerDuration()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.
MeanMarkCompactorDuration()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.
MaxMarkCompactorDuration()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