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.
5 #ifndef V8_HEAP_GC_TRACER_H_
6 #define V8_HEAP_GC_TRACER_H_
8 #include "src/base/platform/platform.h"
9 #include "src/globals.h"
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>
19 class const_iterator {
21 const_iterator() : index_(0), elements_(NULL) {}
23 const_iterator(size_t index, const T* elements)
24 : index_(index), elements_(elements) {}
26 bool operator==(const const_iterator& rhs) const {
27 return elements_ == rhs.elements_ && index_ == rhs.index_;
30 bool operator!=(const const_iterator& rhs) const {
31 return elements_ != rhs.elements_ || index_ != rhs.index_;
34 operator const T*() const { return elements_ + index_; }
36 const T* operator->() const { return elements_ + index_; }
38 const T& operator*() const { return elements_[index_]; }
40 const_iterator& operator++() {
41 index_ = (index_ + 1) % (MAX_SIZE + 1);
45 const_iterator& operator--() {
46 index_ = (index_ + MAX_SIZE) % (MAX_SIZE + 1);
55 RingBuffer() : begin_(0), end_(0) {}
57 bool empty() const { return begin_ == end_; }
59 return (end_ - begin_ + MAX_SIZE + 1) % (MAX_SIZE + 1);
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);
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;
81 T elements_[MAX_SIZE + 1];
85 DISALLOW_COPY_AND_ASSIGN(RingBuffer);
89 enum ScavengeSpeedMode { kForAllObjects, kForSurvivedObjects };
92 // GCTracer collects and prints ONE line after each garbage collector
93 // invocation IFF --trace_gc is used.
94 // TODO(ernstm): Unit tests.
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,
117 MC_WEAKCOLLECTION_PROCESS,
118 MC_WEAKCOLLECTION_CLEAR,
119 MC_WEAKCOLLECTION_ABORT,
121 MC_NONLIVEREFERENCES,
123 SCAVENGER_CODE_FLUSH_CANDIDATES,
124 SCAVENGER_OBJECT_GROUPS,
125 SCAVENGER_OLD_TO_NEW_POINTERS,
133 Scope(GCTracer* tracer, ScopeId scope) : tracer_(tracer), scope_(scope) {
134 start_time_ = base::OS::TimeCurrentMillis();
138 DCHECK(scope_ < NUMBER_OF_SCOPES); // scope_ is unsigned.
139 tracer_->current_.scopes[scope_] +=
140 base::OS::TimeCurrentMillis() - start_time_;
148 DISALLOW_COPY_AND_ASSIGN(Scope);
152 class AllocationEvent {
154 // Default constructor leaves the event uninitialized.
157 AllocationEvent(double duration, size_t allocation_in_bytes);
159 // Time spent in the mutator during the end of the last sample to the
160 // beginning of the next sample.
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_;
169 class ContextDisposalEvent {
171 // Default constructor leaves the event uninitialized.
172 ContextDisposalEvent() {}
174 explicit ContextDisposalEvent(double time);
176 // Time when context disposal event happened.
181 class SurvivalEvent {
183 // Default constructor leaves the event uninitialized.
186 explicit SurvivalEvent(double survival_ratio);
188 double promotion_ratio_;
197 INCREMENTAL_MARK_COMPACTOR = 2,
201 // Default constructor leaves the event uninitialized.
204 Event(Type type, const char* gc_reason, const char* collector_reason);
206 // Returns a string describing the event type.
207 const char* TypeName(bool short_name) const;
212 const char* gc_reason;
213 const char* collector_reason;
215 // Timestamp set in the constructor.
218 // Timestamp set in the destructor.
221 // Size of objects in heap set in constructor.
222 intptr_t start_object_size;
224 // Size of objects in heap set in destructor.
225 intptr_t end_object_size;
227 // Size of memory allocated from OS set in constructor.
228 intptr_t start_memory_size;
230 // Size of memory allocated from OS set in destructor.
231 intptr_t end_memory_size;
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;
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;
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;
246 // Number of incremental marking steps since creation of tracer.
247 // (value at start of event)
248 int cumulative_incremental_marking_steps;
250 // Incremental marking steps since
251 // - last event for SCAVENGER events
252 // - last INCREMENTAL_MARK_COMPACTOR event for INCREMENTAL_MARK_COMPACTOR
254 int incremental_marking_steps;
256 // Bytes marked since creation of tracer (value at start of event).
257 intptr_t cumulative_incremental_marking_bytes;
259 // Bytes marked since
260 // - last event for SCAVENGER events
261 // - last INCREMENTAL_MARK_COMPACTOR event for INCREMENTAL_MARK_COMPACTOR
263 intptr_t incremental_marking_bytes;
265 // Cumulative duration of incremental marking steps since creation of
266 // tracer. (value at start of event)
267 double cumulative_incremental_marking_duration;
269 // Duration of incremental marking steps since
270 // - last event for SCAVENGER events
271 // - last INCREMENTAL_MARK_COMPACTOR event for INCREMENTAL_MARK_COMPACTOR
273 double incremental_marking_duration;
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;
279 // Duration of pure incremental marking steps since
280 // - last event for SCAVENGER events
281 // - last INCREMENTAL_MARK_COMPACTOR event for INCREMENTAL_MARK_COMPACTOR
283 double pure_incremental_marking_duration;
285 // Longest incremental marking step since start of marking.
286 // (value at start of event)
287 double longest_incremental_marking_step;
289 // Amounts of time spent in different scopes during GC.
290 double scopes[Scope::NUMBER_OF_SCOPES];
293 static const size_t kRingBufferMaxSize = 10;
295 typedef RingBuffer<Event, kRingBufferMaxSize> EventBuffer;
297 typedef RingBuffer<AllocationEvent, kRingBufferMaxSize> AllocationEventBuffer;
299 typedef RingBuffer<ContextDisposalEvent, kRingBufferMaxSize>
300 ContextDisposalEventBuffer;
302 typedef RingBuffer<SurvivalEvent, kRingBufferMaxSize> SurvivalEventBuffer;
304 static const int kThroughputTimeFrameMs = 5000;
306 explicit GCTracer(Heap* heap);
308 // Start collecting data.
309 void Start(GarbageCollector collector, const char* gc_reason,
310 const char* collector_reason);
312 // Stop collecting data and print results.
313 void Stop(GarbageCollector collector);
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);
319 // Log the accumulated new space allocation bytes.
320 void AddAllocation(double current_ms);
322 void AddContextDisposalTime(double time);
324 void AddSurvivalRatio(double survival_ratio);
326 // Log an incremental marking step.
327 void AddIncrementalMarkingStep(double duration, intptr_t bytes);
329 // Log time spent in marking.
330 void AddMarkingTime(double duration) {
331 cumulative_marking_duration_ += duration;
334 // Time spent in marking.
335 double cumulative_marking_duration() const {
336 return cumulative_marking_duration_;
339 // Log time spent in sweeping on main thread.
340 void AddSweepingTime(double duration) {
341 cumulative_sweeping_duration_ += duration;
344 // Time spent in sweeping on main thread.
345 double cumulative_sweeping_duration() const {
346 return cumulative_sweeping_duration_;
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_);
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_); }
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_);
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_);
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_);
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;
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;
385 // Compute the average incremental marking speed in bytes/millisecond.
386 // Returns 0 if no events have been recorded.
387 intptr_t IncrementalMarkingSpeedInBytesPerMillisecond() const;
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;
394 // Compute the average mark-sweep speed in bytes/millisecond.
395 // Returns 0 if no events have been recorded.
396 intptr_t MarkCompactSpeedInBytesPerMillisecond() const;
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;
403 // Compute the overall mark compact speed including incremental steps
404 // and the final mark-compact step.
405 double CombinedMarkCompactSpeedInBytesPerMillisecond();
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;
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;
418 // Allocation throughput in heap in bytes/millisecond in the last time_ms
420 // Returns 0 if no allocation events have been recorded.
421 size_t AllocationThroughputInBytesPerMillisecond(double time_ms) const;
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;
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;
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;
439 // Computes the average survival ratio based on the last recorded survival
441 // Returns 0 if no events have been recorded.
442 double AverageSurvivalRatio() const;
444 // Returns true if at least one survival event was recorded.
445 bool SurvivalEventsRecorded() const;
447 // Discard all recorded survival events.
448 void ResetSurvivalEvents();
451 // Print one detailed trace line in name=value format.
452 // TODO(ernstm): Move to Heap.
453 void PrintNVP() const;
455 // Print one trace line.
456 // TODO(ernstm): Move to Heap.
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;
463 // Compute the mean duration of the events in the given ring buffer.
464 double MeanDuration(const EventBuffer& events) const;
466 // Compute the max duration of the events in the given ring buffer.
467 double MaxDuration(const EventBuffer& events) const;
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;
479 // Pointer to the heap that owns this tracer.
482 // Current tracer event. Populated during Start/Stop cycle. Valid after Stop()
486 // Previous tracer event.
489 // Previous INCREMENTAL_MARK_COMPACTOR event.
490 Event previous_incremental_mark_compactor_event_;
492 // RingBuffers for SCAVENGER events.
493 EventBuffer scavenger_events_;
495 // RingBuffers for MARK_COMPACTOR events.
496 EventBuffer mark_compactor_events_;
498 // RingBuffers for INCREMENTAL_MARK_COMPACTOR events.
499 EventBuffer incremental_mark_compactor_events_;
501 // RingBuffer for allocation events.
502 AllocationEventBuffer new_space_allocation_events_;
503 AllocationEventBuffer old_generation_allocation_events_;
505 // RingBuffer for context disposal events.
506 ContextDisposalEventBuffer context_disposal_events_;
508 // RingBuffer for survival events.
509 SurvivalEventBuffer survival_events_;
511 // Cumulative number of incremental marking steps since creation of tracer.
512 int cumulative_incremental_marking_steps_;
514 // Cumulative size of incremental marking steps (in bytes) since creation of
516 intptr_t cumulative_incremental_marking_bytes_;
518 // Cumulative duration of incremental marking steps since creation of tracer.
519 double cumulative_incremental_marking_duration_;
521 // Cumulative duration of pure incremental marking steps since creation of
523 double cumulative_pure_incremental_marking_duration_;
525 // Longest incremental marking step since start of marking.
526 double longest_incremental_marking_step_;
528 // Total marking time.
529 // This timer is precise when run with --print-cumulative-gc-stat
530 double cumulative_marking_duration_;
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_;
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_;
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_;
551 double combined_mark_compact_speed_cache_;
553 // Counts how many tracers were started without stopping.
556 DISALLOW_COPY_AND_ASSIGN(GCTracer);
559 } // namespace v8::internal
561 #endif // V8_HEAP_GC_TRACER_H_