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