| // Copyright 2020 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/heap/cppgc/incremental-marking-schedule.h" |
| |
| #include <cmath> |
| |
| #include "src/heap/cppgc/globals.h" |
| |
| namespace cppgc { |
| namespace internal { |
| |
| // static |
| constexpr size_t IncrementalMarkingSchedule::kInvalidLastEstimatedLiveBytes; |
| |
| const double IncrementalMarkingSchedule::kEstimatedMarkingTimeMs = 500.0; |
| const size_t IncrementalMarkingSchedule::kMinimumMarkedBytesPerIncrementalStep = |
| 64 * kKB; |
| |
| void IncrementalMarkingSchedule::NotifyIncrementalMarkingStart() { |
| DCHECK(incremental_marking_start_time_.IsNull()); |
| incremental_marking_start_time_ = v8::base::TimeTicks::Now(); |
| } |
| |
| void IncrementalMarkingSchedule::UpdateIncrementalMarkedBytes( |
| size_t overall_marked_bytes) { |
| DCHECK(!incremental_marking_start_time_.IsNull()); |
| incrementally_marked_bytes_ = overall_marked_bytes; |
| } |
| |
| void IncrementalMarkingSchedule::AddConcurrentlyMarkedBytes( |
| size_t marked_bytes) { |
| DCHECK(!incremental_marking_start_time_.IsNull()); |
| concurrently_marked_bytes_.fetch_add(marked_bytes, std::memory_order_relaxed); |
| } |
| |
| size_t IncrementalMarkingSchedule::GetOverallMarkedBytes() const { |
| return incrementally_marked_bytes_ + GetConcurrentlyMarkedBytes(); |
| } |
| |
| size_t IncrementalMarkingSchedule::GetConcurrentlyMarkedBytes() const { |
| return concurrently_marked_bytes_.load(std::memory_order_relaxed); |
| } |
| |
| double IncrementalMarkingSchedule::GetElapsedTimeInMs( |
| v8::base::TimeTicks start_time) { |
| if (elapsed_time_for_testing_ != kNoSetElapsedTimeForTesting) { |
| double elapsed_time = elapsed_time_for_testing_; |
| elapsed_time_for_testing_ = kNoSetElapsedTimeForTesting; |
| return elapsed_time; |
| } |
| return (v8::base::TimeTicks::Now() - start_time).InMillisecondsF(); |
| } |
| |
| size_t IncrementalMarkingSchedule::GetNextIncrementalStepDuration( |
| size_t estimated_live_bytes) { |
| last_estimated_live_bytes_ = estimated_live_bytes; |
| DCHECK(!incremental_marking_start_time_.IsNull()); |
| double elapsed_time_in_ms = |
| GetElapsedTimeInMs(incremental_marking_start_time_); |
| size_t actual_marked_bytes = GetOverallMarkedBytes(); |
| size_t expected_marked_bytes = std::ceil( |
| estimated_live_bytes * elapsed_time_in_ms / kEstimatedMarkingTimeMs); |
| if (expected_marked_bytes < actual_marked_bytes) { |
| // Marking is ahead of schedule, incremental marking should do the minimum. |
| return kMinimumMarkedBytesPerIncrementalStep; |
| } |
| // Assuming marking will take |kEstimatedMarkingTime|, overall there will |
| // be |estimated_live_bytes| live bytes to mark, and that marking speed is |
| // constant, after |elapsed_time| the number of marked_bytes should be |
| // |estimated_live_bytes| * (|elapsed_time| / |kEstimatedMarkingTime|), |
| // denoted as |expected_marked_bytes|. If |actual_marked_bytes| is less, |
| // i.e. marking is behind schedule, incremental marking should help "catch |
| // up" by marking (|expected_marked_bytes| - |actual_marked_bytes|). |
| return std::max(kMinimumMarkedBytesPerIncrementalStep, |
| expected_marked_bytes - actual_marked_bytes); |
| } |
| |
| constexpr double |
| IncrementalMarkingSchedule::kEphemeronPairsFlushingRatioIncrements; |
| bool IncrementalMarkingSchedule::ShouldFlushEphemeronPairs() { |
| DCHECK_NE(kInvalidLastEstimatedLiveBytes, last_estimated_live_bytes_); |
| if (GetOverallMarkedBytes() < |
| (ephemeron_pairs_flushing_ratio_target * last_estimated_live_bytes_)) |
| return false; |
| ephemeron_pairs_flushing_ratio_target += |
| kEphemeronPairsFlushingRatioIncrements; |
| return true; |
| } |
| |
| } // namespace internal |
| } // namespace cppgc |