11cb0ef41Sopenharmony_ci// Copyright 2020 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "src/heap/cppgc/incremental-marking-schedule.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include <cmath>
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ci#include "src/heap/cppgc/globals.h"
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_cinamespace cppgc {
121cb0ef41Sopenharmony_cinamespace internal {
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_ci// static
151cb0ef41Sopenharmony_ciconstexpr size_t IncrementalMarkingSchedule::kInvalidLastEstimatedLiveBytes;
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_ciconst double IncrementalMarkingSchedule::kEstimatedMarkingTimeMs = 500.0;
181cb0ef41Sopenharmony_ciconst size_t IncrementalMarkingSchedule::kMinimumMarkedBytesPerIncrementalStep =
191cb0ef41Sopenharmony_ci    64 * kKB;
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_civoid IncrementalMarkingSchedule::NotifyIncrementalMarkingStart() {
221cb0ef41Sopenharmony_ci  DCHECK(incremental_marking_start_time_.IsNull());
231cb0ef41Sopenharmony_ci  incremental_marking_start_time_ = v8::base::TimeTicks::Now();
241cb0ef41Sopenharmony_ci}
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_civoid IncrementalMarkingSchedule::UpdateMutatorThreadMarkedBytes(
271cb0ef41Sopenharmony_ci    size_t overall_marked_bytes) {
281cb0ef41Sopenharmony_ci  mutator_thread_marked_bytes_ = overall_marked_bytes;
291cb0ef41Sopenharmony_ci}
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_civoid IncrementalMarkingSchedule::AddConcurrentlyMarkedBytes(
321cb0ef41Sopenharmony_ci    size_t marked_bytes) {
331cb0ef41Sopenharmony_ci  concurrently_marked_bytes_.fetch_add(marked_bytes, std::memory_order_relaxed);
341cb0ef41Sopenharmony_ci}
351cb0ef41Sopenharmony_ci
361cb0ef41Sopenharmony_cisize_t IncrementalMarkingSchedule::GetOverallMarkedBytes() const {
371cb0ef41Sopenharmony_ci  return mutator_thread_marked_bytes_ + GetConcurrentlyMarkedBytes();
381cb0ef41Sopenharmony_ci}
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_cisize_t IncrementalMarkingSchedule::GetConcurrentlyMarkedBytes() const {
411cb0ef41Sopenharmony_ci  return concurrently_marked_bytes_.load(std::memory_order_relaxed);
421cb0ef41Sopenharmony_ci}
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_cidouble IncrementalMarkingSchedule::GetElapsedTimeInMs(
451cb0ef41Sopenharmony_ci    v8::base::TimeTicks start_time) {
461cb0ef41Sopenharmony_ci  if (elapsed_time_for_testing_ != kNoSetElapsedTimeForTesting) {
471cb0ef41Sopenharmony_ci    double elapsed_time = elapsed_time_for_testing_;
481cb0ef41Sopenharmony_ci    elapsed_time_for_testing_ = kNoSetElapsedTimeForTesting;
491cb0ef41Sopenharmony_ci    return elapsed_time;
501cb0ef41Sopenharmony_ci  }
511cb0ef41Sopenharmony_ci  return (v8::base::TimeTicks::Now() - start_time).InMillisecondsF();
521cb0ef41Sopenharmony_ci}
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_cisize_t IncrementalMarkingSchedule::GetNextIncrementalStepDuration(
551cb0ef41Sopenharmony_ci    size_t estimated_live_bytes) {
561cb0ef41Sopenharmony_ci  last_estimated_live_bytes_ = estimated_live_bytes;
571cb0ef41Sopenharmony_ci  DCHECK(!incremental_marking_start_time_.IsNull());
581cb0ef41Sopenharmony_ci  double elapsed_time_in_ms =
591cb0ef41Sopenharmony_ci      GetElapsedTimeInMs(incremental_marking_start_time_);
601cb0ef41Sopenharmony_ci  size_t actual_marked_bytes = GetOverallMarkedBytes();
611cb0ef41Sopenharmony_ci  size_t expected_marked_bytes = std::ceil(
621cb0ef41Sopenharmony_ci      estimated_live_bytes * elapsed_time_in_ms / kEstimatedMarkingTimeMs);
631cb0ef41Sopenharmony_ci  if (expected_marked_bytes < actual_marked_bytes) {
641cb0ef41Sopenharmony_ci    // Marking is ahead of schedule, incremental marking should do the minimum.
651cb0ef41Sopenharmony_ci    return kMinimumMarkedBytesPerIncrementalStep;
661cb0ef41Sopenharmony_ci  }
671cb0ef41Sopenharmony_ci  // Assuming marking will take |kEstimatedMarkingTime|, overall there will
681cb0ef41Sopenharmony_ci  // be |estimated_live_bytes| live bytes to mark, and that marking speed is
691cb0ef41Sopenharmony_ci  // constant, after |elapsed_time| the number of marked_bytes should be
701cb0ef41Sopenharmony_ci  // |estimated_live_bytes| * (|elapsed_time| / |kEstimatedMarkingTime|),
711cb0ef41Sopenharmony_ci  // denoted as |expected_marked_bytes|.  If |actual_marked_bytes| is less,
721cb0ef41Sopenharmony_ci  // i.e. marking is behind schedule, incremental marking should help "catch
731cb0ef41Sopenharmony_ci  // up" by marking (|expected_marked_bytes| - |actual_marked_bytes|).
741cb0ef41Sopenharmony_ci  return std::max(kMinimumMarkedBytesPerIncrementalStep,
751cb0ef41Sopenharmony_ci                  expected_marked_bytes - actual_marked_bytes);
761cb0ef41Sopenharmony_ci}
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ciconstexpr double
791cb0ef41Sopenharmony_ci    IncrementalMarkingSchedule::kEphemeronPairsFlushingRatioIncrements;
801cb0ef41Sopenharmony_cibool IncrementalMarkingSchedule::ShouldFlushEphemeronPairs() {
811cb0ef41Sopenharmony_ci  DCHECK_NE(kInvalidLastEstimatedLiveBytes, last_estimated_live_bytes_);
821cb0ef41Sopenharmony_ci  if (GetOverallMarkedBytes() <
831cb0ef41Sopenharmony_ci      (ephemeron_pairs_flushing_ratio_target * last_estimated_live_bytes_))
841cb0ef41Sopenharmony_ci    return false;
851cb0ef41Sopenharmony_ci  ephemeron_pairs_flushing_ratio_target +=
861cb0ef41Sopenharmony_ci      kEphemeronPairsFlushingRatioIncrements;
871cb0ef41Sopenharmony_ci  return true;
881cb0ef41Sopenharmony_ci}
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci}  // namespace internal
911cb0ef41Sopenharmony_ci}  // namespace cppgc
92