Index: src/gc-tracer.h |
diff --git a/src/gc-tracer.h b/src/gc-tracer.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a9e02b3118daabca29bc07174d17d43c2ae223db |
--- /dev/null |
+++ b/src/gc-tracer.h |
@@ -0,0 +1,247 @@ |
+// Copyright 2014 the V8 project authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef V8_GC_TRACER_H_ |
+#define V8_GC_TRACER_H_ |
+ |
+namespace v8 { |
+namespace internal { |
+ |
+// A simple ring buffer class with maximum size known at compile time. |
+// The class only implements the functionality required in GCTracer. |
+template <typename T, size_t MAX_SIZE> |
+class RingBuffer { |
+ public: |
+ class const_iterator { |
+ public: |
+ const_iterator() : index_(0), elements_(NULL) {} |
+ |
+ const_iterator(size_t index, const T* elements) |
+ : index_(index), elements_(elements) {} |
+ |
+ bool operator==(const const_iterator& rhs) const { |
+ return elements_ == rhs.elements_ && index_ == rhs.index_; |
+ } |
+ |
+ bool operator!=(const const_iterator& rhs) const { |
+ return elements_ != rhs.elements_ || index_ != rhs.index_; |
+ } |
+ |
+ operator const T*() const { return elements_ + index_; } |
+ |
+ const T* operator->() const { return elements_ + index_; } |
+ |
+ const T& operator*() const { return elements_[index_]; } |
+ |
+ const_iterator& operator++() { |
+ index_ = (index_ + 1) % (MAX_SIZE + 1); |
+ return *this; |
+ } |
+ |
+ const_iterator& operator--() { |
+ index_ = (index_ + MAX_SIZE) % (MAX_SIZE + 1); |
+ return *this; |
+ } |
+ |
+ private: |
+ size_t index_; |
+ const T* elements_; |
+ }; |
+ |
+ RingBuffer() : begin_(0), end_(0) {} |
+ |
+ bool empty() const { return begin_ == end_; } |
+ size_t size() const { |
+ return (end_ - begin_ + MAX_SIZE + 1) % (MAX_SIZE + 1); |
+ } |
+ const_iterator begin() const { return const_iterator(begin_, elements_); } |
+ const_iterator end() const { return const_iterator(end_, elements_); } |
+ const_iterator back() const { return --end(); } |
+ void push_back(const T& element) { |
+ elements_[end_] = element; |
+ end_ = (end_ + 1) % (MAX_SIZE + 1); |
+ if (end_ == begin_) begin_ = (begin_ + 1) % (MAX_SIZE + 1); |
+ } |
+ void push_front(const T& element) { |
+ begin_ = (begin_ + MAX_SIZE) % (MAX_SIZE + 1); |
+ if (begin_ == end_) end_ = (end_ + MAX_SIZE) % (MAX_SIZE + 1); |
+ elements_[begin_] = element; |
+ } |
+ |
+ private: |
+ T elements_[MAX_SIZE + 1]; |
+ size_t begin_; |
+ size_t end_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(RingBuffer); |
+}; |
+ |
+ |
+// GCTracer collects and prints ONE line after each garbage collector |
+// invocation IFF --trace_gc is used. |
+// TODO(ernstm): Unit tests. |
+class GCTracer BASE_EMBEDDED { |
+ public: |
+ class Scope BASE_EMBEDDED { |
+ public: |
+ enum ScopeId { |
+ EXTERNAL, |
+ MC_MARK, |
+ MC_SWEEP, |
+ MC_SWEEP_NEWSPACE, |
+ MC_SWEEP_OLDSPACE, |
+ MC_SWEEP_CODE, |
+ MC_SWEEP_CELL, |
+ MC_SWEEP_MAP, |
+ MC_EVACUATE_PAGES, |
+ MC_UPDATE_NEW_TO_NEW_POINTERS, |
+ MC_UPDATE_ROOT_TO_NEW_POINTERS, |
+ MC_UPDATE_OLD_TO_NEW_POINTERS, |
+ MC_UPDATE_POINTERS_TO_EVACUATED, |
+ MC_UPDATE_POINTERS_BETWEEN_EVACUATED, |
+ MC_UPDATE_MISC_POINTERS, |
+ MC_WEAKCOLLECTION_PROCESS, |
+ MC_WEAKCOLLECTION_CLEAR, |
+ MC_FLUSH_CODE, |
+ NUMBER_OF_SCOPES |
+ }; |
+ |
+ Scope(GCTracer* tracer, ScopeId scope) : tracer_(tracer), scope_(scope) { |
+ start_time_ = base::OS::TimeCurrentMillis(); |
+ } |
+ |
+ ~Scope() { |
+ ASSERT(scope_ < NUMBER_OF_SCOPES); // scope_ is unsigned. |
+ tracer_->current_.scopes[scope_] += |
+ base::OS::TimeCurrentMillis() - start_time_; |
+ } |
+ |
+ private: |
+ GCTracer* tracer_; |
+ ScopeId scope_; |
+ double start_time_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(Scope); |
+ }; |
+ |
+ |
+ class Event { |
+ public: |
+ enum Type { SCAVENGER = 0, MARK_COMPACTOR = 1, START = 2 }; |
+ |
+ // Default constructor leaves the event uninitialized. |
+ Event() {} |
+ |
+ Event(Type type, const char* gc_reason, const char* collector_reason); |
+ |
+ // Returns a string describing the event type. |
+ const char* TypeName(bool short_name) const; |
+ |
+ // Type of event |
+ Type type; |
+ |
+ const char* gc_reason; |
+ const char* collector_reason; |
+ |
+ // Timestamp set in the constructor. |
+ double start_time; |
+ |
+ // Timestamp set in the destructor. |
+ double end_time; |
+ |
+ // Size of objects in heap set in constructor. |
+ intptr_t start_object_size; |
+ |
+ // Size of objects in heap set in destructor. |
+ intptr_t end_object_size; |
+ |
+ // Size of memory allocated from OS set in constructor. |
+ intptr_t start_memory_size; |
+ |
+ // Size of memory allocated from OS set in destructor. |
+ intptr_t end_memory_size; |
+ |
+ // Total amount of space either wasted or contained in one of free lists |
+ // before the current GC. |
+ intptr_t start_holes_size; |
+ |
+ // Total amount of space either wasted or contained in one of free lists |
+ // after the current GC. |
+ intptr_t end_holes_size; |
+ |
+ // Number of incremental marking steps since creation of tracer. |
+ // (value at start of event) |
+ int incremental_marking_steps; |
+ |
+ // Cumulative duration of incremental marking steps since creation of |
+ // tracer. (value at start of event) |
+ double incremental_marking_duration; |
+ |
+ // Longest incremental marking step since start of marking. |
+ // (value at start of event) |
+ double longest_incremental_marking_step; |
+ |
+ // Amounts of time spent in different scopes during GC. |
+ double scopes[Scope::NUMBER_OF_SCOPES]; |
+ }; |
+ |
+ static const int kRingBufferMaxSize = 10; |
+ |
+ typedef RingBuffer<Event, kRingBufferMaxSize> EventBuffer; |
+ |
+ explicit GCTracer(Heap* heap); |
+ |
+ // Start collecting data. |
+ void Start(GarbageCollector collector, const char* gc_reason, |
+ const char* collector_reason); |
+ |
+ // Stop collecting data and print results. |
+ void Stop(); |
+ |
+ // Log an incremental marking step. |
+ void AddIncrementalMarkingStep(double duration); |
+ |
+ private: |
+ // Print one detailed trace line in name=value format. |
+ // TODO(ernstm): Move to Heap. |
+ void PrintNVP() const; |
+ |
+ // Print one trace line. |
+ // TODO(ernstm): Move to Heap. |
+ void Print() const; |
+ |
+ // Pointer to the heap that owns this tracer. |
+ Heap* heap_; |
+ |
+ // Current tracer event. Populated during Start/Stop cycle. Valid after Stop() |
+ // has returned. |
+ Event current_; |
+ |
+ // Previous tracer event. |
+ Event previous_; |
+ |
+ // Previous MARK_COMPACTOR event. |
+ Event previous_mark_compactor_event_; |
+ |
+ // RingBuffers for SCAVENGER events. |
+ EventBuffer scavenger_events_; |
+ |
+ // RingBuffers for MARK_COMPACTOR events. |
+ EventBuffer mark_compactor_events_; |
+ |
+ // Cumulative number of incremental marking steps since creation of tracer. |
+ int incremental_marking_steps_; |
+ |
+ // Cumulative duration of incremental marking steps since creation of tracer. |
+ double incremental_marking_duration_; |
+ |
+ // Longest incremental marking step since start of marking. |
+ double longest_incremental_marking_step_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(GCTracer); |
+}; |
+} |
+} // namespace v8::internal |
+ |
+#endif // V8_GC_TRACER_H_ |