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 3732 : void ScavengeJob::IdleTask::RunInternal(double deadline_in_seconds) {
23 : VMState<GC> state(isolate());
24 7464 : TRACE_EVENT_CALL_STATS_SCOPED(isolate(), "v8", "V8.Task");
25 : Heap* heap = isolate()->heap();
26 : double deadline_in_ms =
27 : deadline_in_seconds *
28 3732 : static_cast<double>(base::Time::kMillisecondsPerSecond);
29 3732 : double start_ms = heap->MonotonicallyIncreasingTimeInMs();
30 3732 : double idle_time_in_ms = deadline_in_ms - start_ms;
31 : double scavenge_speed_in_bytes_per_ms =
32 3732 : heap->tracer()->ScavengeSpeedInBytesPerMillisecond();
33 3732 : size_t new_space_size = heap->new_space()->Size();
34 : size_t new_space_capacity = heap->new_space()->Capacity();
35 :
36 3732 : job_->NotifyIdleTask();
37 :
38 3732 : if (ReachedIdleAllocationLimit(scavenge_speed_in_bytes_per_ms, new_space_size,
39 : new_space_capacity)) {
40 1785 : if (EnoughIdleTimeForScavenge(
41 : idle_time_in_ms, scavenge_speed_in_bytes_per_ms, new_space_size)) {
42 1737 : heap->CollectGarbage(NEW_SPACE, GarbageCollectionReason::kIdleTask);
43 : } else {
44 : // Immediately request another idle task that can get larger idle time.
45 48 : job_->RescheduleIdleTask(heap);
46 : }
47 : }
48 3732 : }
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 3743 : 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 3743 : 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 3743 : 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 3743 : Max<double>(allocation_limit - kBytesAllocatedBeforeNextIdleTask,
70 : kMinAllocationLimit);
71 :
72 3743 : 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 1791 : if (scavenge_speed_in_bytes_per_ms == 0) {
79 : scavenge_speed_in_bytes_per_ms = kInitialScavengeSpeedInBytesPerMs;
80 : }
81 1791 : 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 48 : if (!idle_task_rescheduled_) {
89 24 : ScheduleIdleTask(heap);
90 24 : idle_task_rescheduled_ = true;
91 : }
92 0 : }
93 :
94 :
95 37805 : void ScavengeJob::ScheduleIdleTaskIfNeeded(Heap* heap, int bytes_allocated) {
96 37805 : bytes_allocated_since_the_last_task_ += bytes_allocated;
97 37805 : if (bytes_allocated_since_the_last_task_ >=
98 : static_cast<int>(kBytesAllocatedBeforeNextIdleTask)) {
99 37805 : ScheduleIdleTask(heap);
100 37805 : bytes_allocated_since_the_last_task_ = 0;
101 37805 : idle_task_rescheduled_ = false;
102 : }
103 37805 : }
104 :
105 :
106 37829 : void ScavengeJob::ScheduleIdleTask(Heap* heap) {
107 37829 : if (!idle_task_pending_ && !heap->IsTearingDown()) {
108 : v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(heap->isolate());
109 6188 : if (V8::GetCurrentPlatform()->IdleTasksEnabled(isolate)) {
110 3734 : idle_task_pending_ = true;
111 3734 : auto task = base::make_unique<IdleTask>(heap->isolate(), this);
112 11202 : V8::GetCurrentPlatform()->GetForegroundTaskRunner(isolate)->PostIdleTask(
113 7468 : std::move(task));
114 : }
115 : }
116 37829 : }
117 : } // namespace internal
118 122004 : } // namespace v8
|