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 <stdlib.h>
      6 
      7 #ifdef __linux__
      8 #include <errno.h>
      9 #include <fcntl.h>
     10 #include <sys/stat.h>
     11 #include <sys/types.h>
     12 #include <unistd.h>
     13 #endif
     14 
     15 #include <utility>
     16 
     17 #include "src/v8.h"
     18 
     19 #include "src/full-codegen/full-codegen.h"
     20 #include "src/global-handles.h"
     21 #include "test/cctest/cctest.h"
     22 #include "test/cctest/heap/heap-utils.h"
     23 
     24 using v8::IdleTask;
     25 using v8::Task;
     26 using v8::Isolate;
     27 
     28 namespace v8 {
     29 namespace internal {
     30 
     31 class MockPlatform : public v8::Platform {
     32  public:
     33   explicit MockPlatform(v8::Platform* platform)
     34       : platform_(platform), idle_task_(nullptr), delayed_task_(nullptr) {}
     35   virtual ~MockPlatform() {
     36     delete idle_task_;
     37     delete delayed_task_;
     38   }
     39 
     40   void CallOnBackgroundThread(Task* task,
     41                               ExpectedRuntime expected_runtime) override {
     42     platform_->CallOnBackgroundThread(task, expected_runtime);
     43   }
     44 
     45   void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override {
     46     platform_->CallOnForegroundThread(isolate, task);
     47   }
     48 
     49   void CallDelayedOnForegroundThread(v8::Isolate* isolate, Task* task,
     50                                      double delay_in_seconds) override {
     51     if (delayed_task_ != nullptr) {
     52       delete delayed_task_;
     53     }
     54     delayed_task_ = task;
     55   }
     56 
     57   double MonotonicallyIncreasingTime() override {
     58     return platform_->MonotonicallyIncreasingTime();
     59   }
     60 
     61   void CallIdleOnForegroundThread(v8::Isolate* isolate,
     62                                   IdleTask* task) override {
     63     CHECK(nullptr == idle_task_);
     64     idle_task_ = task;
     65   }
     66 
     67   bool IdleTasksEnabled(v8::Isolate* isolate) override { return true; }
     68 
     69   bool PendingIdleTask() { return idle_task_ != nullptr; }
     70 
     71   void PerformIdleTask(double idle_time_in_seconds) {
     72     IdleTask* task = idle_task_;
     73     idle_task_ = nullptr;
     74     task->Run(MonotonicallyIncreasingTime() + idle_time_in_seconds);
     75     delete task;
     76   }
     77 
     78   bool PendingDelayedTask() { return delayed_task_ != nullptr; }
     79 
     80   void PerformDelayedTask() {
     81     Task* task = delayed_task_;
     82     delayed_task_ = nullptr;
     83     task->Run();
     84     delete task;
     85   }
     86 
     87   uint64_t AddTraceEvent(char phase, const uint8_t* categoryEnabledFlag,
     88                          const char* name, const char* scope, uint64_t id,
     89                          uint64_t bind_id, int numArgs, const char** argNames,
     90                          const uint8_t* argTypes, const uint64_t* argValues,
     91                          unsigned int flags) override {
     92     return 0;
     93   }
     94 
     95   void UpdateTraceEventDuration(const uint8_t* categoryEnabledFlag,
     96                                 const char* name, uint64_t handle) override {}
     97 
     98   const uint8_t* GetCategoryGroupEnabled(const char* name) override {
     99     static uint8_t no = 0;
    100     return &no;
    101   }
    102 
    103   const char* GetCategoryGroupName(
    104       const uint8_t* categoryEnabledFlag) override {
    105     static const char* dummy = "dummy";
    106     return dummy;
    107   }
    108 
    109  private:
    110   v8::Platform* platform_;
    111   IdleTask* idle_task_;
    112   Task* delayed_task_;
    113 };
    114 
    115 
    116 TEST(IncrementalMarkingUsingIdleTasks) {
    117   if (!i::FLAG_incremental_marking) return;
    118   CcTest::InitializeVM();
    119   v8::Platform* old_platform = i::V8::GetCurrentPlatform();
    120   MockPlatform platform(old_platform);
    121   i::V8::SetPlatformForTesting(&platform);
    122   i::heap::SimulateFullSpace(CcTest::heap()->old_space());
    123   i::IncrementalMarking* marking = CcTest::heap()->incremental_marking();
    124   marking->Stop();
    125   marking->Start();
    126   CHECK(platform.PendingIdleTask());
    127   const double kLongIdleTimeInSeconds = 1;
    128   const double kShortIdleTimeInSeconds = 0.010;
    129   const int kShortStepCount = 10;
    130   for (int i = 0; i < kShortStepCount && platform.PendingIdleTask(); i++) {
    131     platform.PerformIdleTask(kShortIdleTimeInSeconds);
    132   }
    133   while (platform.PendingIdleTask()) {
    134     platform.PerformIdleTask(kLongIdleTimeInSeconds);
    135   }
    136   CHECK(marking->IsStopped());
    137   i::V8::SetPlatformForTesting(old_platform);
    138 }
    139 
    140 
    141 TEST(IncrementalMarkingUsingIdleTasksAfterGC) {
    142   if (!i::FLAG_incremental_marking) return;
    143   CcTest::InitializeVM();
    144   v8::Platform* old_platform = i::V8::GetCurrentPlatform();
    145   MockPlatform platform(old_platform);
    146   i::V8::SetPlatformForTesting(&platform);
    147   i::heap::SimulateFullSpace(CcTest::heap()->old_space());
    148   CcTest::heap()->CollectAllGarbage();
    149   i::IncrementalMarking* marking = CcTest::heap()->incremental_marking();
    150   marking->Stop();
    151   marking->Start();
    152   CHECK(platform.PendingIdleTask());
    153   const double kLongIdleTimeInSeconds = 1;
    154   const double kShortIdleTimeInSeconds = 0.010;
    155   const int kShortStepCount = 10;
    156   for (int i = 0; i < kShortStepCount && platform.PendingIdleTask(); i++) {
    157     platform.PerformIdleTask(kShortIdleTimeInSeconds);
    158   }
    159   while (platform.PendingIdleTask()) {
    160     platform.PerformIdleTask(kLongIdleTimeInSeconds);
    161   }
    162   CHECK(marking->IsStopped());
    163   i::V8::SetPlatformForTesting(old_platform);
    164 }
    165 
    166 
    167 TEST(IncrementalMarkingUsingDelayedTasks) {
    168   if (!i::FLAG_incremental_marking) return;
    169   CcTest::InitializeVM();
    170   v8::Platform* old_platform = i::V8::GetCurrentPlatform();
    171   MockPlatform platform(old_platform);
    172   i::V8::SetPlatformForTesting(&platform);
    173   i::heap::SimulateFullSpace(CcTest::heap()->old_space());
    174   i::IncrementalMarking* marking = CcTest::heap()->incremental_marking();
    175   marking->Stop();
    176   marking->Start();
    177   CHECK(platform.PendingIdleTask());
    178   // The delayed task should be a no-op if the idle task makes progress.
    179   const int kIgnoredDelayedTaskStepCount = 1000;
    180   for (int i = 0; i < kIgnoredDelayedTaskStepCount; i++) {
    181     // Dummy idle task progress.
    182     marking->incremental_marking_job()->NotifyIdleTaskProgress();
    183     CHECK(platform.PendingDelayedTask());
    184     platform.PerformDelayedTask();
    185   }
    186   // Once we stop notifying idle task progress, the delayed tasks
    187   // should finish marking.
    188   while (!marking->IsStopped() && platform.PendingDelayedTask()) {
    189     platform.PerformDelayedTask();
    190   }
    191   // There could be pending delayed task from memory reducer after GC finishes.
    192   CHECK(marking->IsStopped());
    193   i::V8::SetPlatformForTesting(old_platform);
    194 }
    195 
    196 }  // namespace internal
    197 }  // namespace v8
    198