blob: 528eb52c6455f073f8ed4139278ac4f2ef7462a1 [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
Emily Bernierd0a1eb72015-03-24 16:35:39 -040074 void reset() {
75 begin_ = 0;
76 end_ = 0;
77 }
78
Ben Murdochb8a8cc12014-11-26 15:28:44 +000079 private:
80 T elements_[MAX_SIZE + 1];
81 size_t begin_;
82 size_t end_;
83
84 DISALLOW_COPY_AND_ASSIGN(RingBuffer);
85};
86
87
88// GCTracer collects and prints ONE line after each garbage collector
89// invocation IFF --trace_gc is used.
90// TODO(ernstm): Unit tests.
91class GCTracer {
92 public:
93 class Scope {
94 public:
95 enum ScopeId {
96 EXTERNAL,
97 MC_MARK,
98 MC_SWEEP,
99 MC_SWEEP_NEWSPACE,
100 MC_SWEEP_OLDSPACE,
101 MC_SWEEP_CODE,
102 MC_SWEEP_CELL,
103 MC_SWEEP_MAP,
104 MC_EVACUATE_PAGES,
105 MC_UPDATE_NEW_TO_NEW_POINTERS,
106 MC_UPDATE_ROOT_TO_NEW_POINTERS,
107 MC_UPDATE_OLD_TO_NEW_POINTERS,
108 MC_UPDATE_POINTERS_TO_EVACUATED,
109 MC_UPDATE_POINTERS_BETWEEN_EVACUATED,
110 MC_UPDATE_MISC_POINTERS,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400111 MC_WEAKCLOSURE,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000112 MC_WEAKCOLLECTION_PROCESS,
113 MC_WEAKCOLLECTION_CLEAR,
114 MC_WEAKCOLLECTION_ABORT,
115 MC_FLUSH_CODE,
116 NUMBER_OF_SCOPES
117 };
118
119 Scope(GCTracer* tracer, ScopeId scope) : tracer_(tracer), scope_(scope) {
120 start_time_ = base::OS::TimeCurrentMillis();
121 }
122
123 ~Scope() {
124 DCHECK(scope_ < NUMBER_OF_SCOPES); // scope_ is unsigned.
125 tracer_->current_.scopes[scope_] +=
126 base::OS::TimeCurrentMillis() - start_time_;
127 }
128
129 private:
130 GCTracer* tracer_;
131 ScopeId scope_;
132 double start_time_;
133
134 DISALLOW_COPY_AND_ASSIGN(Scope);
135 };
136
137
138 class AllocationEvent {
139 public:
140 // Default constructor leaves the event uninitialized.
141 AllocationEvent() {}
142
143 AllocationEvent(double duration, intptr_t allocation_in_bytes);
144
145 // Time spent in the mutator during the end of the last garbage collection
146 // to the beginning of the next garbage collection.
147 double duration_;
148
149 // Memory allocated in the new space during the end of the last garbage
150 // collection to the beginning of the next garbage collection.
151 intptr_t allocation_in_bytes_;
152 };
153
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400154
155 class ContextDisposalEvent {
156 public:
157 // Default constructor leaves the event uninitialized.
158 ContextDisposalEvent() {}
159
160 explicit ContextDisposalEvent(double time);
161
162 // Time when context disposal event happened.
163 double time_;
164 };
165
166
167 class SurvivalEvent {
168 public:
169 // Default constructor leaves the event uninitialized.
170 SurvivalEvent() {}
171
172 explicit SurvivalEvent(double survival_rate);
173
174 double survival_rate_;
175 };
176
177
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000178 class Event {
179 public:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400180 enum Type {
181 SCAVENGER = 0,
182 MARK_COMPACTOR = 1,
183 INCREMENTAL_MARK_COMPACTOR = 2,
184 START = 3
185 };
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000186
187 // Default constructor leaves the event uninitialized.
188 Event() {}
189
190 Event(Type type, const char* gc_reason, const char* collector_reason);
191
192 // Returns a string describing the event type.
193 const char* TypeName(bool short_name) const;
194
195 // Type of event
196 Type type;
197
198 const char* gc_reason;
199 const char* collector_reason;
200
201 // Timestamp set in the constructor.
202 double start_time;
203
204 // Timestamp set in the destructor.
205 double end_time;
206
207 // Size of objects in heap set in constructor.
208 intptr_t start_object_size;
209
210 // Size of objects in heap set in destructor.
211 intptr_t end_object_size;
212
213 // Size of memory allocated from OS set in constructor.
214 intptr_t start_memory_size;
215
216 // Size of memory allocated from OS set in destructor.
217 intptr_t end_memory_size;
218
219 // Total amount of space either wasted or contained in one of free lists
220 // before the current GC.
221 intptr_t start_holes_size;
222
223 // Total amount of space either wasted or contained in one of free lists
224 // after the current GC.
225 intptr_t end_holes_size;
226
227 // Size of new space objects in constructor.
228 intptr_t new_space_object_size;
229
230 // Number of incremental marking steps since creation of tracer.
231 // (value at start of event)
232 int cumulative_incremental_marking_steps;
233
234 // Incremental marking steps since
235 // - last event for SCAVENGER events
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400236 // - last INCREMENTAL_MARK_COMPACTOR event for INCREMENTAL_MARK_COMPACTOR
237 // events
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000238 int incremental_marking_steps;
239
240 // Bytes marked since creation of tracer (value at start of event).
241 intptr_t cumulative_incremental_marking_bytes;
242
243 // Bytes marked since
244 // - last event for SCAVENGER events
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400245 // - last INCREMENTAL_MARK_COMPACTOR event for INCREMENTAL_MARK_COMPACTOR
246 // events
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000247 intptr_t incremental_marking_bytes;
248
249 // Cumulative duration of incremental marking steps since creation of
250 // tracer. (value at start of event)
251 double cumulative_incremental_marking_duration;
252
253 // Duration of incremental marking steps since
254 // - last event for SCAVENGER events
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400255 // - last INCREMENTAL_MARK_COMPACTOR event for INCREMENTAL_MARK_COMPACTOR
256 // events
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000257 double incremental_marking_duration;
258
259 // Cumulative pure duration of incremental marking steps since creation of
260 // tracer. (value at start of event)
261 double cumulative_pure_incremental_marking_duration;
262
263 // Duration of pure incremental marking steps since
264 // - last event for SCAVENGER events
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400265 // - last INCREMENTAL_MARK_COMPACTOR event for INCREMENTAL_MARK_COMPACTOR
266 // events
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000267 double pure_incremental_marking_duration;
268
269 // Longest incremental marking step since start of marking.
270 // (value at start of event)
271 double longest_incremental_marking_step;
272
273 // Amounts of time spent in different scopes during GC.
274 double scopes[Scope::NUMBER_OF_SCOPES];
275 };
276
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400277 static const size_t kRingBufferMaxSize = 10;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000278
279 typedef RingBuffer<Event, kRingBufferMaxSize> EventBuffer;
280
281 typedef RingBuffer<AllocationEvent, kRingBufferMaxSize> AllocationEventBuffer;
282
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400283 typedef RingBuffer<ContextDisposalEvent, kRingBufferMaxSize>
284 ContextDisposalEventBuffer;
285
286 typedef RingBuffer<SurvivalEvent, kRingBufferMaxSize> SurvivalEventBuffer;
287
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000288 explicit GCTracer(Heap* heap);
289
290 // Start collecting data.
291 void Start(GarbageCollector collector, const char* gc_reason,
292 const char* collector_reason);
293
294 // Stop collecting data and print results.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400295 void Stop(GarbageCollector collector);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000296
297 // Log an allocation throughput event.
298 void AddNewSpaceAllocationTime(double duration, intptr_t allocation_in_bytes);
299
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400300 void AddContextDisposalTime(double time);
301
302 void AddSurvivalRate(double survival_rate);
303
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000304 // Log an incremental marking step.
305 void AddIncrementalMarkingStep(double duration, intptr_t bytes);
306
307 // Log time spent in marking.
308 void AddMarkingTime(double duration) {
309 cumulative_marking_duration_ += duration;
310 }
311
312 // Time spent in marking.
313 double cumulative_marking_duration() const {
314 return cumulative_marking_duration_;
315 }
316
317 // Log time spent in sweeping on main thread.
318 void AddSweepingTime(double duration) {
319 cumulative_sweeping_duration_ += duration;
320 }
321
322 // Time spent in sweeping on main thread.
323 double cumulative_sweeping_duration() const {
324 return cumulative_sweeping_duration_;
325 }
326
327 // Compute the mean duration of the last scavenger events. Returns 0 if no
328 // events have been recorded.
329 double MeanScavengerDuration() const {
330 return MeanDuration(scavenger_events_);
331 }
332
333 // Compute the max duration of the last scavenger events. Returns 0 if no
334 // events have been recorded.
335 double MaxScavengerDuration() const { return MaxDuration(scavenger_events_); }
336
337 // Compute the mean duration of the last mark compactor events. Returns 0 if
338 // no events have been recorded.
339 double MeanMarkCompactorDuration() const {
340 return MeanDuration(mark_compactor_events_);
341 }
342
343 // Compute the max duration of the last mark compactor events. Return 0 if no
344 // events have been recorded.
345 double MaxMarkCompactorDuration() const {
346 return MaxDuration(mark_compactor_events_);
347 }
348
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400349 // Compute the mean duration of the last incremental mark compactor
350 // events. Returns 0 if no events have been recorded.
351 double MeanIncrementalMarkCompactorDuration() const {
352 return MeanDuration(incremental_mark_compactor_events_);
353 }
354
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000355 // Compute the mean step duration of the last incremental marking round.
356 // Returns 0 if no incremental marking round has been completed.
357 double MeanIncrementalMarkingDuration() const;
358
359 // Compute the max step duration of the last incremental marking round.
360 // Returns 0 if no incremental marking round has been completed.
361 double MaxIncrementalMarkingDuration() const;
362
363 // Compute the average incremental marking speed in bytes/millisecond.
364 // Returns 0 if no events have been recorded.
365 intptr_t IncrementalMarkingSpeedInBytesPerMillisecond() const;
366
367 // Compute the average scavenge speed in bytes/millisecond.
368 // Returns 0 if no events have been recorded.
369 intptr_t ScavengeSpeedInBytesPerMillisecond() const;
370
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400371 // Compute the average mark-sweep speed in bytes/millisecond.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000372 // Returns 0 if no events have been recorded.
373 intptr_t MarkCompactSpeedInBytesPerMillisecond() const;
374
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400375 // Compute the average incremental mark-sweep finalize speed in
376 // bytes/millisecond.
377 // Returns 0 if no events have been recorded.
378 intptr_t FinalIncrementalMarkCompactSpeedInBytesPerMillisecond() const;
379
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000380 // Allocation throughput in the new space in bytes/millisecond.
381 // Returns 0 if no events have been recorded.
382 intptr_t NewSpaceAllocationThroughputInBytesPerMillisecond() const;
383
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400384 // Computes the context disposal rate in milliseconds. It takes the time
385 // frame of the first recorded context disposal to the current time and
386 // divides it by the number of recorded events.
387 // Returns 0 if no events have been recorded.
388 double ContextDisposalRateInMilliseconds() const;
389
390 // Computes the average survival rate based on the last recorded survival
391 // events.
392 // Returns 0 if no events have been recorded.
393 double AverageSurvivalRate() const;
394
395 // Returns true if at least one survival event was recorded.
396 bool SurvivalEventsRecorded() const;
397
398 // Discard all recorded survival events.
399 void ResetSurvivalEvents();
400
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000401 private:
402 // Print one detailed trace line in name=value format.
403 // TODO(ernstm): Move to Heap.
404 void PrintNVP() const;
405
406 // Print one trace line.
407 // TODO(ernstm): Move to Heap.
408 void Print() const;
409
410 // Compute the mean duration of the events in the given ring buffer.
411 double MeanDuration(const EventBuffer& events) const;
412
413 // Compute the max duration of the events in the given ring buffer.
414 double MaxDuration(const EventBuffer& events) const;
415
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400416 void ClearMarkCompactStatistics() {
417 cumulative_incremental_marking_steps_ = 0;
418 cumulative_incremental_marking_bytes_ = 0;
419 cumulative_incremental_marking_duration_ = 0;
420 cumulative_pure_incremental_marking_duration_ = 0;
421 longest_incremental_marking_step_ = 0;
422 cumulative_marking_duration_ = 0;
423 cumulative_sweeping_duration_ = 0;
424 }
425
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000426 // Pointer to the heap that owns this tracer.
427 Heap* heap_;
428
429 // Current tracer event. Populated during Start/Stop cycle. Valid after Stop()
430 // has returned.
431 Event current_;
432
433 // Previous tracer event.
434 Event previous_;
435
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400436 // Previous INCREMENTAL_MARK_COMPACTOR event.
437 Event previous_incremental_mark_compactor_event_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000438
439 // RingBuffers for SCAVENGER events.
440 EventBuffer scavenger_events_;
441
442 // RingBuffers for MARK_COMPACTOR events.
443 EventBuffer mark_compactor_events_;
444
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400445 // RingBuffers for INCREMENTAL_MARK_COMPACTOR events.
446 EventBuffer incremental_mark_compactor_events_;
447
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000448 // RingBuffer for allocation events.
449 AllocationEventBuffer allocation_events_;
450
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400451 // RingBuffer for context disposal events.
452 ContextDisposalEventBuffer context_disposal_events_;
453
454 // RingBuffer for survival events.
455 SurvivalEventBuffer survival_events_;
456
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000457 // Cumulative number of incremental marking steps since creation of tracer.
458 int cumulative_incremental_marking_steps_;
459
460 // Cumulative size of incremental marking steps (in bytes) since creation of
461 // tracer.
462 intptr_t cumulative_incremental_marking_bytes_;
463
464 // Cumulative duration of incremental marking steps since creation of tracer.
465 double cumulative_incremental_marking_duration_;
466
467 // Cumulative duration of pure incremental marking steps since creation of
468 // tracer.
469 double cumulative_pure_incremental_marking_duration_;
470
471 // Longest incremental marking step since start of marking.
472 double longest_incremental_marking_step_;
473
474 // Total marking time.
475 // This timer is precise when run with --print-cumulative-gc-stat
476 double cumulative_marking_duration_;
477
478 // Total sweeping time on the main thread.
479 // This timer is precise when run with --print-cumulative-gc-stat
480 // TODO(hpayer): Account for sweeping time on sweeper threads. Add a
481 // different field for that.
482 // TODO(hpayer): This timer right now just holds the sweeping time
483 // of the initial atomic sweeping pause. Make sure that it accumulates
484 // all sweeping operations performed on the main thread.
485 double cumulative_sweeping_duration_;
486
487 // Holds the new space top pointer recorded at the end of the last garbage
488 // collection.
489 intptr_t new_space_top_after_gc_;
490
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400491 // Counts how many tracers were started without stopping.
492 int start_counter_;
493
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000494 DISALLOW_COPY_AND_ASSIGN(GCTracer);
495};
496}
497} // namespace v8::internal
498
499#endif // V8_HEAP_GC_TRACER_H_