| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef V8_HEAP_GC_TRACER_H_ | 5 #ifndef V8_HEAP_GC_TRACER_H_ |
| 6 #define V8_HEAP_GC_TRACER_H_ | 6 #define V8_HEAP_GC_TRACER_H_ |
| 7 | 7 |
| 8 #include "src/base/platform/platform.h" | 8 #include "src/base/platform/platform.h" |
| 9 #include "src/counters.h" | 9 #include "src/counters.h" |
| 10 #include "src/globals.h" | 10 #include "src/globals.h" |
| 11 | 11 |
| 12 namespace v8 { | 12 namespace v8 { |
| 13 namespace internal { | 13 namespace internal { |
| 14 | 14 |
| 15 // A simple ring buffer class with maximum size known at compile time. | 15 template <typename T> |
| 16 // The class only implements the functionality required in GCTracer. | |
| 17 template <typename T, size_t MAX_SIZE> | |
| 18 class RingBuffer { | 16 class RingBuffer { |
| 19 public: | 17 public: |
| 20 class const_iterator { | 18 RingBuffer() { Reset(); } |
| 21 public: | 19 static const int kSize = 10; |
| 22 const_iterator() : index_(0), elements_(NULL) {} | 20 void Push(const T& value) { |
| 23 | 21 if (count_ == kSize) { |
| 24 const_iterator(size_t index, const T* elements) | 22 elements_[start_++] = value; |
| 25 : index_(index), elements_(elements) {} | 23 if (start_ == kSize) start_ = 0; |
| 26 | 24 } else { |
| 27 bool operator==(const const_iterator& rhs) const { | 25 DCHECK_EQ(start_, 0); |
| 28 return elements_ == rhs.elements_ && index_ == rhs.index_; | 26 elements_[count_++] = value; |
| 29 } | 27 } |
| 30 | |
| 31 bool operator!=(const const_iterator& rhs) const { | |
| 32 return elements_ != rhs.elements_ || index_ != rhs.index_; | |
| 33 } | |
| 34 | |
| 35 operator const T*() const { return elements_ + index_; } | |
| 36 | |
| 37 const T* operator->() const { return elements_ + index_; } | |
| 38 | |
| 39 const T& operator*() const { return elements_[index_]; } | |
| 40 | |
| 41 const_iterator& operator++() { | |
| 42 index_ = (index_ + 1) % (MAX_SIZE + 1); | |
| 43 return *this; | |
| 44 } | |
| 45 | |
| 46 const_iterator& operator--() { | |
| 47 index_ = (index_ + MAX_SIZE) % (MAX_SIZE + 1); | |
| 48 return *this; | |
| 49 } | |
| 50 | |
| 51 private: | |
| 52 size_t index_; | |
| 53 const T* elements_; | |
| 54 }; | |
| 55 | |
| 56 RingBuffer() : begin_(0), end_(0) {} | |
| 57 | |
| 58 bool empty() const { return begin_ == end_; } | |
| 59 size_t size() const { | |
| 60 return (end_ - begin_ + MAX_SIZE + 1) % (MAX_SIZE + 1); | |
| 61 } | |
| 62 const_iterator begin() const { return const_iterator(begin_, elements_); } | |
| 63 const_iterator end() const { return const_iterator(end_, elements_); } | |
| 64 const_iterator back() const { return --end(); } | |
| 65 void push_back(const T& element) { | |
| 66 elements_[end_] = element; | |
| 67 end_ = (end_ + 1) % (MAX_SIZE + 1); | |
| 68 if (end_ == begin_) begin_ = (begin_ + 1) % (MAX_SIZE + 1); | |
| 69 } | |
| 70 void push_front(const T& element) { | |
| 71 begin_ = (begin_ + MAX_SIZE) % (MAX_SIZE + 1); | |
| 72 if (begin_ == end_) end_ = (end_ + MAX_SIZE) % (MAX_SIZE + 1); | |
| 73 elements_[begin_] = element; | |
| 74 } | 28 } |
| 75 | 29 |
| 76 void reset() { | 30 int Count() const { return count_; } |
| 77 begin_ = 0; | 31 |
| 78 end_ = 0; | 32 template <typename Callback> |
| 33 T Sum(Callback callback, const T& initial) const { |
| 34 int j = start_ + count_ - 1; |
| 35 if (j >= kSize) j -= kSize; |
| 36 T result = initial; |
| 37 for (int i = 0; i < count_; i++) { |
| 38 result = callback(result, elements_[j]); |
| 39 if (--j == -1) j += kSize; |
| 40 } |
| 41 return result; |
| 79 } | 42 } |
| 80 | 43 |
| 44 void Reset() { start_ = count_ = 0; } |
| 45 |
| 81 private: | 46 private: |
| 82 T elements_[MAX_SIZE + 1]; | 47 T elements_[kSize]; |
| 83 size_t begin_; | 48 int start_; |
| 84 size_t end_; | 49 int count_; |
| 85 | |
| 86 DISALLOW_COPY_AND_ASSIGN(RingBuffer); | 50 DISALLOW_COPY_AND_ASSIGN(RingBuffer); |
| 87 }; | 51 }; |
| 88 | 52 |
| 53 typedef std::pair<uint64_t, double> BytesAndDuration; |
| 54 |
| 55 inline BytesAndDuration MakeBytesAndDuration(uint64_t bytes, double duration) { |
| 56 return std::make_pair(bytes, duration); |
| 57 } |
| 89 | 58 |
| 90 enum ScavengeSpeedMode { kForAllObjects, kForSurvivedObjects }; | 59 enum ScavengeSpeedMode { kForAllObjects, kForSurvivedObjects }; |
| 91 | 60 |
| 92 // GCTracer collects and prints ONE line after each garbage collector | 61 // GCTracer collects and prints ONE line after each garbage collector |
| 93 // invocation IFF --trace_gc is used. | 62 // invocation IFF --trace_gc is used. |
| 94 // TODO(ernstm): Unit tests. | 63 // TODO(ernstm): Unit tests. |
| 95 class GCTracer { | 64 class GCTracer { |
| 96 public: | 65 public: |
| 97 class Scope { | 66 class Scope { |
| 98 public: | 67 public: |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 151 private: | 120 private: |
| 152 GCTracer* tracer_; | 121 GCTracer* tracer_; |
| 153 ScopeId scope_; | 122 ScopeId scope_; |
| 154 double start_time_; | 123 double start_time_; |
| 155 RuntimeCallTimer timer_; | 124 RuntimeCallTimer timer_; |
| 156 | 125 |
| 157 DISALLOW_COPY_AND_ASSIGN(Scope); | 126 DISALLOW_COPY_AND_ASSIGN(Scope); |
| 158 }; | 127 }; |
| 159 | 128 |
| 160 | 129 |
| 161 class AllocationEvent { | |
| 162 public: | |
| 163 // Default constructor leaves the event uninitialized. | |
| 164 AllocationEvent() {} | |
| 165 | |
| 166 AllocationEvent(double duration, size_t allocation_in_bytes); | |
| 167 | |
| 168 // Time spent in the mutator during the end of the last sample to the | |
| 169 // beginning of the next sample. | |
| 170 double duration_; | |
| 171 | |
| 172 // Memory allocated in the new space during the end of the last sample | |
| 173 // to the beginning of the next sample | |
| 174 size_t allocation_in_bytes_; | |
| 175 }; | |
| 176 | |
| 177 | |
| 178 class CompactionEvent { | |
| 179 public: | |
| 180 CompactionEvent() : duration(0), live_bytes_compacted(0) {} | |
| 181 | |
| 182 CompactionEvent(double duration, intptr_t live_bytes_compacted) | |
| 183 : duration(duration), live_bytes_compacted(live_bytes_compacted) {} | |
| 184 | |
| 185 double duration; | |
| 186 intptr_t live_bytes_compacted; | |
| 187 }; | |
| 188 | |
| 189 | |
| 190 class ContextDisposalEvent { | |
| 191 public: | |
| 192 // Default constructor leaves the event uninitialized. | |
| 193 ContextDisposalEvent() {} | |
| 194 | |
| 195 explicit ContextDisposalEvent(double time); | |
| 196 | |
| 197 // Time when context disposal event happened. | |
| 198 double time_; | |
| 199 }; | |
| 200 | |
| 201 | |
| 202 class SurvivalEvent { | |
| 203 public: | |
| 204 // Default constructor leaves the event uninitialized. | |
| 205 SurvivalEvent() {} | |
| 206 | |
| 207 explicit SurvivalEvent(double survival_ratio); | |
| 208 | |
| 209 double promotion_ratio_; | |
| 210 }; | |
| 211 | |
| 212 | |
| 213 class Event { | 130 class Event { |
| 214 public: | 131 public: |
| 215 enum Type { | 132 enum Type { |
| 216 SCAVENGER = 0, | 133 SCAVENGER = 0, |
| 217 MARK_COMPACTOR = 1, | 134 MARK_COMPACTOR = 1, |
| 218 INCREMENTAL_MARK_COMPACTOR = 2, | 135 INCREMENTAL_MARK_COMPACTOR = 2, |
| 219 START = 3 | 136 START = 3 |
| 220 }; | 137 }; |
| 221 | 138 |
| 222 // Default constructor leaves the event uninitialized. | 139 // Default constructor leaves the event uninitialized. |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 307 double pure_incremental_marking_duration; | 224 double pure_incremental_marking_duration; |
| 308 | 225 |
| 309 // Longest incremental marking step since start of marking. | 226 // Longest incremental marking step since start of marking. |
| 310 // (value at start of event) | 227 // (value at start of event) |
| 311 double longest_incremental_marking_step; | 228 double longest_incremental_marking_step; |
| 312 | 229 |
| 313 // Amounts of time spent in different scopes during GC. | 230 // Amounts of time spent in different scopes during GC. |
| 314 double scopes[Scope::NUMBER_OF_SCOPES]; | 231 double scopes[Scope::NUMBER_OF_SCOPES]; |
| 315 }; | 232 }; |
| 316 | 233 |
| 317 static const size_t kRingBufferMaxSize = 10; | |
| 318 | |
| 319 typedef RingBuffer<Event, kRingBufferMaxSize> EventBuffer; | |
| 320 | |
| 321 typedef RingBuffer<AllocationEvent, kRingBufferMaxSize> AllocationEventBuffer; | |
| 322 | |
| 323 typedef RingBuffer<ContextDisposalEvent, kRingBufferMaxSize> | |
| 324 ContextDisposalEventBuffer; | |
| 325 | |
| 326 typedef RingBuffer<CompactionEvent, kRingBufferMaxSize> CompactionEventBuffer; | |
| 327 | |
| 328 typedef RingBuffer<SurvivalEvent, kRingBufferMaxSize> SurvivalEventBuffer; | |
| 329 | |
| 330 static const int kThroughputTimeFrameMs = 5000; | 234 static const int kThroughputTimeFrameMs = 5000; |
| 331 | 235 |
| 332 explicit GCTracer(Heap* heap); | 236 explicit GCTracer(Heap* heap); |
| 333 | 237 |
| 334 // Start collecting data. | 238 // Start collecting data. |
| 335 void Start(GarbageCollector collector, const char* gc_reason, | 239 void Start(GarbageCollector collector, const char* gc_reason, |
| 336 const char* collector_reason); | 240 const char* collector_reason); |
| 337 | 241 |
| 338 // Stop collecting data and print results. | 242 // Stop collecting data and print results. |
| 339 void Stop(GarbageCollector collector); | 243 void Stop(GarbageCollector collector); |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 438 // events. | 342 // events. |
| 439 // Returns 0 if no events have been recorded. | 343 // Returns 0 if no events have been recorded. |
| 440 double AverageSurvivalRatio() const; | 344 double AverageSurvivalRatio() const; |
| 441 | 345 |
| 442 // Returns true if at least one survival event was recorded. | 346 // Returns true if at least one survival event was recorded. |
| 443 bool SurvivalEventsRecorded() const; | 347 bool SurvivalEventsRecorded() const; |
| 444 | 348 |
| 445 // Discard all recorded survival events. | 349 // Discard all recorded survival events. |
| 446 void ResetSurvivalEvents(); | 350 void ResetSurvivalEvents(); |
| 447 | 351 |
| 352 // Returns the average speed of the events in the buffer. |
| 353 // If the buffer is empty, the result is 0. |
| 354 // Otherwise, the result is between 1 byte/ms and 1 GB/ms. |
| 355 static int AverageSpeed(const RingBuffer<BytesAndDuration>& buffer); |
| 356 static int AverageSpeed(const RingBuffer<BytesAndDuration>& buffer, |
| 357 const BytesAndDuration& initial, double time_ms); |
| 358 |
| 448 private: | 359 private: |
| 449 // Print one detailed trace line in name=value format. | 360 // Print one detailed trace line in name=value format. |
| 450 // TODO(ernstm): Move to Heap. | 361 // TODO(ernstm): Move to Heap. |
| 451 void PrintNVP() const; | 362 void PrintNVP() const; |
| 452 | 363 |
| 453 // Print one trace line. | 364 // Print one trace line. |
| 454 // TODO(ernstm): Move to Heap. | 365 // TODO(ernstm): Move to Heap. |
| 455 void Print() const; | 366 void Print() const; |
| 456 | 367 |
| 457 // Prints a line and also adds it to the heap's ring buffer so that | 368 // Prints a line and also adds it to the heap's ring buffer so that |
| 458 // it can be included in later crash dumps. | 369 // it can be included in later crash dumps. |
| 459 void Output(const char* format, ...) const; | 370 void Output(const char* format, ...) const; |
| 460 | 371 |
| 461 // Compute the mean duration of the events in the given ring buffer. | |
| 462 double MeanDuration(const EventBuffer& events) const; | |
| 463 | |
| 464 // Compute the max duration of the events in the given ring buffer. | |
| 465 double MaxDuration(const EventBuffer& events) const; | |
| 466 | |
| 467 void ClearMarkCompactStatistics() { | 372 void ClearMarkCompactStatistics() { |
| 468 cumulative_incremental_marking_steps_ = 0; | 373 cumulative_incremental_marking_steps_ = 0; |
| 469 cumulative_incremental_marking_bytes_ = 0; | 374 cumulative_incremental_marking_bytes_ = 0; |
| 470 cumulative_incremental_marking_duration_ = 0; | 375 cumulative_incremental_marking_duration_ = 0; |
| 471 cumulative_pure_incremental_marking_duration_ = 0; | 376 cumulative_pure_incremental_marking_duration_ = 0; |
| 472 longest_incremental_marking_step_ = 0; | 377 longest_incremental_marking_step_ = 0; |
| 473 cumulative_incremental_marking_finalization_steps_ = 0; | 378 cumulative_incremental_marking_finalization_steps_ = 0; |
| 474 cumulative_incremental_marking_finalization_duration_ = 0; | 379 cumulative_incremental_marking_finalization_duration_ = 0; |
| 475 longest_incremental_marking_finalization_step_ = 0; | 380 longest_incremental_marking_finalization_step_ = 0; |
| 476 cumulative_marking_duration_ = 0; | 381 cumulative_marking_duration_ = 0; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 493 // Current tracer event. Populated during Start/Stop cycle. Valid after Stop() | 398 // Current tracer event. Populated during Start/Stop cycle. Valid after Stop() |
| 494 // has returned. | 399 // has returned. |
| 495 Event current_; | 400 Event current_; |
| 496 | 401 |
| 497 // Previous tracer event. | 402 // Previous tracer event. |
| 498 Event previous_; | 403 Event previous_; |
| 499 | 404 |
| 500 // Previous INCREMENTAL_MARK_COMPACTOR event. | 405 // Previous INCREMENTAL_MARK_COMPACTOR event. |
| 501 Event previous_incremental_mark_compactor_event_; | 406 Event previous_incremental_mark_compactor_event_; |
| 502 | 407 |
| 503 // RingBuffers for SCAVENGER events. | |
| 504 EventBuffer scavenger_events_; | |
| 505 | |
| 506 // RingBuffers for MARK_COMPACTOR events. | |
| 507 EventBuffer mark_compactor_events_; | |
| 508 | |
| 509 // RingBuffers for INCREMENTAL_MARK_COMPACTOR events. | |
| 510 EventBuffer incremental_mark_compactor_events_; | |
| 511 | |
| 512 // RingBuffer for allocation events. | |
| 513 AllocationEventBuffer new_space_allocation_events_; | |
| 514 AllocationEventBuffer old_generation_allocation_events_; | |
| 515 | |
| 516 // RingBuffer for context disposal events. | |
| 517 ContextDisposalEventBuffer context_disposal_events_; | |
| 518 | |
| 519 // RingBuffer for compaction events. | |
| 520 CompactionEventBuffer compaction_events_; | |
| 521 | |
| 522 // RingBuffer for survival events. | |
| 523 SurvivalEventBuffer survival_events_; | |
| 524 | |
| 525 // Cumulative number of incremental marking steps since creation of tracer. | 408 // Cumulative number of incremental marking steps since creation of tracer. |
| 526 int cumulative_incremental_marking_steps_; | 409 int cumulative_incremental_marking_steps_; |
| 527 | 410 |
| 528 // Cumulative size of incremental marking steps (in bytes) since creation of | 411 // Cumulative size of incremental marking steps (in bytes) since creation of |
| 529 // tracer. | 412 // tracer. |
| 530 intptr_t cumulative_incremental_marking_bytes_; | 413 intptr_t cumulative_incremental_marking_bytes_; |
| 531 | 414 |
| 532 // Cumulative duration of incremental marking steps since creation of tracer. | 415 // Cumulative duration of incremental marking steps since creation of tracer. |
| 533 double cumulative_incremental_marking_duration_; | 416 double cumulative_incremental_marking_duration_; |
| 534 | 417 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 574 size_t old_generation_allocation_in_bytes_since_gc_; | 457 size_t old_generation_allocation_in_bytes_since_gc_; |
| 575 | 458 |
| 576 double combined_mark_compact_speed_cache_; | 459 double combined_mark_compact_speed_cache_; |
| 577 | 460 |
| 578 // Counts how many tracers were started without stopping. | 461 // Counts how many tracers were started without stopping. |
| 579 int start_counter_; | 462 int start_counter_; |
| 580 | 463 |
| 581 // Separate timer used for --runtime_call_stats | 464 // Separate timer used for --runtime_call_stats |
| 582 RuntimeCallTimer timer_; | 465 RuntimeCallTimer timer_; |
| 583 | 466 |
| 467 RingBuffer<BytesAndDuration> recorded_incremental_marking_steps_; |
| 468 RingBuffer<BytesAndDuration> recorded_scavenges_total_; |
| 469 RingBuffer<BytesAndDuration> recorded_scavenges_survived_; |
| 470 RingBuffer<BytesAndDuration> recorded_compactions_; |
| 471 RingBuffer<BytesAndDuration> recorded_mark_compacts_; |
| 472 RingBuffer<BytesAndDuration> recorded_incremental_mark_compacts_; |
| 473 RingBuffer<BytesAndDuration> recorded_new_generation_allocations_; |
| 474 RingBuffer<BytesAndDuration> recorded_old_generation_allocations_; |
| 475 RingBuffer<double> recorded_context_disposal_times_; |
| 476 RingBuffer<double> recorded_survival_ratios_; |
| 477 |
| 584 DISALLOW_COPY_AND_ASSIGN(GCTracer); | 478 DISALLOW_COPY_AND_ASSIGN(GCTracer); |
| 585 }; | 479 }; |
| 586 } // namespace internal | 480 } // namespace internal |
| 587 } // namespace v8 | 481 } // namespace v8 |
| 588 | 482 |
| 589 #endif // V8_HEAP_GC_TRACER_H_ | 483 #endif // V8_HEAP_GC_TRACER_H_ |
| OLD | NEW |