v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
incremental-marking-schedule.h
Go to the documentation of this file.
1// Copyright 2020 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_HEAP_BASE_INCREMENTAL_MARKING_SCHEDULE_H_
6#define V8_HEAP_BASE_INCREMENTAL_MARKING_SCHEDULE_H_
7
8#include <atomic>
9#include <memory>
10#include <optional>
11
13
14namespace heap::base {
15
16// Incremental marking schedule that assumes a fixed time window for scheduling
17// incremental marking steps.
18//
19// Usage:
20// 1. NotifyIncrementalMarkingStart()
21// 2. Any combination of:
22// -> UpdateMutatorThreadMarkedBytes(mutator_marked_bytes)
23// -> AddConcurrentlyMarkedBytes(concurrently_marked_bytes_delta)
24// -> MarkSynchronously(GetNextIncrementalStepDuration(estimated_live_size))
26 public:
27 struct StepInfo final {
28 size_t mutator_marked_bytes = 0;
29 size_t concurrent_marked_bytes = 0;
30 size_t estimated_live_bytes = 0;
31 size_t expected_marked_bytes = 0;
33
34 size_t marked_bytes() const {
35 return mutator_marked_bytes + concurrent_marked_bytes;
36 }
37 // Returns the schedule delta in bytes. Positive and negative delta values
38 // indicate that the marked bytes are ahead and behind the expected
39 // schedule, respectively.
40 int64_t scheduled_delta_bytes() const {
41 return static_cast<int64_t>(marked_bytes()) - expected_marked_bytes;
42 }
43
44 // Returns whether the schedule is behind the expectation.
45 bool is_behind_expectation() const { return scheduled_delta_bytes() < 0; }
46 };
47
48 // Estimated walltime duration of incremental marking per GC cycle. This value
49 // determines how the mutator thread will try to catch up on incremental
50 // marking steps.
51 static constexpr v8::base::TimeDelta kEstimatedMarkingTime =
53
54 // Step size used when no progress is being made. This step size should allow
55 // for finalizing marking.
56 static constexpr size_t kStepSizeWhenNotMakingProgress = 64 * 1024;
57
58 static std::unique_ptr<IncrementalMarkingSchedule> Create(
59 bool predictable_schedule = false);
60 static std::unique_ptr<IncrementalMarkingSchedule>
61 CreateWithMarkedBytesPerStepForTesting(size_t min_marked_bytes_per_step,
62 bool predictable_schedule = false);
63
66 delete;
67
68 // Notifies the schedule that incremental marking has been started. Can be
69 // called multiple times and is a nop after the first notification.
70 void NotifyIncrementalMarkingStart();
71
72 // Notifies the schedule that concurrent marking has been started. Can be
73 // called multiple times and is a nop after the first notification.
74 void NotifyConcurrentMarkingStart();
75
76 // Adds or removes bytes marked on the mutator thread. Must be called from the
77 // thread owning the schedule. The schedule supports marked bytes being
78 // adjusted downwards, i.e., going backwards in the schedule.
79 void AddMutatorThreadMarkedBytes(size_t);
80
81 // Adds concurrently marked bytes. May be called from any thread. Not required
82 // to be complete, i.e., it is okay to not report bytes already marked for the
83 // schedule.
84 void AddConcurrentlyMarkedBytes(size_t);
85
86 // Computes the next step duration based on reported marked bytes and the
87 // current `estimated_live_bytes`.
88 size_t GetNextIncrementalStepDuration(size_t estimated_live_bytes);
89
90 // Returns the step info for the current step. This function is most useful
91 // after calling `GetNextIncrementalStepDuration()` to report scheduling
92 // details.
93 StepInfo GetCurrentStepInfo() const;
94
95 // Returns whether locally cached ephemerons should be flushed and made
96 // available globally. Will only return true once every
97 // `kEphemeronPairsFlushingRatioIncrements` percent of overall marked bytes.
98 bool ShouldFlushEphemeronPairs();
99
100 // Returns the time span since concurrent marking has added marked bytes via
101 // `AddConcurrentlyMarkedBytes()`. Note that instead of updating the time on
102 // adding bytes we only update time in
103 // `GetTimeSinceLastConcurrentMarkingUpdate()`.
104 v8::base::TimeDelta GetTimeSinceLastConcurrentMarkingUpdate();
105
106 // The minimum marked bytes per step. This is a lower bound for all the step
107 // sizes returned from `GetNextIncrementalStepDuration()`.
109 return min_marked_bytes_per_step_;
110 }
111
112 // Sets the elapsed time for testing purposes. Is reset after calling
113 // `GetNextIncrementalStepDuration()`.
114 void SetElapsedTimeForTesting(v8::base::TimeDelta);
115
116 private:
117 static constexpr double kEphemeronPairsFlushingRatioIncrements = 0.25;
118
119 IncrementalMarkingSchedule(size_t min_marked_bytes_per_step,
120 bool predictable_schedule);
121
122 v8::base::TimeDelta GetElapsedTimeSinceMarkingStart();
123
124 // Returns the reported overall marked bytes including those marked by the
125 // mutator and concurrently.
126 size_t GetOverallMarkedBytes() const;
127
128 // Returns the reported concurrently marked bytes. Only as accurate as
129 // `AddConcurrentlyMarkedBytes()` is.
130 size_t GetConcurrentlyMarkedBytes() const;
131
133 size_t mutator_thread_marked_bytes_ = 0;
134 std::atomic_size_t concurrently_marked_bytes_{0};
135 size_t last_estimated_live_bytes_ = 0;
136 double ephemeron_pairs_flushing_ratio_target_ = 0.25;
139 const bool predictable_schedule_ = false;
140 std::optional<v8::base::TimeDelta> elapsed_time_override_;
141 size_t last_concurrently_marked_bytes_ = 0;
143};
144
145} // namespace heap::base
146
147#endif // V8_HEAP_BASE_INCREMENTAL_MARKING_SCHEDULE_H_
std::optional< v8::base::TimeDelta > elapsed_time_override_
IncrementalMarkingSchedule & operator=(const IncrementalMarkingSchedule &)=delete
IncrementalMarkingSchedule(const IncrementalMarkingSchedule &)=delete
static constexpr TimeDelta FromMilliseconds(int64_t milliseconds)
Definition time.h:84
#define V8_EXPORT_PRIVATE
Definition macros.h:460