| 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 recorded_scavenges_total_.Push( |
| 233 MakeBytesAndDuration(current_.new_space_object_size, duration)); |
| 234 recorded_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 recorded_incremental_marking_steps_.Push( |
| 255 MakeBytesAndDuration(current_.incremental_marking_bytes, |
| 256 current_.pure_incremental_marking_duration)); |
| 257 recorded_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 recorded_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 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 if (allocation_duration_since_gc_ > 0) { | 328 if (allocation_duration_since_gc_ > 0) { |
| 339 new_space_allocation_events_.push_front( | 329 recorded_new_generation_allocations_.Push( |
| 340 AllocationEvent(allocation_duration_since_gc_, | 330 MakeBytesAndDuration(new_space_allocation_in_bytes_since_gc_, |
| 341 new_space_allocation_in_bytes_since_gc_)); | 331 allocation_duration_since_gc_)); |
| 342 old_generation_allocation_events_.push_front( | 332 recorded_old_generation_allocations_.Push( |
| 343 AllocationEvent(allocation_duration_since_gc_, | 333 MakeBytesAndDuration(old_generation_allocation_in_bytes_since_gc_, |
| 344 old_generation_allocation_in_bytes_since_gc_)); | 334 allocation_duration_since_gc_)); |
| 345 } | 335 } |
| 346 allocation_duration_since_gc_ = 0; | 336 allocation_duration_since_gc_ = 0; |
| 347 new_space_allocation_in_bytes_since_gc_ = 0; | 337 new_space_allocation_in_bytes_since_gc_ = 0; |
| 348 old_generation_allocation_in_bytes_since_gc_ = 0; | 338 old_generation_allocation_in_bytes_since_gc_ = 0; |
| 349 } | 339 } |
| 350 | 340 |
| 351 | 341 |
| 352 void GCTracer::AddContextDisposalTime(double time) { | 342 void GCTracer::AddContextDisposalTime(double time) { |
| 353 context_disposal_events_.push_front(ContextDisposalEvent(time)); | 343 recorded_context_disposal_times_.Push(time); |
| 354 } | 344 } |
| 355 | 345 |
| 356 | 346 |
| 357 void GCTracer::AddCompactionEvent(double duration, | 347 void GCTracer::AddCompactionEvent(double duration, |
| 358 intptr_t live_bytes_compacted) { | 348 intptr_t live_bytes_compacted) { |
| 359 compaction_events_.push_front( | 349 recorded_compactions_.Push( |
| 360 CompactionEvent(duration, live_bytes_compacted)); | 350 MakeBytesAndDuration(live_bytes_compacted, duration)); |
| 361 } | 351 } |
| 362 | 352 |
| 363 | 353 |
| 364 void GCTracer::AddSurvivalRatio(double promotion_ratio) { | 354 void GCTracer::AddSurvivalRatio(double promotion_ratio) { |
| 365 survival_events_.push_front(SurvivalEvent(promotion_ratio)); | 355 recorded_survival_ratios_.Push(promotion_ratio); |
| 366 } | 356 } |
| 367 | 357 |
| 368 | 358 |
| 369 void GCTracer::AddIncrementalMarkingStep(double duration, intptr_t bytes) { | 359 void GCTracer::AddIncrementalMarkingStep(double duration, intptr_t bytes) { |
| 370 cumulative_incremental_marking_steps_++; | 360 cumulative_incremental_marking_steps_++; |
| 371 cumulative_incremental_marking_bytes_ += bytes; | 361 cumulative_incremental_marking_bytes_ += bytes; |
| 372 cumulative_incremental_marking_duration_ += duration; | 362 cumulative_incremental_marking_duration_ += duration; |
| 373 longest_incremental_marking_step_ = | 363 longest_incremental_marking_step_ = |
| 374 Max(longest_incremental_marking_step_, duration); | 364 Max(longest_incremental_marking_step_, duration); |
| 375 cumulative_marking_duration_ += duration; | 365 cumulative_marking_duration_ += duration; |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 662 ContextDisposalRateInMilliseconds(), | 652 ContextDisposalRateInMilliseconds(), |
| 663 CompactionSpeedInBytesPerMillisecond()); | 653 CompactionSpeedInBytesPerMillisecond()); |
| 664 break; | 654 break; |
| 665 case Event::START: | 655 case Event::START: |
| 666 break; | 656 break; |
| 667 default: | 657 default: |
| 668 UNREACHABLE(); | 658 UNREACHABLE(); |
| 669 } | 659 } |
| 670 } | 660 } |
| 671 | 661 |
| 672 | 662 int GCTracer::AverageSpeed(const RingBuffer<BytesAndDuration>& buffer, |
| 673 double GCTracer::MeanDuration(const EventBuffer& events) const { | 663 const BytesAndDuration& initial, double time_ms) { |
| 674 if (events.empty()) return 0.0; | 664 BytesAndDuration sum = buffer.Sum( |
| 675 | 665 [time_ms](BytesAndDuration a, BytesAndDuration b) { |
| 676 double mean = 0.0; | 666 if (time_ms != 0 && a.second >= time_ms) return a; |
| 677 EventBuffer::const_iterator iter = events.begin(); | 667 return std::make_pair(a.first + b.first, a.second + b.second); |
| 678 while (iter != events.end()) { | 668 }, |
| 679 mean += iter->end_time - iter->start_time; | 669 initial); |
| 680 ++iter; | 670 uint64_t bytes = sum.first; |
| 681 } | 671 double durations = sum.second; |
| 682 | 672 if (durations == 0.0) return 0; |
| 683 return mean / events.size(); | 673 double speed = bytes / durations + 0.5; |
| 674 const int max_speed = 1024 * MB; |
| 675 const int min_speed = 1; |
| 676 if (speed >= max_speed) return max_speed; |
| 677 if (speed <= min_speed) return min_speed; |
| 678 return static_cast<int>(speed); |
| 684 } | 679 } |
| 685 | 680 |
| 686 | 681 int GCTracer::AverageSpeed(const RingBuffer<BytesAndDuration>& buffer) { |
| 687 double GCTracer::MaxDuration(const EventBuffer& events) const { | 682 return AverageSpeed(buffer, MakeBytesAndDuration(0, 0), 0); |
| 688 if (events.empty()) return 0.0; | |
| 689 | |
| 690 double maximum = 0.0f; | |
| 691 EventBuffer::const_iterator iter = events.begin(); | |
| 692 while (iter != events.end()) { | |
| 693 maximum = Max(iter->end_time - iter->start_time, maximum); | |
| 694 ++iter; | |
| 695 } | |
| 696 | |
| 697 return maximum; | |
| 698 } | 683 } |
| 699 | 684 |
| 700 | |
| 701 intptr_t GCTracer::IncrementalMarkingSpeedInBytesPerMillisecond() const { | 685 intptr_t GCTracer::IncrementalMarkingSpeedInBytesPerMillisecond() const { |
| 702 if (cumulative_incremental_marking_duration_ == 0.0) return 0; | 686 if (cumulative_incremental_marking_duration_ == 0.0) return 0; |
| 703 | |
| 704 // We haven't completed an entire round of incremental marking, yet. | 687 // We haven't completed an entire round of incremental marking, yet. |
| 705 // Use data from GCTracer instead of data from event buffers. | 688 // Use data from GCTracer instead of data from event buffers. |
| 706 if (incremental_mark_compactor_events_.empty()) { | 689 if (recorded_incremental_marking_steps_.Count() == 0) { |
| 707 return static_cast<intptr_t>(cumulative_incremental_marking_bytes_ / | 690 return static_cast<intptr_t>(cumulative_incremental_marking_bytes_ / |
| 708 cumulative_pure_incremental_marking_duration_); | 691 cumulative_pure_incremental_marking_duration_); |
| 709 } | 692 } |
| 710 | 693 return AverageSpeed(recorded_incremental_marking_steps_); |
| 711 intptr_t bytes = 0; | |
| 712 double durations = 0.0; | |
| 713 EventBuffer::const_iterator iter = incremental_mark_compactor_events_.begin(); | |
| 714 while (iter != incremental_mark_compactor_events_.end()) { | |
| 715 bytes += iter->incremental_marking_bytes; | |
| 716 durations += iter->pure_incremental_marking_duration; | |
| 717 ++iter; | |
| 718 } | |
| 719 | |
| 720 if (durations == 0.0) return 0; | |
| 721 // Make sure the result is at least 1. | |
| 722 return Max<size_t>(static_cast<size_t>(bytes / durations + 0.5), 1); | |
| 723 } | 694 } |
| 724 | 695 |
| 725 | |
| 726 intptr_t GCTracer::ScavengeSpeedInBytesPerMillisecond( | 696 intptr_t GCTracer::ScavengeSpeedInBytesPerMillisecond( |
| 727 ScavengeSpeedMode mode) const { | 697 ScavengeSpeedMode mode) const { |
| 728 intptr_t bytes = 0; | 698 if (mode == kForAllObjects) { |
| 729 double durations = 0.0; | 699 return AverageSpeed(recorded_scavenges_total_); |
| 730 EventBuffer::const_iterator iter = scavenger_events_.begin(); | 700 } else { |
| 731 while (iter != scavenger_events_.end()) { | 701 return AverageSpeed(recorded_scavenges_survived_); |
| 732 bytes += mode == kForAllObjects ? iter->new_space_object_size | |
| 733 : iter->survived_new_space_object_size; | |
| 734 durations += iter->end_time - iter->start_time; | |
| 735 ++iter; | |
| 736 } | 702 } |
| 737 | |
| 738 if (durations == 0.0) return 0; | |
| 739 // Make sure the result is at least 1. | |
| 740 return Max<size_t>(static_cast<size_t>(bytes / durations + 0.5), 1); | |
| 741 } | 703 } |
| 742 | 704 |
| 743 | |
| 744 intptr_t GCTracer::CompactionSpeedInBytesPerMillisecond() const { | 705 intptr_t GCTracer::CompactionSpeedInBytesPerMillisecond() const { |
| 745 if (compaction_events_.size() == 0) return 0; | 706 return AverageSpeed(recorded_compactions_); |
| 746 intptr_t bytes = 0; | |
| 747 double durations = 0.0; | |
| 748 CompactionEventBuffer::const_iterator iter = compaction_events_.begin(); | |
| 749 while (iter != compaction_events_.end()) { | |
| 750 bytes += iter->live_bytes_compacted; | |
| 751 durations += iter->duration; | |
| 752 ++iter; | |
| 753 } | |
| 754 | |
| 755 if (durations == 0.0) return 0; | |
| 756 // Make sure the result is at least 1. | |
| 757 return Max<intptr_t>(static_cast<intptr_t>(bytes / durations + 0.5), 1); | |
| 758 } | 707 } |
| 759 | 708 |
| 760 | |
| 761 intptr_t GCTracer::MarkCompactSpeedInBytesPerMillisecond() const { | 709 intptr_t GCTracer::MarkCompactSpeedInBytesPerMillisecond() const { |
| 762 intptr_t bytes = 0; | 710 return AverageSpeed(recorded_mark_compacts_); |
| 763 double durations = 0.0; | |
| 764 EventBuffer::const_iterator iter = mark_compactor_events_.begin(); | |
| 765 while (iter != mark_compactor_events_.end()) { | |
| 766 bytes += iter->start_object_size; | |
| 767 durations += iter->end_time - iter->start_time; | |
| 768 ++iter; | |
| 769 } | |
| 770 | |
| 771 if (durations == 0.0) return 0; | |
| 772 // Make sure the result is at least 1. | |
| 773 return Max<size_t>(static_cast<size_t>(bytes / durations + 0.5), 1); | |
| 774 } | 711 } |
| 775 | 712 |
| 776 | |
| 777 intptr_t GCTracer::FinalIncrementalMarkCompactSpeedInBytesPerMillisecond() | 713 intptr_t GCTracer::FinalIncrementalMarkCompactSpeedInBytesPerMillisecond() |
| 778 const { | 714 const { |
| 779 intptr_t bytes = 0; | 715 return AverageSpeed(recorded_incremental_mark_compacts_); |
| 780 double durations = 0.0; | |
| 781 EventBuffer::const_iterator iter = incremental_mark_compactor_events_.begin(); | |
| 782 while (iter != incremental_mark_compactor_events_.end()) { | |
| 783 bytes += iter->start_object_size; | |
| 784 durations += iter->end_time - iter->start_time; | |
| 785 ++iter; | |
| 786 } | |
| 787 | |
| 788 if (durations == 0.0) return 0; | |
| 789 // Make sure the result is at least 1. | |
| 790 return Max<size_t>(static_cast<size_t>(bytes / durations + 0.5), 1); | |
| 791 } | 716 } |
| 792 | 717 |
| 793 | |
| 794 double GCTracer::CombinedMarkCompactSpeedInBytesPerMillisecond() { | 718 double GCTracer::CombinedMarkCompactSpeedInBytesPerMillisecond() { |
| 795 if (combined_mark_compact_speed_cache_ > 0) | 719 if (combined_mark_compact_speed_cache_ > 0) |
| 796 return combined_mark_compact_speed_cache_; | 720 return combined_mark_compact_speed_cache_; |
| 797 const double kMinimumMarkingSpeed = 0.5; | 721 const double kMinimumMarkingSpeed = 0.5; |
| 798 double speed1 = | 722 double speed1 = |
| 799 static_cast<double>(IncrementalMarkingSpeedInBytesPerMillisecond()); | 723 static_cast<double>(IncrementalMarkingSpeedInBytesPerMillisecond()); |
| 800 double speed2 = static_cast<double>( | 724 double speed2 = static_cast<double>( |
| 801 FinalIncrementalMarkCompactSpeedInBytesPerMillisecond()); | 725 FinalIncrementalMarkCompactSpeedInBytesPerMillisecond()); |
| 802 if (speed1 < kMinimumMarkingSpeed || speed2 < kMinimumMarkingSpeed) { | 726 if (speed1 < kMinimumMarkingSpeed || speed2 < kMinimumMarkingSpeed) { |
| 803 // No data for the incremental marking speed. | 727 // No data for the incremental marking speed. |
| 804 // Return the non-incremental mark-compact speed. | 728 // Return the non-incremental mark-compact speed. |
| 805 combined_mark_compact_speed_cache_ = | 729 combined_mark_compact_speed_cache_ = |
| 806 static_cast<double>(MarkCompactSpeedInBytesPerMillisecond()); | 730 static_cast<double>(MarkCompactSpeedInBytesPerMillisecond()); |
| 807 } else { | 731 } else { |
| 808 // Combine the speed of incremental step and the speed of the final step. | 732 // Combine the speed of incremental step and the speed of the final step. |
| 809 // 1 / (1 / speed1 + 1 / speed2) = speed1 * speed2 / (speed1 + speed2). | 733 // 1 / (1 / speed1 + 1 / speed2) = speed1 * speed2 / (speed1 + speed2). |
| 810 combined_mark_compact_speed_cache_ = speed1 * speed2 / (speed1 + speed2); | 734 combined_mark_compact_speed_cache_ = speed1 * speed2 / (speed1 + speed2); |
| 811 } | 735 } |
| 812 return combined_mark_compact_speed_cache_; | 736 return combined_mark_compact_speed_cache_; |
| 813 } | 737 } |
| 814 | 738 |
| 815 double GCTracer::NewSpaceAllocationThroughputInBytesPerMillisecond( | 739 double GCTracer::NewSpaceAllocationThroughputInBytesPerMillisecond( |
| 816 double time_ms) const { | 740 double time_ms) const { |
| 817 size_t bytes = new_space_allocation_in_bytes_since_gc_; | 741 size_t bytes = new_space_allocation_in_bytes_since_gc_; |
| 818 double durations = allocation_duration_since_gc_; | 742 double durations = allocation_duration_since_gc_; |
| 819 AllocationEventBuffer::const_iterator iter = | 743 return AverageSpeed(recorded_new_generation_allocations_, |
| 820 new_space_allocation_events_.begin(); | 744 MakeBytesAndDuration(bytes, durations), time_ms); |
| 821 const size_t max_bytes = static_cast<size_t>(-1); | |
| 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 | |
| 831 // Make sure the result is at least 1. | |
| 832 return Max<double>(bytes / durations, 1); | |
| 833 } | 745 } |
| 834 | 746 |
| 835 double GCTracer::OldGenerationAllocationThroughputInBytesPerMillisecond( | 747 double GCTracer::OldGenerationAllocationThroughputInBytesPerMillisecond( |
| 836 double time_ms) const { | 748 double time_ms) const { |
| 837 size_t bytes = old_generation_allocation_in_bytes_since_gc_; | 749 size_t bytes = old_generation_allocation_in_bytes_since_gc_; |
| 838 double durations = allocation_duration_since_gc_; | 750 double durations = allocation_duration_since_gc_; |
| 839 AllocationEventBuffer::const_iterator iter = | 751 return AverageSpeed(recorded_old_generation_allocations_, |
| 840 old_generation_allocation_events_.begin(); | 752 MakeBytesAndDuration(bytes, durations), time_ms); |
| 841 const size_t max_bytes = static_cast<size_t>(-1); | |
| 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<double>(bytes / durations, 1); | |
| 852 } | 753 } |
| 853 | 754 |
| 854 double GCTracer::AllocationThroughputInBytesPerMillisecond( | 755 double GCTracer::AllocationThroughputInBytesPerMillisecond( |
| 855 double time_ms) const { | 756 double time_ms) const { |
| 856 return NewSpaceAllocationThroughputInBytesPerMillisecond(time_ms) + | 757 return NewSpaceAllocationThroughputInBytesPerMillisecond(time_ms) + |
| 857 OldGenerationAllocationThroughputInBytesPerMillisecond(time_ms); | 758 OldGenerationAllocationThroughputInBytesPerMillisecond(time_ms); |
| 858 } | 759 } |
| 859 | 760 |
| 860 | 761 |
| 861 size_t GCTracer::CurrentAllocationThroughputInBytesPerMillisecond() const { | 762 size_t GCTracer::CurrentAllocationThroughputInBytesPerMillisecond() const { |
| 862 return AllocationThroughputInBytesPerMillisecond(kThroughputTimeFrameMs); | 763 return AllocationThroughputInBytesPerMillisecond(kThroughputTimeFrameMs); |
| 863 } | 764 } |
| 864 | 765 |
| 865 | 766 |
| 866 size_t GCTracer::CurrentOldGenerationAllocationThroughputInBytesPerMillisecond() | 767 size_t GCTracer::CurrentOldGenerationAllocationThroughputInBytesPerMillisecond() |
| 867 const { | 768 const { |
| 868 return OldGenerationAllocationThroughputInBytesPerMillisecond( | 769 return OldGenerationAllocationThroughputInBytesPerMillisecond( |
| 869 kThroughputTimeFrameMs); | 770 kThroughputTimeFrameMs); |
| 870 } | 771 } |
| 871 | 772 |
| 872 | |
| 873 double GCTracer::ContextDisposalRateInMilliseconds() const { | 773 double GCTracer::ContextDisposalRateInMilliseconds() const { |
| 874 if (context_disposal_events_.size() < kRingBufferMaxSize) return 0.0; | 774 if (recorded_context_disposal_times_.Count() < |
| 875 | 775 recorded_context_disposal_times_.kSize) |
| 776 return 0.0; |
| 876 double begin = heap_->MonotonicallyIncreasingTimeInMs(); | 777 double begin = heap_->MonotonicallyIncreasingTimeInMs(); |
| 877 double end = 0.0; | 778 double end = recorded_context_disposal_times_.Sum( |
| 878 ContextDisposalEventBuffer::const_iterator iter = | 779 [](double a, double b) { return b; }, 0.0); |
| 879 context_disposal_events_.begin(); | 780 return (begin - end) / recorded_context_disposal_times_.Count(); |
| 880 while (iter != context_disposal_events_.end()) { | |
| 881 end = iter->time_; | |
| 882 ++iter; | |
| 883 } | |
| 884 | |
| 885 return (begin - end) / context_disposal_events_.size(); | |
| 886 } | 781 } |
| 887 | 782 |
| 888 | |
| 889 double GCTracer::AverageSurvivalRatio() const { | 783 double GCTracer::AverageSurvivalRatio() const { |
| 890 if (survival_events_.size() == 0) return 0.0; | 784 if (recorded_survival_ratios_.Count() == 0) return 0.0; |
| 891 | 785 double sum = recorded_survival_ratios_.Sum( |
| 892 double sum_of_rates = 0.0; | 786 [](double a, double b) { return a + b; }, 0.0); |
| 893 SurvivalEventBuffer::const_iterator iter = survival_events_.begin(); | 787 return sum / recorded_survival_ratios_.Count(); |
| 894 while (iter != survival_events_.end()) { | |
| 895 sum_of_rates += iter->promotion_ratio_; | |
| 896 ++iter; | |
| 897 } | |
| 898 | |
| 899 return sum_of_rates / static_cast<double>(survival_events_.size()); | |
| 900 } | 788 } |
| 901 | 789 |
| 902 | |
| 903 bool GCTracer::SurvivalEventsRecorded() const { | 790 bool GCTracer::SurvivalEventsRecorded() const { |
| 904 return survival_events_.size() > 0; | 791 return recorded_survival_ratios_.Count() > 0; |
| 905 } | 792 } |
| 906 | 793 |
| 907 | 794 void GCTracer::ResetSurvivalEvents() { recorded_survival_ratios_.Reset(); } |
| 908 void GCTracer::ResetSurvivalEvents() { survival_events_.reset(); } | |
| 909 } // namespace internal | 795 } // namespace internal |
| 910 } // namespace v8 | 796 } // namespace v8 |
| OLD | NEW |