V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
scavenge-job.cc
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 void ScavengeJob::IdleTask::RunInternal(double deadline_in_seconds) {
23  VMState<GC> state(isolate());
24  TRACE_EVENT_CALL_STATS_SCOPED(isolate(), "v8", "V8.Task");
25  Heap* heap = isolate()->heap();
26  double deadline_in_ms =
27  deadline_in_seconds *
28  static_cast<double>(base::Time::kMillisecondsPerSecond);
29  double start_ms = heap->MonotonicallyIncreasingTimeInMs();
30  double idle_time_in_ms = deadline_in_ms - start_ms;
31  double scavenge_speed_in_bytes_per_ms =
32  heap->tracer()->ScavengeSpeedInBytesPerMillisecond();
33  size_t new_space_size = heap->new_space()->Size();
34  size_t new_space_capacity = heap->new_space()->Capacity();
35 
36  job_->NotifyIdleTask();
37 
38  if (ReachedIdleAllocationLimit(scavenge_speed_in_bytes_per_ms, new_space_size,
39  new_space_capacity)) {
40  if (EnoughIdleTimeForScavenge(
41  idle_time_in_ms, scavenge_speed_in_bytes_per_ms, new_space_size)) {
42  heap->CollectGarbage(NEW_SPACE, GarbageCollectionReason::kIdleTask);
43  } else {
44  // Immediately request another idle task that can get larger idle time.
45  job_->RescheduleIdleTask(heap);
46  }
47  }
48 }
49 
50 bool ScavengeJob::ReachedIdleAllocationLimit(
51  double scavenge_speed_in_bytes_per_ms, size_t new_space_size,
52  size_t new_space_capacity) {
53  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  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  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  Max<double>(allocation_limit - kBytesAllocatedBeforeNextIdleTask,
70  kMinAllocationLimit);
71 
72  return allocation_limit <= new_space_size;
73 }
74 
75 bool ScavengeJob::EnoughIdleTimeForScavenge(
76  double idle_time_in_ms, double scavenge_speed_in_bytes_per_ms,
77  size_t new_space_size) {
78  if (scavenge_speed_in_bytes_per_ms == 0) {
79  scavenge_speed_in_bytes_per_ms = kInitialScavengeSpeedInBytesPerMs;
80  }
81  return new_space_size <= idle_time_in_ms * scavenge_speed_in_bytes_per_ms;
82 }
83 
84 
85 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  if (!idle_task_rescheduled_) {
89  ScheduleIdleTask(heap);
90  idle_task_rescheduled_ = true;
91  }
92 }
93 
94 
95 void ScavengeJob::ScheduleIdleTaskIfNeeded(Heap* heap, int bytes_allocated) {
96  bytes_allocated_since_the_last_task_ += bytes_allocated;
97  if (bytes_allocated_since_the_last_task_ >=
98  static_cast<int>(kBytesAllocatedBeforeNextIdleTask)) {
99  ScheduleIdleTask(heap);
100  bytes_allocated_since_the_last_task_ = 0;
101  idle_task_rescheduled_ = false;
102  }
103 }
104 
105 
106 void ScavengeJob::ScheduleIdleTask(Heap* heap) {
107  if (!idle_task_pending_ && !heap->IsTearingDown()) {
108  v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(heap->isolate());
109  if (V8::GetCurrentPlatform()->IdleTasksEnabled(isolate)) {
110  idle_task_pending_ = true;
111  auto task = base::make_unique<IdleTask>(heap->isolate(), this);
112  V8::GetCurrentPlatform()->GetForegroundTaskRunner(isolate)->PostIdleTask(
113  std::move(task));
114  }
115  }
116 }
117 } // namespace internal
118 } // namespace v8
Definition: libplatform.h:13