Line data Source code
1 : // Copyright 2015 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 : #include "src/heap/scavenge-job.h"
6 :
7 : #include "src/base/platform/time.h"
8 : #include "src/heap/gc-tracer.h"
9 : #include "src/heap/heap-inl.h"
10 : #include "src/heap/heap.h"
11 : #include "src/heap/spaces.h"
12 : #include "src/isolate.h"
13 : #include "src/v8.h"
14 : #include "src/vm-state-inl.h"
15 :
16 : namespace v8 {
17 : namespace internal {
18 :
19 :
20 : const double ScavengeJob::kMaxAllocationLimitAsFractionOfNewSpace = 0.8;
21 :
22 2861 : void ScavengeJob::IdleTask::RunInternal(double deadline_in_seconds) {
23 : VMState<GC> state(isolate());
24 5722 : TRACE_EVENT_CALL_STATS_SCOPED(isolate(), "v8", "V8.Task");
25 : Heap* heap = isolate()->heap();
26 : double deadline_in_ms =
27 : deadline_in_seconds *
28 2861 : static_cast<double>(base::Time::kMillisecondsPerSecond);
29 2861 : double start_ms = heap->MonotonicallyIncreasingTimeInMs();
30 2861 : double idle_time_in_ms = deadline_in_ms - start_ms;
31 : double scavenge_speed_in_bytes_per_ms =
32 2861 : heap->tracer()->ScavengeSpeedInBytesPerMillisecond();
33 2861 : size_t new_space_size = heap->new_space()->Size();
34 : size_t new_space_capacity = heap->new_space()->Capacity();
35 :
36 2861 : job_->NotifyIdleTask();
37 :
38 2861 : if (ReachedIdleAllocationLimit(scavenge_speed_in_bytes_per_ms, new_space_size,
39 : new_space_capacity)) {
40 1393 : if (EnoughIdleTimeForScavenge(
41 : idle_time_in_ms, scavenge_speed_in_bytes_per_ms, new_space_size)) {
42 1341 : heap->CollectGarbage(NEW_SPACE, GarbageCollectionReason::kIdleTask);
43 : } else {
44 : // Immediately request another idle task that can get larger idle time.
45 52 : job_->RescheduleIdleTask(heap);
46 : }
47 : }
48 2861 : }
49 :
50 11 : bool ScavengeJob::ReachedIdleAllocationLimit(
51 : double scavenge_speed_in_bytes_per_ms, size_t new_space_size,
52 : size_t new_space_capacity) {
53 2872 : if (scavenge_speed_in_bytes_per_ms == 0) {
54 : scavenge_speed_in_bytes_per_ms = kInitialScavengeSpeedInBytesPerMs;
55 : }
56 :
57 : // Set the allocation limit to the number of bytes we can scavenge in an
58 : // average idle task.
59 2872 : double allocation_limit = kAverageIdleTimeMs * scavenge_speed_in_bytes_per_ms;
60 :
61 : // Keep the limit smaller than the new space capacity.
62 : allocation_limit =
63 2872 : Min<double>(allocation_limit,
64 : new_space_capacity * kMaxAllocationLimitAsFractionOfNewSpace);
65 : // Adjust the limit to take into account bytes that will be allocated until
66 : // the next check and keep the limit large enough to avoid scavenges in tiny
67 : // new space.
68 : allocation_limit =
69 2872 : Max<double>(allocation_limit - kBytesAllocatedBeforeNextIdleTask,
70 : kMinAllocationLimit);
71 :
72 2872 : return allocation_limit <= new_space_size;
73 : }
74 :
75 6 : bool ScavengeJob::EnoughIdleTimeForScavenge(
76 : double idle_time_in_ms, double scavenge_speed_in_bytes_per_ms,
77 : size_t new_space_size) {
78 1399 : if (scavenge_speed_in_bytes_per_ms == 0) {
79 : scavenge_speed_in_bytes_per_ms = kInitialScavengeSpeedInBytesPerMs;
80 : }
81 1399 : return new_space_size <= idle_time_in_ms * scavenge_speed_in_bytes_per_ms;
82 : }
83 :
84 :
85 0 : void ScavengeJob::RescheduleIdleTask(Heap* heap) {
86 : // Make sure that we don't reschedule more than one time.
87 : // Otherwise, we might spam the scheduler with idle tasks.
88 52 : if (!idle_task_rescheduled_) {
89 26 : ScheduleIdleTask(heap);
90 26 : idle_task_rescheduled_ = true;
91 : }
92 0 : }
93 :
94 :
95 23459 : void ScavengeJob::ScheduleIdleTaskIfNeeded(Heap* heap, int bytes_allocated) {
96 23459 : bytes_allocated_since_the_last_task_ += bytes_allocated;
97 23459 : if (bytes_allocated_since_the_last_task_ >=
98 : static_cast<int>(kBytesAllocatedBeforeNextIdleTask)) {
99 23459 : ScheduleIdleTask(heap);
100 23459 : bytes_allocated_since_the_last_task_ = 0;
101 23459 : idle_task_rescheduled_ = false;
102 : }
103 23459 : }
104 :
105 :
106 23485 : void ScavengeJob::ScheduleIdleTask(Heap* heap) {
107 23485 : if (!idle_task_pending_ && !heap->IsTearingDown()) {
108 : v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(heap->isolate());
109 4178 : if (V8::GetCurrentPlatform()->IdleTasksEnabled(isolate)) {
110 2863 : idle_task_pending_ = true;
111 2863 : auto task = base::make_unique<IdleTask>(heap->isolate(), this);
112 8589 : V8::GetCurrentPlatform()->GetForegroundTaskRunner(isolate)->PostIdleTask(
113 5726 : std::move(task));
114 : }
115 : }
116 23485 : }
117 : } // namespace internal
118 120216 : } // namespace v8
|