| OLD | NEW |
| (Empty) |
| 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_GC_TRACER_H_ | |
| 6 #define V8_GC_TRACER_H_ | |
| 7 | |
| 8 namespace v8 { | |
| 9 namespace internal { | |
| 10 | |
| 11 // A simple ring buffer class with maximum size known at compile time. | |
| 12 // The class only implements the functionality required in GCTracer. | |
| 13 template <typename T, size_t MAX_SIZE> | |
| 14 class RingBuffer { | |
| 15 public: | |
| 16 class const_iterator { | |
| 17 public: | |
| 18 const_iterator() : index_(0), elements_(NULL) {} | |
| 19 | |
| 20 const_iterator(size_t index, const T* elements) | |
| 21 : index_(index), elements_(elements) {} | |
| 22 | |
| 23 bool operator==(const const_iterator& rhs) const { | |
| 24 return elements_ == rhs.elements_ && index_ == rhs.index_; | |
| 25 } | |
| 26 | |
| 27 bool operator!=(const const_iterator& rhs) const { | |
| 28 return elements_ != rhs.elements_ || index_ != rhs.index_; | |
| 29 } | |
| 30 | |
| 31 operator const T*() const { return elements_ + index_; } | |
| 32 | |
| 33 const T* operator->() const { return elements_ + index_; } | |
| 34 | |
| 35 const T& operator*() const { return elements_[index_]; } | |
| 36 | |
| 37 const_iterator& operator++() { | |
| 38 index_ = (index_ + 1) % (MAX_SIZE + 1); | |
| 39 return *this; | |
| 40 } | |
| 41 | |
| 42 const_iterator& operator--() { | |
| 43 index_ = (index_ + MAX_SIZE) % (MAX_SIZE + 1); | |
| 44 return *this; | |
| 45 } | |
| 46 | |
| 47 private: | |
| 48 size_t index_; | |
| 49 const T* elements_; | |
| 50 }; | |
| 51 | |
| 52 RingBuffer() : begin_(0), end_(0) {} | |
| 53 | |
| 54 bool empty() const { return begin_ == end_; } | |
| 55 size_t size() const { | |
| 56 return (end_ - begin_ + MAX_SIZE + 1) % (MAX_SIZE + 1); | |
| 57 } | |
| 58 const_iterator begin() const { return const_iterator(begin_, elements_); } | |
| 59 const_iterator end() const { return const_iterator(end_, elements_); } | |
| 60 const_iterator back() const { return --end(); } | |
| 61 void push_back(const T& element) { | |
| 62 elements_[end_] = element; | |
| 63 end_ = (end_ + 1) % (MAX_SIZE + 1); | |
| 64 if (end_ == begin_) begin_ = (begin_ + 1) % (MAX_SIZE + 1); | |
| 65 } | |
| 66 void push_front(const T& element) { | |
| 67 begin_ = (begin_ + MAX_SIZE) % (MAX_SIZE + 1); | |
| 68 if (begin_ == end_) end_ = (end_ + MAX_SIZE) % (MAX_SIZE + 1); | |
| 69 elements_[begin_] = element; | |
| 70 } | |
| 71 | |
| 72 private: | |
| 73 T elements_[MAX_SIZE + 1]; | |
| 74 size_t begin_; | |
| 75 size_t end_; | |
| 76 | |
| 77 DISALLOW_COPY_AND_ASSIGN(RingBuffer); | |
| 78 }; | |
| 79 | |
| 80 | |
| 81 // GCTracer collects and prints ONE line after each garbage collector | |
| 82 // invocation IFF --trace_gc is used. | |
| 83 // TODO(ernstm): Unit tests. | |
| 84 class GCTracer BASE_EMBEDDED { | |
| 85 public: | |
| 86 class Scope BASE_EMBEDDED { | |
| 87 public: | |
| 88 enum ScopeId { | |
| 89 EXTERNAL, | |
| 90 MC_MARK, | |
| 91 MC_SWEEP, | |
| 92 MC_SWEEP_NEWSPACE, | |
| 93 MC_SWEEP_OLDSPACE, | |
| 94 MC_SWEEP_CODE, | |
| 95 MC_SWEEP_CELL, | |
| 96 MC_SWEEP_MAP, | |
| 97 MC_EVACUATE_PAGES, | |
| 98 MC_UPDATE_NEW_TO_NEW_POINTERS, | |
| 99 MC_UPDATE_ROOT_TO_NEW_POINTERS, | |
| 100 MC_UPDATE_OLD_TO_NEW_POINTERS, | |
| 101 MC_UPDATE_POINTERS_TO_EVACUATED, | |
| 102 MC_UPDATE_POINTERS_BETWEEN_EVACUATED, | |
| 103 MC_UPDATE_MISC_POINTERS, | |
| 104 MC_WEAKCOLLECTION_PROCESS, | |
| 105 MC_WEAKCOLLECTION_CLEAR, | |
| 106 MC_FLUSH_CODE, | |
| 107 NUMBER_OF_SCOPES | |
| 108 }; | |
| 109 | |
| 110 Scope(GCTracer* tracer, ScopeId scope) : tracer_(tracer), scope_(scope) { | |
| 111 start_time_ = base::OS::TimeCurrentMillis(); | |
| 112 } | |
| 113 | |
| 114 ~Scope() { | |
| 115 DCHECK(scope_ < NUMBER_OF_SCOPES); // scope_ is unsigned. | |
| 116 tracer_->current_.scopes[scope_] += | |
| 117 base::OS::TimeCurrentMillis() - start_time_; | |
| 118 } | |
| 119 | |
| 120 private: | |
| 121 GCTracer* tracer_; | |
| 122 ScopeId scope_; | |
| 123 double start_time_; | |
| 124 | |
| 125 DISALLOW_COPY_AND_ASSIGN(Scope); | |
| 126 }; | |
| 127 | |
| 128 | |
| 129 class Event { | |
| 130 public: | |
| 131 enum Type { SCAVENGER = 0, MARK_COMPACTOR = 1, START = 2 }; | |
| 132 | |
| 133 // Default constructor leaves the event uninitialized. | |
| 134 Event() {} | |
| 135 | |
| 136 Event(Type type, const char* gc_reason, const char* collector_reason); | |
| 137 | |
| 138 // Returns a string describing the event type. | |
| 139 const char* TypeName(bool short_name) const; | |
| 140 | |
| 141 // Type of event | |
| 142 Type type; | |
| 143 | |
| 144 const char* gc_reason; | |
| 145 const char* collector_reason; | |
| 146 | |
| 147 // Timestamp set in the constructor. | |
| 148 double start_time; | |
| 149 | |
| 150 // Timestamp set in the destructor. | |
| 151 double end_time; | |
| 152 | |
| 153 // Size of objects in heap set in constructor. | |
| 154 intptr_t start_object_size; | |
| 155 | |
| 156 // Size of objects in heap set in destructor. | |
| 157 intptr_t end_object_size; | |
| 158 | |
| 159 // Size of memory allocated from OS set in constructor. | |
| 160 intptr_t start_memory_size; | |
| 161 | |
| 162 // Size of memory allocated from OS set in destructor. | |
| 163 intptr_t end_memory_size; | |
| 164 | |
| 165 // Total amount of space either wasted or contained in one of free lists | |
| 166 // before the current GC. | |
| 167 intptr_t start_holes_size; | |
| 168 | |
| 169 // Total amount of space either wasted or contained in one of free lists | |
| 170 // after the current GC. | |
| 171 intptr_t end_holes_size; | |
| 172 | |
| 173 // Number of incremental marking steps since creation of tracer. | |
| 174 // (value at start of event) | |
| 175 int cumulative_incremental_marking_steps; | |
| 176 | |
| 177 // Incremental marking steps since | |
| 178 // - last event for SCAVENGER events | |
| 179 // - last MARK_COMPACTOR event for MARK_COMPACTOR events | |
| 180 int incremental_marking_steps; | |
| 181 | |
| 182 // Bytes marked since creation of tracer (value at start of event). | |
| 183 intptr_t cumulative_incremental_marking_bytes; | |
| 184 | |
| 185 // Bytes marked since | |
| 186 // - last event for SCAVENGER events | |
| 187 // - last MARK_COMPACTOR event for MARK_COMPACTOR events | |
| 188 intptr_t incremental_marking_bytes; | |
| 189 | |
| 190 // Cumulative duration of incremental marking steps since creation of | |
| 191 // tracer. (value at start of event) | |
| 192 double cumulative_incremental_marking_duration; | |
| 193 | |
| 194 // Duration of incremental marking steps since | |
| 195 // - last event for SCAVENGER events | |
| 196 // - last MARK_COMPACTOR event for MARK_COMPACTOR events | |
| 197 double incremental_marking_duration; | |
| 198 | |
| 199 // Longest incremental marking step since start of marking. | |
| 200 // (value at start of event) | |
| 201 double longest_incremental_marking_step; | |
| 202 | |
| 203 // Amounts of time spent in different scopes during GC. | |
| 204 double scopes[Scope::NUMBER_OF_SCOPES]; | |
| 205 }; | |
| 206 | |
| 207 static const int kRingBufferMaxSize = 10; | |
| 208 | |
| 209 typedef RingBuffer<Event, kRingBufferMaxSize> EventBuffer; | |
| 210 | |
| 211 explicit GCTracer(Heap* heap); | |
| 212 | |
| 213 // Start collecting data. | |
| 214 void Start(GarbageCollector collector, const char* gc_reason, | |
| 215 const char* collector_reason); | |
| 216 | |
| 217 // Stop collecting data and print results. | |
| 218 void Stop(); | |
| 219 | |
| 220 // Log an incremental marking step. | |
| 221 void AddIncrementalMarkingStep(double duration, intptr_t bytes); | |
| 222 | |
| 223 // Log time spent in marking. | |
| 224 void AddMarkingTime(double duration) { | |
| 225 cumulative_marking_duration_ += duration; | |
| 226 } | |
| 227 | |
| 228 // Time spent in marking. | |
| 229 double cumulative_marking_duration() const { | |
| 230 return cumulative_marking_duration_; | |
| 231 } | |
| 232 | |
| 233 // Log time spent in sweeping on main thread. | |
| 234 void AddSweepingTime(double duration) { | |
| 235 cumulative_sweeping_duration_ += duration; | |
| 236 } | |
| 237 | |
| 238 // Time spent in sweeping on main thread. | |
| 239 double cumulative_sweeping_duration() const { | |
| 240 return cumulative_sweeping_duration_; | |
| 241 } | |
| 242 | |
| 243 // Compute the mean duration of the last scavenger events. Returns 0 if no | |
| 244 // events have been recorded. | |
| 245 double MeanScavengerDuration() const { | |
| 246 return MeanDuration(scavenger_events_); | |
| 247 } | |
| 248 | |
| 249 // Compute the max duration of the last scavenger events. Returns 0 if no | |
| 250 // events have been recorded. | |
| 251 double MaxScavengerDuration() const { return MaxDuration(scavenger_events_); } | |
| 252 | |
| 253 // Compute the mean duration of the last mark compactor events. Returns 0 if | |
| 254 // no events have been recorded. | |
| 255 double MeanMarkCompactorDuration() const { | |
| 256 return MeanDuration(mark_compactor_events_); | |
| 257 } | |
| 258 | |
| 259 // Compute the max duration of the last mark compactor events. Return 0 if no | |
| 260 // events have been recorded. | |
| 261 double MaxMarkCompactorDuration() const { | |
| 262 return MaxDuration(mark_compactor_events_); | |
| 263 } | |
| 264 | |
| 265 // Compute the mean step duration of the last incremental marking round. | |
| 266 // Returns 0 if no incremental marking round has been completed. | |
| 267 double MeanIncrementalMarkingDuration() const; | |
| 268 | |
| 269 // Compute the max step duration of the last incremental marking round. | |
| 270 // Returns 0 if no incremental marking round has been completed. | |
| 271 double MaxIncrementalMarkingDuration() const; | |
| 272 | |
| 273 // Compute the average incremental marking speed in bytes/second. Returns 0 if | |
| 274 // no events have been recorded. | |
| 275 intptr_t IncrementalMarkingSpeedInBytesPerMillisecond() const; | |
| 276 | |
| 277 private: | |
| 278 // Print one detailed trace line in name=value format. | |
| 279 // TODO(ernstm): Move to Heap. | |
| 280 void PrintNVP() const; | |
| 281 | |
| 282 // Print one trace line. | |
| 283 // TODO(ernstm): Move to Heap. | |
| 284 void Print() const; | |
| 285 | |
| 286 // Compute the mean duration of the events in the given ring buffer. | |
| 287 double MeanDuration(const EventBuffer& events) const; | |
| 288 | |
| 289 // Compute the max duration of the events in the given ring buffer. | |
| 290 double MaxDuration(const EventBuffer& events) const; | |
| 291 | |
| 292 // Pointer to the heap that owns this tracer. | |
| 293 Heap* heap_; | |
| 294 | |
| 295 // Current tracer event. Populated during Start/Stop cycle. Valid after Stop() | |
| 296 // has returned. | |
| 297 Event current_; | |
| 298 | |
| 299 // Previous tracer event. | |
| 300 Event previous_; | |
| 301 | |
| 302 // Previous MARK_COMPACTOR event. | |
| 303 Event previous_mark_compactor_event_; | |
| 304 | |
| 305 // RingBuffers for SCAVENGER events. | |
| 306 EventBuffer scavenger_events_; | |
| 307 | |
| 308 // RingBuffers for MARK_COMPACTOR events. | |
| 309 EventBuffer mark_compactor_events_; | |
| 310 | |
| 311 // Cumulative number of incremental marking steps since creation of tracer. | |
| 312 int cumulative_incremental_marking_steps_; | |
| 313 | |
| 314 // Cumulative size of incremental marking steps (in bytes) since creation of | |
| 315 // tracer. | |
| 316 intptr_t cumulative_incremental_marking_bytes_; | |
| 317 | |
| 318 // Cumulative duration of incremental marking steps since creation of tracer. | |
| 319 double cumulative_incremental_marking_duration_; | |
| 320 | |
| 321 // Longest incremental marking step since start of marking. | |
| 322 double longest_incremental_marking_step_; | |
| 323 | |
| 324 // Total marking time. | |
| 325 // This timer is precise when run with --print-cumulative-gc-stat | |
| 326 double cumulative_marking_duration_; | |
| 327 | |
| 328 // Total sweeping time on the main thread. | |
| 329 // This timer is precise when run with --print-cumulative-gc-stat | |
| 330 // TODO(hpayer): Account for sweeping time on sweeper threads. Add a | |
| 331 // different field for that. | |
| 332 // TODO(hpayer): This timer right now just holds the sweeping time | |
| 333 // of the initial atomic sweeping pause. Make sure that it accumulates | |
| 334 // all sweeping operations performed on the main thread. | |
| 335 double cumulative_sweeping_duration_; | |
| 336 | |
| 337 DISALLOW_COPY_AND_ASSIGN(GCTracer); | |
| 338 }; | |
| 339 } | |
| 340 } // namespace v8::internal | |
| 341 | |
| 342 #endif // V8_GC_TRACER_H_ | |
| OLD | NEW |