Chromium Code Reviews| 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/heap/gc-tracer.h" | 5 #include "src/heap/gc-tracer.h" |
| 6 | 6 |
| 7 #include "src/counters.h" | 7 #include "src/counters.h" |
| 8 #include "src/heap/heap-inl.h" | 8 #include "src/heap/heap-inl.h" |
| 9 #include "src/isolate.h" | 9 #include "src/isolate.h" |
| 10 | 10 |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 38 DCHECK(scope_ < NUMBER_OF_SCOPES); // scope_ is unsigned. | 38 DCHECK(scope_ < NUMBER_OF_SCOPES); // scope_ is unsigned. |
| 39 tracer_->current_.scopes[scope_] += | 39 tracer_->current_.scopes[scope_] += |
| 40 tracer_->heap_->MonotonicallyIncreasingTimeInMs() - start_time_; | 40 tracer_->heap_->MonotonicallyIncreasingTimeInMs() - start_time_; |
| 41 // TODO(cbruni): remove once we fully moved to a trace-based system. | 41 // TODO(cbruni): remove once we fully moved to a trace-based system. |
| 42 if (FLAG_runtime_call_stats) { | 42 if (FLAG_runtime_call_stats) { |
| 43 tracer_->heap_->isolate()->counters()->runtime_call_stats()->Leave(&timer_); | 43 tracer_->heap_->isolate()->counters()->runtime_call_stats()->Leave(&timer_); |
| 44 } | 44 } |
| 45 } | 45 } |
| 46 | 46 |
| 47 | 47 |
| 48 GCTracer::AllocationEvent::AllocationEvent(double duration, | |
| 49 size_t allocation_in_bytes) { | |
| 50 duration_ = duration; | |
| 51 allocation_in_bytes_ = allocation_in_bytes; | |
| 52 } | |
| 53 | |
| 54 | |
| 55 GCTracer::ContextDisposalEvent::ContextDisposalEvent(double time) { | |
| 56 time_ = time; | |
| 57 } | |
| 58 | |
| 59 | |
| 60 GCTracer::SurvivalEvent::SurvivalEvent(double promotion_ratio) { | |
| 61 promotion_ratio_ = promotion_ratio; | |
| 62 } | |
| 63 | |
| 64 | |
| 65 GCTracer::Event::Event(Type type, const char* gc_reason, | 48 GCTracer::Event::Event(Type type, const char* gc_reason, |
| 66 const char* collector_reason) | 49 const char* collector_reason) |
| 67 : type(type), | 50 : type(type), |
| 68 gc_reason(gc_reason), | 51 gc_reason(gc_reason), |
| 69 collector_reason(collector_reason), | 52 collector_reason(collector_reason), |
| 70 start_time(0.0), | 53 start_time(0.0), |
| 71 end_time(0.0), | 54 end_time(0.0), |
| 72 reduce_memory(false), | 55 reduce_memory(false), |
| 73 start_object_size(0), | 56 start_object_size(0), |
| 74 end_object_size(0), | 57 end_object_size(0), |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 195 start_time, used_memory); | 178 start_time, used_memory); |
| 196 // TODO(cbruni): remove once we fully moved to a trace-based system. | 179 // TODO(cbruni): remove once we fully moved to a trace-based system. |
| 197 if (FLAG_runtime_call_stats) { | 180 if (FLAG_runtime_call_stats) { |
| 198 RuntimeCallStats* stats = | 181 RuntimeCallStats* stats = |
| 199 heap_->isolate()->counters()->runtime_call_stats(); | 182 heap_->isolate()->counters()->runtime_call_stats(); |
| 200 timer_.Initialize(&stats->GC, stats->current_timer()); | 183 timer_.Initialize(&stats->GC, stats->current_timer()); |
| 201 stats->Enter(&timer_); | 184 stats->Enter(&timer_); |
| 202 } | 185 } |
| 203 } | 186 } |
| 204 | 187 |
| 205 | |
| 206 void GCTracer::Stop(GarbageCollector collector) { | 188 void GCTracer::Stop(GarbageCollector collector) { |
| 207 start_counter_--; | 189 start_counter_--; |
| 208 if (start_counter_ != 0) { | 190 if (start_counter_ != 0) { |
| 209 Output("[Finished reentrant %s during %s.]\n", | 191 Output("[Finished reentrant %s during %s.]\n", |
| 210 collector == SCAVENGER ? "Scavenge" : "Mark-sweep", | 192 collector == SCAVENGER ? "Scavenge" : "Mark-sweep", |
| 211 current_.TypeName(false)); | 193 current_.TypeName(false)); |
| 212 return; | 194 return; |
| 213 } | 195 } |
| 214 | 196 |
| 215 DCHECK(start_counter_ >= 0); | 197 DCHECK(start_counter_ >= 0); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 226 | 208 |
| 227 AddAllocation(current_.end_time); | 209 AddAllocation(current_.end_time); |
| 228 | 210 |
| 229 int committed_memory = static_cast<int>(heap_->CommittedMemory() / KB); | 211 int committed_memory = static_cast<int>(heap_->CommittedMemory() / KB); |
| 230 int used_memory = static_cast<int>(current_.end_object_size / KB); | 212 int used_memory = static_cast<int>(current_.end_object_size / KB); |
| 231 heap_->isolate()->counters()->aggregated_memory_heap_committed()->AddSample( | 213 heap_->isolate()->counters()->aggregated_memory_heap_committed()->AddSample( |
| 232 current_.end_time, committed_memory); | 214 current_.end_time, committed_memory); |
| 233 heap_->isolate()->counters()->aggregated_memory_heap_used()->AddSample( | 215 heap_->isolate()->counters()->aggregated_memory_heap_used()->AddSample( |
| 234 current_.end_time, used_memory); | 216 current_.end_time, used_memory); |
| 235 | 217 |
| 218 double duration = current_.end_time - current_.start_time; | |
| 236 if (current_.type == Event::SCAVENGER) { | 219 if (current_.type == Event::SCAVENGER) { |
| 237 current_.incremental_marking_steps = | 220 current_.incremental_marking_steps = |
| 238 current_.cumulative_incremental_marking_steps - | 221 current_.cumulative_incremental_marking_steps - |
| 239 previous_.cumulative_incremental_marking_steps; | 222 previous_.cumulative_incremental_marking_steps; |
| 240 current_.incremental_marking_bytes = | 223 current_.incremental_marking_bytes = |
| 241 current_.cumulative_incremental_marking_bytes - | 224 current_.cumulative_incremental_marking_bytes - |
| 242 previous_.cumulative_incremental_marking_bytes; | 225 previous_.cumulative_incremental_marking_bytes; |
| 243 current_.incremental_marking_duration = | 226 current_.incremental_marking_duration = |
| 244 current_.cumulative_incremental_marking_duration - | 227 current_.cumulative_incremental_marking_duration - |
| 245 previous_.cumulative_incremental_marking_duration; | 228 previous_.cumulative_incremental_marking_duration; |
| 246 current_.pure_incremental_marking_duration = | 229 current_.pure_incremental_marking_duration = |
| 247 current_.cumulative_pure_incremental_marking_duration - | 230 current_.cumulative_pure_incremental_marking_duration - |
| 248 previous_.cumulative_pure_incremental_marking_duration; | 231 previous_.cumulative_pure_incremental_marking_duration; |
| 249 scavenger_events_.push_front(current_); | 232 past_scavenges_total_.Push( |
| 233 MakeBytesAndDuration(current_.new_space_object_size, duration)); | |
| 234 past_scavenges_survived_.Push(MakeBytesAndDuration( | |
| 235 current_.survived_new_space_object_size, duration)); | |
| 250 } else if (current_.type == Event::INCREMENTAL_MARK_COMPACTOR) { | 236 } else if (current_.type == Event::INCREMENTAL_MARK_COMPACTOR) { |
| 251 current_.incremental_marking_steps = | 237 current_.incremental_marking_steps = |
| 252 current_.cumulative_incremental_marking_steps - | 238 current_.cumulative_incremental_marking_steps - |
| 253 previous_incremental_mark_compactor_event_ | 239 previous_incremental_mark_compactor_event_ |
| 254 .cumulative_incremental_marking_steps; | 240 .cumulative_incremental_marking_steps; |
| 255 current_.incremental_marking_bytes = | 241 current_.incremental_marking_bytes = |
| 256 current_.cumulative_incremental_marking_bytes - | 242 current_.cumulative_incremental_marking_bytes - |
| 257 previous_incremental_mark_compactor_event_ | 243 previous_incremental_mark_compactor_event_ |
| 258 .cumulative_incremental_marking_bytes; | 244 .cumulative_incremental_marking_bytes; |
| 259 current_.incremental_marking_duration = | 245 current_.incremental_marking_duration = |
| 260 current_.cumulative_incremental_marking_duration - | 246 current_.cumulative_incremental_marking_duration - |
| 261 previous_incremental_mark_compactor_event_ | 247 previous_incremental_mark_compactor_event_ |
| 262 .cumulative_incremental_marking_duration; | 248 .cumulative_incremental_marking_duration; |
| 263 current_.pure_incremental_marking_duration = | 249 current_.pure_incremental_marking_duration = |
| 264 current_.cumulative_pure_incremental_marking_duration - | 250 current_.cumulative_pure_incremental_marking_duration - |
| 265 previous_incremental_mark_compactor_event_ | 251 previous_incremental_mark_compactor_event_ |
| 266 .cumulative_pure_incremental_marking_duration; | 252 .cumulative_pure_incremental_marking_duration; |
| 267 longest_incremental_marking_step_ = 0.0; | 253 longest_incremental_marking_step_ = 0.0; |
| 268 incremental_mark_compactor_events_.push_front(current_); | 254 past_incremental_marking_steps_.Push( |
| 255 MakeBytesAndDuration(current_.incremental_marking_bytes, | |
| 256 current_.pure_incremental_marking_duration)); | |
| 257 past_incremental_mark_compacts_.Push( | |
| 258 MakeBytesAndDuration(current_.start_object_size, duration)); | |
| 269 combined_mark_compact_speed_cache_ = 0.0; | 259 combined_mark_compact_speed_cache_ = 0.0; |
| 270 } else { | 260 } else { |
| 271 DCHECK(current_.incremental_marking_bytes == 0); | 261 DCHECK(current_.incremental_marking_bytes == 0); |
| 272 DCHECK(current_.incremental_marking_duration == 0); | 262 DCHECK(current_.incremental_marking_duration == 0); |
| 273 DCHECK(current_.pure_incremental_marking_duration == 0); | 263 DCHECK(current_.pure_incremental_marking_duration == 0); |
| 274 longest_incremental_marking_step_ = 0.0; | 264 longest_incremental_marking_step_ = 0.0; |
| 275 mark_compactor_events_.push_front(current_); | 265 past_mark_compacts_.Push( |
| 266 MakeBytesAndDuration(current_.start_object_size, duration)); | |
| 276 combined_mark_compact_speed_cache_ = 0.0; | 267 combined_mark_compact_speed_cache_ = 0.0; |
| 277 } | 268 } |
| 278 | 269 |
| 279 // TODO(ernstm): move the code below out of GCTracer. | 270 // TODO(ernstm): move the code below out of GCTracer. |
| 280 | 271 |
| 281 double duration = current_.end_time - current_.start_time; | |
| 282 double spent_in_mutator = Max(current_.start_time - previous_.end_time, 0.0); | 272 double spent_in_mutator = Max(current_.start_time - previous_.end_time, 0.0); |
| 283 | 273 |
| 284 heap_->UpdateCumulativeGCStatistics(duration, spent_in_mutator, | 274 heap_->UpdateCumulativeGCStatistics(duration, spent_in_mutator, |
| 285 current_.scopes[Scope::MC_MARK]); | 275 current_.scopes[Scope::MC_MARK]); |
| 286 | 276 |
| 287 if (current_.type == Event::SCAVENGER && FLAG_trace_gc_ignore_scavenger) | 277 if (current_.type == Event::SCAVENGER && FLAG_trace_gc_ignore_scavenger) |
| 288 return; | 278 return; |
| 289 | 279 |
| 290 if (FLAG_trace_gc_nvp) | 280 if (FLAG_trace_gc_nvp) |
| 291 PrintNVP(); | 281 PrintNVP(); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 328 old_generation_allocation_counter_bytes_ = old_generation_counter_bytes; | 318 old_generation_allocation_counter_bytes_ = old_generation_counter_bytes; |
| 329 allocation_duration_since_gc_ += duration; | 319 allocation_duration_since_gc_ += duration; |
| 330 new_space_allocation_in_bytes_since_gc_ += new_space_allocated_bytes; | 320 new_space_allocation_in_bytes_since_gc_ += new_space_allocated_bytes; |
| 331 old_generation_allocation_in_bytes_since_gc_ += | 321 old_generation_allocation_in_bytes_since_gc_ += |
| 332 old_generation_allocated_bytes; | 322 old_generation_allocated_bytes; |
| 333 } | 323 } |
| 334 | 324 |
| 335 | 325 |
| 336 void GCTracer::AddAllocation(double current_ms) { | 326 void GCTracer::AddAllocation(double current_ms) { |
| 337 allocation_time_ms_ = current_ms; | 327 allocation_time_ms_ = current_ms; |
| 338 new_space_allocation_events_.push_front(AllocationEvent( | 328 past_new_generation_allocations_.Push(MakeBytesAndDuration( |
| 339 allocation_duration_since_gc_, new_space_allocation_in_bytes_since_gc_)); | 329 new_space_allocation_in_bytes_since_gc_, allocation_duration_since_gc_)); |
| 340 old_generation_allocation_events_.push_front( | 330 past_old_generation_allocations_.Push( |
| 341 AllocationEvent(allocation_duration_since_gc_, | 331 MakeBytesAndDuration(old_generation_allocation_in_bytes_since_gc_, |
| 342 old_generation_allocation_in_bytes_since_gc_)); | 332 allocation_duration_since_gc_)); |
| 343 allocation_duration_since_gc_ = 0; | 333 allocation_duration_since_gc_ = 0; |
| 344 new_space_allocation_in_bytes_since_gc_ = 0; | 334 new_space_allocation_in_bytes_since_gc_ = 0; |
| 345 old_generation_allocation_in_bytes_since_gc_ = 0; | 335 old_generation_allocation_in_bytes_since_gc_ = 0; |
| 346 } | 336 } |
| 347 | 337 |
| 348 | 338 |
| 349 void GCTracer::AddContextDisposalTime(double time) { | 339 void GCTracer::AddContextDisposalTime(double time) { |
| 350 context_disposal_events_.push_front(ContextDisposalEvent(time)); | 340 past_context_disposal_times_.Push(time); |
| 351 } | 341 } |
| 352 | 342 |
| 353 | 343 |
| 354 void GCTracer::AddCompactionEvent(double duration, | 344 void GCTracer::AddCompactionEvent(double duration, |
| 355 intptr_t live_bytes_compacted) { | 345 intptr_t live_bytes_compacted) { |
| 356 compaction_events_.push_front( | 346 past_compactions_.Push(MakeBytesAndDuration(live_bytes_compacted, duration)); |
| 357 CompactionEvent(duration, live_bytes_compacted)); | |
| 358 } | 347 } |
| 359 | 348 |
| 360 | 349 |
| 361 void GCTracer::AddSurvivalRatio(double promotion_ratio) { | 350 void GCTracer::AddSurvivalRatio(double promotion_ratio) { |
| 362 survival_events_.push_front(SurvivalEvent(promotion_ratio)); | 351 past_survival_ratios_.Push(promotion_ratio); |
| 363 } | 352 } |
| 364 | 353 |
| 365 | 354 |
| 366 void GCTracer::AddIncrementalMarkingStep(double duration, intptr_t bytes) { | 355 void GCTracer::AddIncrementalMarkingStep(double duration, intptr_t bytes) { |
| 367 cumulative_incremental_marking_steps_++; | 356 cumulative_incremental_marking_steps_++; |
| 368 cumulative_incremental_marking_bytes_ += bytes; | 357 cumulative_incremental_marking_bytes_ += bytes; |
| 369 cumulative_incremental_marking_duration_ += duration; | 358 cumulative_incremental_marking_duration_ += duration; |
| 370 longest_incremental_marking_step_ = | 359 longest_incremental_marking_step_ = |
| 371 Max(longest_incremental_marking_step_, duration); | 360 Max(longest_incremental_marking_step_, duration); |
| 372 cumulative_marking_duration_ += duration; | 361 cumulative_marking_duration_ += duration; |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 661 ContextDisposalRateInMilliseconds(), | 650 ContextDisposalRateInMilliseconds(), |
| 662 CompactionSpeedInBytesPerMillisecond()); | 651 CompactionSpeedInBytesPerMillisecond()); |
| 663 break; | 652 break; |
| 664 case Event::START: | 653 case Event::START: |
| 665 break; | 654 break; |
| 666 default: | 655 default: |
| 667 UNREACHABLE(); | 656 UNREACHABLE(); |
| 668 } | 657 } |
| 669 } | 658 } |
| 670 | 659 |
| 671 | 660 int GCTracer::AverageSpeed(const RingBuffer<BytesAndDuration>& buffer, |
|
Hannes Payer (out of office)
2016/03/29 11:37:38
How about returning double here?
ulan
2016/03/29 12:13:07
Yes, I am going to change all function to return d
Hannes Payer (out of office)
2016/03/29 12:18:34
Ack, cool!
| |
| 672 double GCTracer::MeanDuration(const EventBuffer& events) const { | 661 const BytesAndDuration& initial, double time_ms) { |
| 673 if (events.empty()) return 0.0; | 662 BytesAndDuration sum = buffer.Sum( |
| 674 | 663 [time_ms](BytesAndDuration a, BytesAndDuration b) { |
| 675 double mean = 0.0; | 664 if (time_ms != 0 && a.second >= time_ms) return a; |
| 676 EventBuffer::const_iterator iter = events.begin(); | 665 return std::make_pair(a.first + b.first, a.second + b.second); |
| 677 while (iter != events.end()) { | 666 }, |
| 678 mean += iter->end_time - iter->start_time; | 667 initial); |
| 679 ++iter; | 668 uint64_t bytes = sum.first; |
| 680 } | 669 double durations = sum.second; |
| 681 | 670 if (durations == 0.0) return 0; |
| 682 return mean / events.size(); | 671 double speed = bytes / durations + 0.5; |
| 672 const int max_speed = 1024 * MB; | |
| 673 const int min_speed = 1; | |
| 674 if (speed >= max_speed) return max_speed; | |
| 675 if (speed <= min_speed) return min_speed; | |
| 676 return static_cast<int>(speed); | |
| 683 } | 677 } |
| 684 | 678 |
| 685 | 679 int GCTracer::AverageSpeed(const RingBuffer<BytesAndDuration>& buffer) { |
| 686 double GCTracer::MaxDuration(const EventBuffer& events) const { | 680 return AverageSpeed(buffer, MakeBytesAndDuration(0, 0), 0); |
| 687 if (events.empty()) return 0.0; | |
| 688 | |
| 689 double maximum = 0.0f; | |
| 690 EventBuffer::const_iterator iter = events.begin(); | |
| 691 while (iter != events.end()) { | |
| 692 maximum = Max(iter->end_time - iter->start_time, maximum); | |
| 693 ++iter; | |
| 694 } | |
| 695 | |
| 696 return maximum; | |
| 697 } | 681 } |
| 698 | 682 |
| 699 | |
| 700 intptr_t GCTracer::IncrementalMarkingSpeedInBytesPerMillisecond() const { | 683 intptr_t GCTracer::IncrementalMarkingSpeedInBytesPerMillisecond() const { |
| 701 if (cumulative_incremental_marking_duration_ == 0.0) return 0; | 684 if (cumulative_incremental_marking_duration_ == 0.0) return 0; |
| 702 | |
| 703 // We haven't completed an entire round of incremental marking, yet. | 685 // We haven't completed an entire round of incremental marking, yet. |
| 704 // Use data from GCTracer instead of data from event buffers. | 686 // Use data from GCTracer instead of data from event buffers. |
| 705 if (incremental_mark_compactor_events_.empty()) { | 687 if (past_incremental_marking_steps_.Count() == 0) { |
| 706 return static_cast<intptr_t>(cumulative_incremental_marking_bytes_ / | 688 return static_cast<intptr_t>(cumulative_incremental_marking_bytes_ / |
| 707 cumulative_pure_incremental_marking_duration_); | 689 cumulative_pure_incremental_marking_duration_); |
| 708 } | 690 } |
| 709 | 691 return AverageSpeed(past_incremental_marking_steps_); |
| 710 intptr_t bytes = 0; | |
| 711 double durations = 0.0; | |
| 712 EventBuffer::const_iterator iter = incremental_mark_compactor_events_.begin(); | |
| 713 while (iter != incremental_mark_compactor_events_.end()) { | |
| 714 bytes += iter->incremental_marking_bytes; | |
| 715 durations += iter->pure_incremental_marking_duration; | |
| 716 ++iter; | |
| 717 } | |
| 718 | |
| 719 if (durations == 0.0) return 0; | |
| 720 // Make sure the result is at least 1. | |
| 721 return Max<size_t>(static_cast<size_t>(bytes / durations + 0.5), 1); | |
| 722 } | 692 } |
| 723 | 693 |
| 724 | |
| 725 intptr_t GCTracer::ScavengeSpeedInBytesPerMillisecond( | 694 intptr_t GCTracer::ScavengeSpeedInBytesPerMillisecond( |
| 726 ScavengeSpeedMode mode) const { | 695 ScavengeSpeedMode mode) const { |
| 727 intptr_t bytes = 0; | 696 if (mode == kForAllObjects) { |
| 728 double durations = 0.0; | 697 return AverageSpeed(past_scavenges_total_); |
| 729 EventBuffer::const_iterator iter = scavenger_events_.begin(); | 698 } else { |
| 730 while (iter != scavenger_events_.end()) { | 699 return AverageSpeed(past_scavenges_survived_); |
| 731 bytes += mode == kForAllObjects ? iter->new_space_object_size | |
| 732 : iter->survived_new_space_object_size; | |
| 733 durations += iter->end_time - iter->start_time; | |
| 734 ++iter; | |
| 735 } | 700 } |
| 736 | |
| 737 if (durations == 0.0) return 0; | |
| 738 // Make sure the result is at least 1. | |
| 739 return Max<size_t>(static_cast<size_t>(bytes / durations + 0.5), 1); | |
| 740 } | 701 } |
| 741 | 702 |
| 742 | |
| 743 intptr_t GCTracer::CompactionSpeedInBytesPerMillisecond() const { | 703 intptr_t GCTracer::CompactionSpeedInBytesPerMillisecond() const { |
| 744 if (compaction_events_.size() == 0) return 0; | 704 return AverageSpeed(past_compactions_); |
| 745 intptr_t bytes = 0; | |
| 746 double durations = 0.0; | |
| 747 CompactionEventBuffer::const_iterator iter = compaction_events_.begin(); | |
| 748 while (iter != compaction_events_.end()) { | |
| 749 bytes += iter->live_bytes_compacted; | |
| 750 durations += iter->duration; | |
| 751 ++iter; | |
| 752 } | |
| 753 | |
| 754 if (durations == 0.0) return 0; | |
| 755 // Make sure the result is at least 1. | |
| 756 return Max<intptr_t>(static_cast<intptr_t>(bytes / durations + 0.5), 1); | |
| 757 } | 705 } |
| 758 | 706 |
| 759 | |
| 760 intptr_t GCTracer::MarkCompactSpeedInBytesPerMillisecond() const { | 707 intptr_t GCTracer::MarkCompactSpeedInBytesPerMillisecond() const { |
| 761 intptr_t bytes = 0; | 708 return AverageSpeed(past_mark_compacts_); |
| 762 double durations = 0.0; | |
| 763 EventBuffer::const_iterator iter = mark_compactor_events_.begin(); | |
| 764 while (iter != mark_compactor_events_.end()) { | |
| 765 bytes += iter->start_object_size; | |
| 766 durations += iter->end_time - iter->start_time; | |
| 767 ++iter; | |
| 768 } | |
| 769 | |
| 770 if (durations == 0.0) return 0; | |
| 771 // Make sure the result is at least 1. | |
| 772 return Max<size_t>(static_cast<size_t>(bytes / durations + 0.5), 1); | |
| 773 } | 709 } |
| 774 | 710 |
| 775 | |
| 776 intptr_t GCTracer::FinalIncrementalMarkCompactSpeedInBytesPerMillisecond() | 711 intptr_t GCTracer::FinalIncrementalMarkCompactSpeedInBytesPerMillisecond() |
| 777 const { | 712 const { |
| 778 intptr_t bytes = 0; | 713 return AverageSpeed(past_incremental_mark_compacts_); |
| 779 double durations = 0.0; | |
| 780 EventBuffer::const_iterator iter = incremental_mark_compactor_events_.begin(); | |
| 781 while (iter != incremental_mark_compactor_events_.end()) { | |
| 782 bytes += iter->start_object_size; | |
| 783 durations += iter->end_time - iter->start_time; | |
| 784 ++iter; | |
| 785 } | |
| 786 | |
| 787 if (durations == 0.0) return 0; | |
| 788 // Make sure the result is at least 1. | |
| 789 return Max<size_t>(static_cast<size_t>(bytes / durations + 0.5), 1); | |
| 790 } | 714 } |
| 791 | 715 |
| 792 | |
| 793 double GCTracer::CombinedMarkCompactSpeedInBytesPerMillisecond() { | 716 double GCTracer::CombinedMarkCompactSpeedInBytesPerMillisecond() { |
| 794 if (combined_mark_compact_speed_cache_ > 0) | 717 if (combined_mark_compact_speed_cache_ > 0) |
| 795 return combined_mark_compact_speed_cache_; | 718 return combined_mark_compact_speed_cache_; |
| 796 const double kMinimumMarkingSpeed = 0.5; | 719 const double kMinimumMarkingSpeed = 0.5; |
| 797 double speed1 = | 720 double speed1 = |
| 798 static_cast<double>(IncrementalMarkingSpeedInBytesPerMillisecond()); | 721 static_cast<double>(IncrementalMarkingSpeedInBytesPerMillisecond()); |
| 799 double speed2 = static_cast<double>( | 722 double speed2 = static_cast<double>( |
| 800 FinalIncrementalMarkCompactSpeedInBytesPerMillisecond()); | 723 FinalIncrementalMarkCompactSpeedInBytesPerMillisecond()); |
| 801 if (speed1 < kMinimumMarkingSpeed || speed2 < kMinimumMarkingSpeed) { | 724 if (speed1 < kMinimumMarkingSpeed || speed2 < kMinimumMarkingSpeed) { |
| 802 // No data for the incremental marking speed. | 725 // No data for the incremental marking speed. |
| 803 // Return the non-incremental mark-compact speed. | 726 // Return the non-incremental mark-compact speed. |
| 804 combined_mark_compact_speed_cache_ = | 727 combined_mark_compact_speed_cache_ = |
| 805 static_cast<double>(MarkCompactSpeedInBytesPerMillisecond()); | 728 static_cast<double>(MarkCompactSpeedInBytesPerMillisecond()); |
| 806 } else { | 729 } else { |
| 807 // Combine the speed of incremental step and the speed of the final step. | 730 // Combine the speed of incremental step and the speed of the final step. |
| 808 // 1 / (1 / speed1 + 1 / speed2) = speed1 * speed2 / (speed1 + speed2). | 731 // 1 / (1 / speed1 + 1 / speed2) = speed1 * speed2 / (speed1 + speed2). |
| 809 combined_mark_compact_speed_cache_ = speed1 * speed2 / (speed1 + speed2); | 732 combined_mark_compact_speed_cache_ = speed1 * speed2 / (speed1 + speed2); |
| 810 } | 733 } |
| 811 return combined_mark_compact_speed_cache_; | 734 return combined_mark_compact_speed_cache_; |
| 812 } | 735 } |
| 813 | 736 |
| 814 | |
| 815 size_t GCTracer::NewSpaceAllocationThroughputInBytesPerMillisecond( | 737 size_t GCTracer::NewSpaceAllocationThroughputInBytesPerMillisecond( |
| 816 double time_ms) const { | 738 double time_ms) const { |
| 817 size_t bytes = new_space_allocation_in_bytes_since_gc_; | 739 size_t bytes = new_space_allocation_in_bytes_since_gc_; |
| 818 double durations = allocation_duration_since_gc_; | 740 double durations = allocation_duration_since_gc_; |
| 819 AllocationEventBuffer::const_iterator iter = | 741 return static_cast<size_t>( |
| 820 new_space_allocation_events_.begin(); | 742 AverageSpeed(past_new_generation_allocations_, |
| 821 const size_t max_bytes = static_cast<size_t>(-1); | 743 MakeBytesAndDuration(bytes, durations), time_ms)); |
| 822 while (iter != new_space_allocation_events_.end() && | |
| 823 bytes < max_bytes - bytes && (time_ms == 0 || durations < time_ms)) { | |
| 824 bytes += iter->allocation_in_bytes_; | |
| 825 durations += iter->duration_; | |
| 826 ++iter; | |
| 827 } | |
| 828 | |
| 829 if (durations == 0.0) return 0; | |
| 830 // Make sure the result is at least 1. | |
| 831 return Max<size_t>(static_cast<size_t>(bytes / durations + 0.5), 1); | |
| 832 } | 744 } |
| 833 | 745 |
| 834 | |
| 835 size_t GCTracer::OldGenerationAllocationThroughputInBytesPerMillisecond( | 746 size_t GCTracer::OldGenerationAllocationThroughputInBytesPerMillisecond( |
| 836 double time_ms) const { | 747 double time_ms) const { |
| 837 size_t bytes = old_generation_allocation_in_bytes_since_gc_; | 748 size_t bytes = old_generation_allocation_in_bytes_since_gc_; |
| 838 double durations = allocation_duration_since_gc_; | 749 double durations = allocation_duration_since_gc_; |
| 839 AllocationEventBuffer::const_iterator iter = | 750 return static_cast<size_t>( |
| 840 old_generation_allocation_events_.begin(); | 751 AverageSpeed(past_old_generation_allocations_, |
| 841 const size_t max_bytes = static_cast<size_t>(-1); | 752 MakeBytesAndDuration(bytes, durations), time_ms)); |
| 842 while (iter != old_generation_allocation_events_.end() && | |
| 843 bytes < max_bytes - bytes && (time_ms == 0 || durations < time_ms)) { | |
| 844 bytes += iter->allocation_in_bytes_; | |
| 845 durations += iter->duration_; | |
| 846 ++iter; | |
| 847 } | |
| 848 | |
| 849 if (durations == 0.0) return 0; | |
| 850 // Make sure the result is at least 1. | |
| 851 return Max<size_t>(static_cast<size_t>(bytes / durations + 0.5), 1); | |
| 852 } | 753 } |
| 853 | 754 |
| 854 | |
| 855 size_t GCTracer::AllocationThroughputInBytesPerMillisecond( | 755 size_t GCTracer::AllocationThroughputInBytesPerMillisecond( |
| 856 double time_ms) const { | 756 double time_ms) const { |
| 857 return NewSpaceAllocationThroughputInBytesPerMillisecond(time_ms) + | 757 return NewSpaceAllocationThroughputInBytesPerMillisecond(time_ms) + |
| 858 OldGenerationAllocationThroughputInBytesPerMillisecond(time_ms); | 758 OldGenerationAllocationThroughputInBytesPerMillisecond(time_ms); |
| 859 } | 759 } |
| 860 | 760 |
| 861 | 761 |
| 862 size_t GCTracer::CurrentAllocationThroughputInBytesPerMillisecond() const { | 762 size_t GCTracer::CurrentAllocationThroughputInBytesPerMillisecond() const { |
| 863 return AllocationThroughputInBytesPerMillisecond(kThroughputTimeFrameMs); | 763 return AllocationThroughputInBytesPerMillisecond(kThroughputTimeFrameMs); |
| 864 } | 764 } |
| 865 | 765 |
| 866 | 766 |
| 867 size_t GCTracer::CurrentOldGenerationAllocationThroughputInBytesPerMillisecond() | 767 size_t GCTracer::CurrentOldGenerationAllocationThroughputInBytesPerMillisecond() |
| 868 const { | 768 const { |
| 869 return OldGenerationAllocationThroughputInBytesPerMillisecond( | 769 return OldGenerationAllocationThroughputInBytesPerMillisecond( |
| 870 kThroughputTimeFrameMs); | 770 kThroughputTimeFrameMs); |
| 871 } | 771 } |
| 872 | 772 |
| 873 | |
| 874 double GCTracer::ContextDisposalRateInMilliseconds() const { | 773 double GCTracer::ContextDisposalRateInMilliseconds() const { |
| 875 if (context_disposal_events_.size() < kRingBufferMaxSize) return 0.0; | 774 if (past_context_disposal_times_.Count() < past_context_disposal_times_.kSize) |
| 876 | 775 return 0.0; |
| 877 double begin = heap_->MonotonicallyIncreasingTimeInMs(); | 776 double begin = heap_->MonotonicallyIncreasingTimeInMs(); |
| 878 double end = 0.0; | 777 double end = past_context_disposal_times_.Sum( |
| 879 ContextDisposalEventBuffer::const_iterator iter = | 778 [](double a, double b) { return b; }, 0.0); |
| 880 context_disposal_events_.begin(); | 779 return (begin - end) / past_context_disposal_times_.Count(); |
| 881 while (iter != context_disposal_events_.end()) { | |
| 882 end = iter->time_; | |
| 883 ++iter; | |
| 884 } | |
| 885 | |
| 886 return (begin - end) / context_disposal_events_.size(); | |
| 887 } | 780 } |
| 888 | 781 |
| 889 | |
| 890 double GCTracer::AverageSurvivalRatio() const { | 782 double GCTracer::AverageSurvivalRatio() const { |
| 891 if (survival_events_.size() == 0) return 0.0; | 783 if (past_survival_ratios_.Count() == 0) return 0.0; |
| 892 | 784 double sum = |
| 893 double sum_of_rates = 0.0; | 785 past_survival_ratios_.Sum([](double a, double b) { return a + b; }, 0.0); |
| 894 SurvivalEventBuffer::const_iterator iter = survival_events_.begin(); | 786 return sum / past_survival_ratios_.Count(); |
| 895 while (iter != survival_events_.end()) { | |
| 896 sum_of_rates += iter->promotion_ratio_; | |
| 897 ++iter; | |
| 898 } | |
| 899 | |
| 900 return sum_of_rates / static_cast<double>(survival_events_.size()); | |
| 901 } | 787 } |
| 902 | 788 |
| 903 | |
| 904 bool GCTracer::SurvivalEventsRecorded() const { | 789 bool GCTracer::SurvivalEventsRecorded() const { |
| 905 return survival_events_.size() > 0; | 790 return past_survival_ratios_.Count() > 0; |
| 906 } | 791 } |
| 907 | 792 |
| 908 | 793 void GCTracer::ResetSurvivalEvents() { past_survival_ratios_.Reset(); } |
| 909 void GCTracer::ResetSurvivalEvents() { survival_events_.reset(); } | |
| 910 } // namespace internal | 794 } // namespace internal |
| 911 } // namespace v8 | 795 } // namespace v8 |
| OLD | NEW |