• 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/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