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:
MockPlatform(v8::Platform * platform)33 explicit MockPlatform(v8::Platform* platform)
34 : platform_(platform), idle_task_(nullptr), delayed_task_(nullptr) {}
~MockPlatform()35 virtual ~MockPlatform() {
36 delete idle_task_;
37 delete delayed_task_;
38 }
39
CallOnBackgroundThread(Task * task,ExpectedRuntime expected_runtime)40 void CallOnBackgroundThread(Task* task,
41 ExpectedRuntime expected_runtime) override {
42 platform_->CallOnBackgroundThread(task, expected_runtime);
43 }
44
CallOnForegroundThread(v8::Isolate * isolate,Task * task)45 void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override {
46 platform_->CallOnForegroundThread(isolate, task);
47 }
48
CallDelayedOnForegroundThread(v8::Isolate * isolate,Task * task,double delay_in_seconds)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
MonotonicallyIncreasingTime()57 double MonotonicallyIncreasingTime() override {
58 return platform_->MonotonicallyIncreasingTime();
59 }
60
CallIdleOnForegroundThread(v8::Isolate * isolate,IdleTask * task)61 void CallIdleOnForegroundThread(v8::Isolate* isolate,
62 IdleTask* task) override {
63 CHECK(nullptr == idle_task_);
64 idle_task_ = task;
65 }
66
IdleTasksEnabled(v8::Isolate * isolate)67 bool IdleTasksEnabled(v8::Isolate* isolate) override { return true; }
68
PendingIdleTask()69 bool PendingIdleTask() { return idle_task_ != nullptr; }
70
PerformIdleTask(double idle_time_in_seconds)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
PendingDelayedTask()78 bool PendingDelayedTask() { return delayed_task_ != nullptr; }
79
PerformDelayedTask()80 void PerformDelayedTask() {
81 Task* task = delayed_task_;
82 delayed_task_ = nullptr;
83 task->Run();
84 delete task;
85 }
86
AddTraceEvent(char phase,const uint8_t * categoryEnabledFlag,const char * name,const char * scope,uint64_t id,uint64_t bind_id,int numArgs,const char ** argNames,const uint8_t * argTypes,const uint64_t * argValues,unsigned int flags)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
UpdateTraceEventDuration(const uint8_t * categoryEnabledFlag,const char * name,uint64_t handle)95 void UpdateTraceEventDuration(const uint8_t* categoryEnabledFlag,
96 const char* name, uint64_t handle) override {}
97
GetCategoryGroupEnabled(const char * name)98 const uint8_t* GetCategoryGroupEnabled(const char* name) override {
99 static uint8_t no = 0;
100 return &no;
101 }
102
GetCategoryGroupName(const uint8_t * categoryEnabledFlag)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
TEST(IncrementalMarkingUsingIdleTasks)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
TEST(IncrementalMarkingUsingIdleTasksAfterGC)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
TEST(IncrementalMarkingUsingDelayedTasks)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