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