blob: 4e70f0741c5aaf0e05c9a7297bbbf972e6ce4527 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
10namespace v8 {
11namespace 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.
15template <typename T, size_t MAX_SIZE>
16class 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.
86class 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_