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 |