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