Home | History | Annotate | Download | only in heap
      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 void ScavengeJob::IdleTask::RunInternal(double deadline_in_seconds) {
     20   Heap* heap = isolate()->heap();
     21   double deadline_in_ms =
     22       deadline_in_seconds *
     23       static_cast<double>(base::Time::kMillisecondsPerSecond);
     24   double start_ms = heap->MonotonicallyIncreasingTimeInMs();
     25   double idle_time_in_ms = deadline_in_ms - start_ms;
     26   double scavenge_speed_in_bytes_per_ms =
     27       heap->tracer()->ScavengeSpeedInBytesPerMillisecond();
     28   size_t new_space_size = heap->new_space()->Size();
     29   size_t new_space_capacity = heap->new_space()->Capacity();
     30 
     31   job_->NotifyIdleTask();
     32 
     33   if (ReachedIdleAllocationLimit(scavenge_speed_in_bytes_per_ms, new_space_size,
     34                                  new_space_capacity)) {
     35     if (EnoughIdleTimeForScavenge(
     36             idle_time_in_ms, scavenge_speed_in_bytes_per_ms, new_space_size)) {
     37       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 }
     44 
     45 bool ScavengeJob::ReachedIdleAllocationLimit(
     46     double scavenge_speed_in_bytes_per_ms, size_t new_space_size,
     47     size_t new_space_capacity) {
     48   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   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                   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                   kMinAllocationLimit);
     66 
     67   return allocation_limit <= new_space_size;
     68 }
     69 
     70 bool ScavengeJob::EnoughIdleTimeForScavenge(
     71     double idle_time_in_ms, double scavenge_speed_in_bytes_per_ms,
     72     size_t new_space_size) {
     73   if (scavenge_speed_in_bytes_per_ms == 0) {
     74     scavenge_speed_in_bytes_per_ms = kInitialScavengeSpeedInBytesPerMs;
     75   }
     76   return new_space_size <= idle_time_in_ms * scavenge_speed_in_bytes_per_ms;
     77 }
     78 
     79 
     80 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   if (!idle_task_rescheduled_) {
     84     ScheduleIdleTask(heap);
     85     idle_task_rescheduled_ = true;
     86   }
     87 }
     88 
     89 
     90 void ScavengeJob::ScheduleIdleTaskIfNeeded(Heap* heap, int bytes_allocated) {
     91   bytes_allocated_since_the_last_task_ += bytes_allocated;
     92   if (bytes_allocated_since_the_last_task_ >=
     93       static_cast<int>(kBytesAllocatedBeforeNextIdleTask)) {
     94     ScheduleIdleTask(heap);
     95     bytes_allocated_since_the_last_task_ = 0;
     96     idle_task_rescheduled_ = false;
     97   }
     98 }
     99 
    100 
    101 void ScavengeJob::ScheduleIdleTask(Heap* heap) {
    102   if (!idle_task_pending_) {
    103     v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(heap->isolate());
    104     if (V8::GetCurrentPlatform()->IdleTasksEnabled(isolate)) {
    105       idle_task_pending_ = true;
    106       auto task = new IdleTask(heap->isolate(), this);
    107       V8::GetCurrentPlatform()->CallIdleOnForegroundThread(isolate, task);
    108     }
    109   }
    110 }
    111 }  // namespace internal
    112 }  // namespace v8
    113