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 #include "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #include "src/heap/gc-tracer.h" | 7 #include "src/heap/gc-tracer.h" |
8 | 8 |
9 namespace v8 { | 9 namespace v8 { |
10 namespace internal { | 10 namespace internal { |
11 | 11 |
12 static intptr_t CountTotalHolesSize(Heap* heap) { | 12 static intptr_t CountTotalHolesSize(Heap* heap) { |
13 intptr_t holes_size = 0; | 13 intptr_t holes_size = 0; |
14 OldSpaces spaces(heap); | 14 OldSpaces spaces(heap); |
15 for (OldSpace* space = spaces.next(); space != NULL; space = spaces.next()) { | 15 for (OldSpace* space = spaces.next(); space != NULL; space = spaces.next()) { |
16 holes_size += space->Waste() + space->Available(); | 16 holes_size += space->Waste() + space->Available(); |
17 } | 17 } |
18 return holes_size; | 18 return holes_size; |
19 } | 19 } |
20 | 20 |
21 | 21 |
22 GCTracer::AllocationEvent::AllocationEvent(double duration, | 22 GCTracer::AllocationEvent::AllocationEvent(double duration, |
23 intptr_t allocation_in_bytes) { | 23 size_t allocation_in_bytes) { |
24 duration_ = duration; | 24 duration_ = duration; |
25 allocation_in_bytes_ = allocation_in_bytes; | 25 allocation_in_bytes_ = allocation_in_bytes; |
26 } | 26 } |
27 | 27 |
28 | 28 |
29 GCTracer::ContextDisposalEvent::ContextDisposalEvent(double time) { | 29 GCTracer::ContextDisposalEvent::ContextDisposalEvent(double time) { |
30 time_ = time; | 30 time_ = time; |
31 } | 31 } |
32 | 32 |
33 | 33 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
92 | 92 |
93 GCTracer::GCTracer(Heap* heap) | 93 GCTracer::GCTracer(Heap* heap) |
94 : heap_(heap), | 94 : heap_(heap), |
95 cumulative_incremental_marking_steps_(0), | 95 cumulative_incremental_marking_steps_(0), |
96 cumulative_incremental_marking_bytes_(0), | 96 cumulative_incremental_marking_bytes_(0), |
97 cumulative_incremental_marking_duration_(0.0), | 97 cumulative_incremental_marking_duration_(0.0), |
98 cumulative_pure_incremental_marking_duration_(0.0), | 98 cumulative_pure_incremental_marking_duration_(0.0), |
99 longest_incremental_marking_step_(0.0), | 99 longest_incremental_marking_step_(0.0), |
100 cumulative_marking_duration_(0.0), | 100 cumulative_marking_duration_(0.0), |
101 cumulative_sweeping_duration_(0.0), | 101 cumulative_sweeping_duration_(0.0), |
102 new_space_top_after_gc_(0), | 102 new_space_allocation_time_ms_(0.0), |
| 103 new_space_allocation_counter_bytes_(0), |
103 start_counter_(0) { | 104 start_counter_(0) { |
104 current_ = Event(Event::START, NULL, NULL); | 105 current_ = Event(Event::START, NULL, NULL); |
105 current_.end_time = base::OS::TimeCurrentMillis(); | 106 current_.end_time = base::OS::TimeCurrentMillis(); |
106 previous_ = previous_incremental_mark_compactor_event_ = current_; | 107 previous_ = previous_incremental_mark_compactor_event_ = current_; |
107 } | 108 } |
108 | 109 |
109 | 110 |
110 void GCTracer::Start(GarbageCollector collector, const char* gc_reason, | 111 void GCTracer::Start(GarbageCollector collector, const char* gc_reason, |
111 const char* collector_reason) { | 112 const char* collector_reason) { |
112 start_counter_++; | 113 start_counter_++; |
113 if (start_counter_ != 1) return; | 114 if (start_counter_ != 1) return; |
114 | 115 |
115 previous_ = current_; | 116 previous_ = current_; |
116 double start_time = heap_->MonotonicallyIncreasingTimeInMs(); | 117 double start_time = heap_->MonotonicallyIncreasingTimeInMs(); |
117 if (new_space_top_after_gc_ != 0) { | 118 SampleNewSpaceAllocation(start_time, heap_->NewSpaceAllocationCounter()); |
118 AddNewSpaceAllocationTime( | |
119 start_time - previous_.end_time, | |
120 reinterpret_cast<intptr_t>((heap_->new_space()->top()) - | |
121 new_space_top_after_gc_)); | |
122 } | |
123 if (current_.type == Event::INCREMENTAL_MARK_COMPACTOR) | 119 if (current_.type == Event::INCREMENTAL_MARK_COMPACTOR) |
124 previous_incremental_mark_compactor_event_ = current_; | 120 previous_incremental_mark_compactor_event_ = current_; |
125 | 121 |
126 if (collector == SCAVENGER) { | 122 if (collector == SCAVENGER) { |
127 current_ = Event(Event::SCAVENGER, gc_reason, collector_reason); | 123 current_ = Event(Event::SCAVENGER, gc_reason, collector_reason); |
128 } else if (collector == MARK_COMPACTOR) { | 124 } else if (collector == MARK_COMPACTOR) { |
129 if (heap_->incremental_marking()->WasActivated()) { | 125 if (heap_->incremental_marking()->WasActivated()) { |
130 current_ = | 126 current_ = |
131 Event(Event::INCREMENTAL_MARK_COMPACTOR, gc_reason, collector_reason); | 127 Event(Event::INCREMENTAL_MARK_COMPACTOR, gc_reason, collector_reason); |
132 } else { | 128 } else { |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 DCHECK(start_counter_ >= 0); | 173 DCHECK(start_counter_ >= 0); |
178 DCHECK((collector == SCAVENGER && current_.type == Event::SCAVENGER) || | 174 DCHECK((collector == SCAVENGER && current_.type == Event::SCAVENGER) || |
179 (collector == MARK_COMPACTOR && | 175 (collector == MARK_COMPACTOR && |
180 (current_.type == Event::MARK_COMPACTOR || | 176 (current_.type == Event::MARK_COMPACTOR || |
181 current_.type == Event::INCREMENTAL_MARK_COMPACTOR))); | 177 current_.type == Event::INCREMENTAL_MARK_COMPACTOR))); |
182 | 178 |
183 current_.end_time = heap_->MonotonicallyIncreasingTimeInMs(); | 179 current_.end_time = heap_->MonotonicallyIncreasingTimeInMs(); |
184 current_.end_object_size = heap_->SizeOfObjects(); | 180 current_.end_object_size = heap_->SizeOfObjects(); |
185 current_.end_memory_size = heap_->isolate()->memory_allocator()->Size(); | 181 current_.end_memory_size = heap_->isolate()->memory_allocator()->Size(); |
186 current_.end_holes_size = CountTotalHolesSize(heap_); | 182 current_.end_holes_size = CountTotalHolesSize(heap_); |
187 new_space_top_after_gc_ = | |
188 reinterpret_cast<intptr_t>(heap_->new_space()->top()); | |
189 | 183 |
190 int committed_memory = static_cast<int>(heap_->CommittedMemory() / KB); | 184 int committed_memory = static_cast<int>(heap_->CommittedMemory() / KB); |
191 int used_memory = static_cast<int>(current_.end_object_size / KB); | 185 int used_memory = static_cast<int>(current_.end_object_size / KB); |
192 heap_->isolate()->counters()->aggregated_memory_heap_committed()->AddSample( | 186 heap_->isolate()->counters()->aggregated_memory_heap_committed()->AddSample( |
193 current_.end_time, committed_memory); | 187 current_.end_time, committed_memory); |
194 heap_->isolate()->counters()->aggregated_memory_heap_used()->AddSample( | 188 heap_->isolate()->counters()->aggregated_memory_heap_used()->AddSample( |
195 current_.end_time, used_memory); | 189 current_.end_time, used_memory); |
196 | 190 |
197 if (current_.type == Event::SCAVENGER) { | 191 if (current_.type == Event::SCAVENGER) { |
198 current_.incremental_marking_steps = | 192 current_.incremental_marking_steps = |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
252 if (FLAG_trace_gc_nvp) | 246 if (FLAG_trace_gc_nvp) |
253 PrintNVP(); | 247 PrintNVP(); |
254 else | 248 else |
255 Print(); | 249 Print(); |
256 | 250 |
257 heap_->PrintShortHeapStatistics(); | 251 heap_->PrintShortHeapStatistics(); |
258 } | 252 } |
259 } | 253 } |
260 | 254 |
261 | 255 |
262 void GCTracer::AddNewSpaceAllocationTime(double duration, | 256 void GCTracer::SampleNewSpaceAllocation(double current_ms, |
263 intptr_t allocation_in_bytes) { | 257 size_t counter_bytes) { |
264 allocation_events_.push_front(AllocationEvent(duration, allocation_in_bytes)); | 258 if (new_space_allocation_time_ms_ == 0) { |
| 259 // It is the first sample. |
| 260 new_space_allocation_time_ms_ = current_ms; |
| 261 new_space_allocation_counter_bytes_ = counter_bytes; |
| 262 return; |
| 263 } |
| 264 // This assumes that counters are unsigned integers so that the subtraction |
| 265 // below works even if the new counter is less then the old counter. |
| 266 size_t allocated_bytes = counter_bytes - new_space_allocation_counter_bytes_; |
| 267 double duration = current_ms - new_space_allocation_time_ms_; |
| 268 const double kMinDurationMs = 1; |
| 269 if (duration < kMinDurationMs) { |
| 270 // Do not sample small durations to avoid precision errors. |
| 271 return; |
| 272 } |
| 273 new_space_allocation_time_ms_ = current_ms; |
| 274 new_space_allocation_counter_bytes_ = counter_bytes; |
| 275 allocation_events_.push_front(AllocationEvent(duration, allocated_bytes)); |
265 } | 276 } |
266 | 277 |
267 | 278 |
268 void GCTracer::AddContextDisposalTime(double time) { | 279 void GCTracer::AddContextDisposalTime(double time) { |
269 context_disposal_events_.push_front(ContextDisposalEvent(time)); | 280 context_disposal_events_.push_front(ContextDisposalEvent(time)); |
270 } | 281 } |
271 | 282 |
272 | 283 |
273 void GCTracer::AddSurvivalRatio(double promotion_ratio) { | 284 void GCTracer::AddSurvivalRatio(double promotion_ratio) { |
274 survival_events_.push_front(SurvivalEvent(promotion_ratio)); | 285 survival_events_.push_front(SurvivalEvent(promotion_ratio)); |
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
548 durations += iter->end_time - iter->start_time; | 559 durations += iter->end_time - iter->start_time; |
549 ++iter; | 560 ++iter; |
550 } | 561 } |
551 | 562 |
552 if (durations == 0.0) return 0; | 563 if (durations == 0.0) return 0; |
553 | 564 |
554 return static_cast<intptr_t>(bytes / durations); | 565 return static_cast<intptr_t>(bytes / durations); |
555 } | 566 } |
556 | 567 |
557 | 568 |
558 intptr_t GCTracer::NewSpaceAllocationThroughputInBytesPerMillisecond() const { | 569 size_t GCTracer::NewSpaceAllocationThroughputInBytesPerMillisecond() const { |
559 intptr_t bytes = 0; | 570 size_t bytes = 0; |
560 double durations = 0.0; | 571 double durations = 0.0; |
561 AllocationEventBuffer::const_iterator iter = allocation_events_.begin(); | 572 AllocationEventBuffer::const_iterator iter = allocation_events_.begin(); |
562 while (iter != allocation_events_.end()) { | 573 const size_t max_bytes = static_cast<size_t>(-1); |
| 574 while (iter != allocation_events_.end() && bytes < max_bytes - bytes) { |
563 bytes += iter->allocation_in_bytes_; | 575 bytes += iter->allocation_in_bytes_; |
564 durations += iter->duration_; | 576 durations += iter->duration_; |
565 ++iter; | 577 ++iter; |
566 } | 578 } |
567 | 579 |
568 if (durations == 0.0) return 0; | 580 if (durations == 0.0) return 0; |
569 | 581 |
570 return static_cast<intptr_t>(bytes / durations); | 582 return static_cast<size_t>(bytes / durations + 0.5); |
571 } | 583 } |
572 | 584 |
573 | 585 |
574 double GCTracer::ContextDisposalRateInMilliseconds() const { | 586 double GCTracer::ContextDisposalRateInMilliseconds() const { |
575 if (context_disposal_events_.size() < kRingBufferMaxSize) return 0.0; | 587 if (context_disposal_events_.size() < kRingBufferMaxSize) return 0.0; |
576 | 588 |
577 double begin = base::OS::TimeCurrentMillis(); | 589 double begin = base::OS::TimeCurrentMillis(); |
578 double end = 0.0; | 590 double end = 0.0; |
579 ContextDisposalEventBuffer::const_iterator iter = | 591 ContextDisposalEventBuffer::const_iterator iter = |
580 context_disposal_events_.begin(); | 592 context_disposal_events_.begin(); |
(...skipping 21 matching lines...) Expand all Loading... |
602 | 614 |
603 | 615 |
604 bool GCTracer::SurvivalEventsRecorded() const { | 616 bool GCTracer::SurvivalEventsRecorded() const { |
605 return survival_events_.size() > 0; | 617 return survival_events_.size() > 0; |
606 } | 618 } |
607 | 619 |
608 | 620 |
609 void GCTracer::ResetSurvivalEvents() { survival_events_.reset(); } | 621 void GCTracer::ResetSurvivalEvents() { survival_events_.reset(); } |
610 } | 622 } |
611 } // namespace v8::internal | 623 } // namespace v8::internal |
OLD | NEW |