OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "config.h" | 5 #include "config.h" |
6 #include "platform/Timer.h" | 6 #include "platform/Timer.h" |
7 | 7 |
8 #include "public/platform/Platform.h" | 8 #include "public/platform/Platform.h" |
9 #include "public/platform/WebScheduler.h" | 9 #include "public/platform/WebScheduler.h" |
10 #include "public/platform/WebThread.h" | 10 #include "public/platform/WebThread.h" |
11 #include <gmock/gmock.h> | 11 #include <gmock/gmock.h> |
12 #include <gtest/gtest.h> | 12 #include <gtest/gtest.h> |
13 #include <queue> | 13 #include <queue> |
14 | 14 |
15 using testing::ElementsAre; | 15 using testing::ElementsAre; |
16 | 16 |
17 namespace blink { | 17 namespace blink { |
18 namespace { | 18 namespace { |
19 double gCurrentTimeSecs = 0.0; | 19 double gCurrentTimeSecs = 0.0; |
20 | 20 |
21 double currentTime() | 21 double currentTime() |
22 { | 22 { |
23 return gCurrentTimeSecs; | 23 return gCurrentTimeSecs; |
24 } | 24 } |
25 | 25 |
| 26 // This class exists because gcc doesn't know how to move an OwnPtr. |
| 27 class RefCountedTaskContainer : public RefCounted<RefCountedTaskContainer> { |
| 28 public: |
| 29 explicit RefCountedTaskContainer(WebThread::Task* task) : m_task(adoptPtr(ta
sk)) { } |
| 30 |
| 31 ~RefCountedTaskContainer() { } |
| 32 |
| 33 void run() |
| 34 { |
| 35 m_task->run(); |
| 36 } |
| 37 |
| 38 private: |
| 39 OwnPtr<WebThread::Task> m_task; |
| 40 }; |
| 41 |
| 42 class DelayedTask { |
| 43 public: |
| 44 DelayedTask(WebThread::Task* task, long long delayMs) |
| 45 : m_task(adoptRef(new RefCountedTaskContainer(task))) |
| 46 , m_runTimeSecs(monotonicallyIncreasingTime() + 0.001 * static_cast<doub
le>(delayMs)) |
| 47 , m_delayMs(delayMs) { } |
| 48 |
| 49 bool operator<(const DelayedTask& other) const |
| 50 { |
| 51 return m_runTimeSecs > other.m_runTimeSecs; |
| 52 } |
| 53 |
| 54 void run() const |
| 55 { |
| 56 m_task->run(); |
| 57 } |
| 58 |
| 59 double runTimeSecs() const |
| 60 { |
| 61 return m_runTimeSecs; |
| 62 } |
| 63 |
| 64 long long delayMs() const |
| 65 { |
| 66 return m_delayMs; |
| 67 } |
| 68 |
| 69 private: |
| 70 RefPtr<RefCountedTaskContainer> m_task; |
| 71 double m_runTimeSecs; |
| 72 long long m_delayMs; |
| 73 }; |
| 74 |
26 class MockWebScheduler : public WebScheduler { | 75 class MockWebScheduler : public WebScheduler { |
27 public: | 76 public: |
28 explicit MockWebScheduler() { } | 77 MockWebScheduler() { } |
29 ~MockWebScheduler() override { } | 78 ~MockWebScheduler() override { } |
30 | 79 |
31 bool shouldYieldForHighPriorityWork() override | 80 bool shouldYieldForHighPriorityWork() override |
32 { | 81 { |
33 return false; | 82 return false; |
34 } | 83 } |
35 | 84 |
36 bool canExceedIdleDeadlineIfRequired() override | 85 bool canExceedIdleDeadlineIfRequired() override |
37 { | 86 { |
38 return false; | 87 return false; |
(...skipping 10 matching lines...) Expand all Loading... |
49 void postIdleTaskAfterWakeup(const WebTraceLocation&, WebThread::IdleTask*)
override | 98 void postIdleTaskAfterWakeup(const WebTraceLocation&, WebThread::IdleTask*)
override |
50 { | 99 { |
51 } | 100 } |
52 | 101 |
53 void postLoadingTask(const WebTraceLocation&, WebThread::Task*) override | 102 void postLoadingTask(const WebTraceLocation&, WebThread::Task*) override |
54 { | 103 { |
55 } | 104 } |
56 | 105 |
57 void postTimerTask(const WebTraceLocation&, WebThread::Task* task, long long
delayMs) override | 106 void postTimerTask(const WebTraceLocation&, WebThread::Task* task, long long
delayMs) override |
58 { | 107 { |
| 108 m_timerTasks.push(DelayedTask(task, delayMs)); |
59 } | 109 } |
| 110 |
| 111 void runUntilIdle() |
| 112 { |
| 113 while (!m_timerTasks.empty()) { |
| 114 gCurrentTimeSecs = m_timerTasks.top().runTimeSecs(); |
| 115 m_timerTasks.top().run(); |
| 116 m_timerTasks.pop(); |
| 117 } |
| 118 } |
| 119 |
| 120 void runUntilIdleOrDeadlinePassed(double deadline) |
| 121 { |
| 122 while (!m_timerTasks.empty()) { |
| 123 if (m_timerTasks.top().runTimeSecs() > deadline) { |
| 124 gCurrentTimeSecs = deadline; |
| 125 break; |
| 126 } |
| 127 gCurrentTimeSecs = m_timerTasks.top().runTimeSecs(); |
| 128 m_timerTasks.top().run(); |
| 129 m_timerTasks.pop(); |
| 130 } |
| 131 } |
| 132 |
| 133 bool hasOneTimerTask() const |
| 134 { |
| 135 return m_timerTasks.size() == 1; |
| 136 } |
| 137 |
| 138 long nextTimerTaskDelayMillis() const |
| 139 { |
| 140 ASSERT(hasOneTimerTask()); |
| 141 return m_timerTasks.top().delayMs(); |
| 142 } |
| 143 |
| 144 private: |
| 145 std::priority_queue<DelayedTask> m_timerTasks; |
60 }; | 146 }; |
61 | 147 |
62 class FakeWebThread : public WebThread { | 148 class FakeWebThread : public WebThread { |
63 public: | 149 public: |
64 explicit FakeWebThread(WebScheduler* webScheduler) : m_webScheduler(webSched
uler) { } | 150 FakeWebThread() : m_webScheduler(adoptPtr(new MockWebScheduler())) { } |
65 ~FakeWebThread() override { } | 151 ~FakeWebThread() override { } |
66 | 152 |
67 // WebThread implementation: | 153 // WebThread implementation: |
68 void postTask(const WebTraceLocation&, Task*) | 154 void postTask(const WebTraceLocation&, Task*) |
69 { | 155 { |
70 ASSERT_NOT_REACHED(); | 156 ASSERT_NOT_REACHED(); |
71 } | 157 } |
72 | 158 |
73 virtual void postDelayedTask(const WebTraceLocation&, Task*, long long) | 159 virtual void postDelayedTask(const WebTraceLocation&, Task*, long long) |
74 { | 160 { |
75 ASSERT_NOT_REACHED(); | 161 ASSERT_NOT_REACHED(); |
76 } | 162 } |
77 | 163 |
78 virtual bool isCurrentThread() const | 164 virtual bool isCurrentThread() const |
79 { | 165 { |
80 ASSERT_NOT_REACHED(); | 166 ASSERT_NOT_REACHED(); |
81 return true; | 167 return true; |
82 } | 168 } |
83 | 169 |
84 virtual PlatformThreadId threadId() const | 170 virtual PlatformThreadId threadId() const |
85 { | 171 { |
86 ASSERT_NOT_REACHED(); | 172 ASSERT_NOT_REACHED(); |
87 return 0; | 173 return 0; |
88 } | 174 } |
89 | 175 |
90 WebScheduler* scheduler() const override | 176 WebScheduler* scheduler() const override |
91 { | 177 { |
92 return m_webScheduler; | 178 return m_webScheduler.get(); |
93 } | 179 } |
94 | 180 |
95 virtual void enterRunLoop() | 181 virtual void enterRunLoop() |
96 { | 182 { |
97 ASSERT_NOT_REACHED(); | 183 ASSERT_NOT_REACHED(); |
98 } | 184 } |
99 | 185 |
100 virtual void exitRunLoop() | 186 virtual void exitRunLoop() |
101 { | 187 { |
102 ASSERT_NOT_REACHED(); | 188 ASSERT_NOT_REACHED(); |
103 } | 189 } |
104 | 190 |
105 private: | 191 private: |
106 WebScheduler* m_webScheduler; | 192 OwnPtr<MockWebScheduler> m_webScheduler; |
107 }; | 193 }; |
108 | 194 |
109 class TimerTestPlatform : public Platform { | 195 class TimerTestPlatform : public Platform { |
110 public: | 196 public: |
111 explicit TimerTestPlatform(WebThread* webThread) | 197 TimerTestPlatform() |
112 : m_webThread(webThread) | 198 : m_webThread(adoptPtr(new FakeWebThread())) { } |
113 , m_timerInterval(-1) { } | |
114 ~TimerTestPlatform() override { } | 199 ~TimerTestPlatform() override { } |
115 | 200 |
116 WebThread* currentThread() override | 201 WebThread* currentThread() override |
117 { | 202 { |
118 return m_webThread; | 203 return m_webThread.get(); |
119 } | 204 } |
120 | 205 |
121 void cryptographicallyRandomValues(unsigned char*, size_t) override | 206 void cryptographicallyRandomValues(unsigned char*, size_t) override |
122 { | 207 { |
123 ASSERT_NOT_REACHED(); | 208 ASSERT_NOT_REACHED(); |
124 } | 209 } |
125 | 210 |
126 const unsigned char* getTraceCategoryEnabledFlag(const char* categoryName) o
verride | 211 const unsigned char* getTraceCategoryEnabledFlag(const char* categoryName) o
verride |
127 { | 212 { |
128 static const unsigned char enabled[] = {0}; | 213 static const unsigned char enabled[] = {0}; |
129 return enabled; | 214 return enabled; |
130 } | 215 } |
131 | 216 |
132 void setSharedTimerFiredFunction(SharedTimerFunction timerFunction) override | |
133 { | |
134 s_timerFunction = timerFunction; | |
135 } | |
136 | |
137 void setSharedTimerFireInterval(double interval) override | |
138 { | |
139 m_timerInterval = interval; | |
140 } | |
141 | |
142 virtual void stopSharedTimer() override | |
143 { | |
144 m_timerInterval = -1; | |
145 } | |
146 | |
147 void runUntilIdle() | 217 void runUntilIdle() |
148 { | 218 { |
149 while (hasOneTimerTask()) { | 219 mockScheduler()->runUntilIdle(); |
150 gCurrentTimeSecs += m_timerInterval; | |
151 s_timerFunction(); | |
152 } | |
153 } | 220 } |
154 | 221 |
155 void runUntilIdleOrDeadlinePassed(double deadline) | 222 void runUntilIdleOrDeadlinePassed(double deadline) |
156 { | 223 { |
157 while (hasOneTimerTask()) { | 224 mockScheduler()->runUntilIdleOrDeadlinePassed(deadline); |
158 double newTime = gCurrentTimeSecs + m_timerInterval; | |
159 if (newTime >= deadline) { | |
160 gCurrentTimeSecs = deadline; | |
161 break; | |
162 } | |
163 gCurrentTimeSecs = newTime; | |
164 s_timerFunction(); | |
165 } | |
166 } | 225 } |
167 | 226 |
168 bool hasOneTimerTask() const | 227 bool hasOneTimerTask() const |
169 { | 228 { |
170 return s_timerFunction && m_timerInterval >= 0; | 229 return mockScheduler()->hasOneTimerTask(); |
171 } | 230 } |
172 | 231 |
173 long nextTimerTaskDelayMillis() const | 232 long nextTimerTaskDelayMillis() const |
174 { | 233 { |
175 ASSERT(hasOneTimerTask()); | 234 return mockScheduler()->nextTimerTaskDelayMillis(); |
176 return static_cast<long>(m_timerInterval * 1000); | |
177 } | 235 } |
178 | 236 |
179 private: | 237 private: |
180 WebThread* m_webThread; | 238 MockWebScheduler* mockScheduler() const |
181 double m_timerInterval; | 239 { |
| 240 return static_cast<MockWebScheduler*>(m_webThread->scheduler()); |
| 241 } |
182 | 242 |
183 // This needs to be static because the callback is registered only once by | 243 OwnPtr<FakeWebThread> m_webThread; |
184 // PlatformThreadData. | |
185 static SharedTimerFunction s_timerFunction; | |
186 }; | 244 }; |
187 | 245 |
188 Platform::SharedTimerFunction TimerTestPlatform::s_timerFunction; | |
189 | |
190 class TimerTest : public testing::Test { | 246 class TimerTest : public testing::Test { |
191 public: | 247 public: |
192 void SetUp() override | 248 void SetUp() override |
193 { | 249 { |
194 m_mockWebScheduler = adoptPtr(new MockWebScheduler()); | 250 m_platform = adoptPtr(new TimerTestPlatform()); |
195 m_fakeWebThread = adoptPtr(new FakeWebThread(m_mockWebScheduler.get())); | |
196 m_platform = adoptPtr(new TimerTestPlatform(m_fakeWebThread.get())); | |
197 m_oldPlatform = Platform::current(); | 251 m_oldPlatform = Platform::current(); |
198 Platform::initialize(m_platform.get()); | 252 Platform::initialize(m_platform.get()); |
199 WTF::setMonotonicallyIncreasingTimeFunction(currentTime); | 253 WTF::setMonotonicallyIncreasingTimeFunction(currentTime); |
200 | 254 |
201 m_runTimes.clear(); | 255 m_runTimes.clear(); |
202 gCurrentTimeSecs = 10.0; | 256 gCurrentTimeSecs = 10.0; |
203 m_startTime = gCurrentTimeSecs; | 257 m_startTime = gCurrentTimeSecs; |
204 } | 258 } |
205 | 259 |
206 void TearDown() override | 260 void TearDown() override |
(...skipping 29 matching lines...) Expand all Loading... |
236 long nextTimerTaskDelayMillis() const | 290 long nextTimerTaskDelayMillis() const |
237 { | 291 { |
238 return m_platform->nextTimerTaskDelayMillis(); | 292 return m_platform->nextTimerTaskDelayMillis(); |
239 } | 293 } |
240 | 294 |
241 protected: | 295 protected: |
242 double m_startTime; | 296 double m_startTime; |
243 std::vector<double> m_runTimes; | 297 std::vector<double> m_runTimes; |
244 | 298 |
245 private: | 299 private: |
246 OwnPtr<MockWebScheduler> m_mockWebScheduler; | |
247 OwnPtr<FakeWebThread> m_fakeWebThread; | |
248 OwnPtr<TimerTestPlatform> m_platform; | 300 OwnPtr<TimerTestPlatform> m_platform; |
249 Platform* m_oldPlatform; | 301 Platform* m_oldPlatform; |
250 }; | 302 }; |
251 | 303 |
252 TEST_F(TimerTest, StartOneShot_Zero) | 304 TEST_F(TimerTest, StartOneShot_Zero) |
253 { | 305 { |
254 Timer<TimerTest> timer(this, &TimerTest::countingTask); | 306 Timer<TimerTest> timer(this, &TimerTest::countingTask); |
255 timer.startOneShot(0, FROM_HERE); | 307 timer.startOneShot(0, FROM_HERE); |
256 | 308 |
257 ASSERT(hasOneTimerTask()); | 309 ASSERT(hasOneTimerTask()); |
(...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
665 MockTimerWithAlignment timer; | 717 MockTimerWithAlignment timer; |
666 timer.setAlignedFireTime(m_startTime + 1.0); | 718 timer.setAlignedFireTime(m_startTime + 1.0); |
667 | 719 |
668 timer.start(0.0, 0.0, FROM_HERE); | 720 timer.start(0.0, 0.0, FROM_HERE); |
669 | 721 |
670 EXPECT_FLOAT_EQ(1.0, timer.nextFireInterval()); | 722 EXPECT_FLOAT_EQ(1.0, timer.nextFireInterval()); |
671 EXPECT_FLOAT_EQ(0.0, timer.nextUnalignedFireInterval()); | 723 EXPECT_FLOAT_EQ(0.0, timer.nextUnalignedFireInterval()); |
672 EXPECT_FLOAT_EQ(m_startTime, timer.lastFireTime()); | 724 EXPECT_FLOAT_EQ(m_startTime, timer.lastFireTime()); |
673 | 725 |
674 timer.setAlignedFireTime(m_startTime); | 726 timer.setAlignedFireTime(m_startTime); |
675 timer.didChangeAlignmentInterval(); | 727 timer.didChangeAlignmentInterval(monotonicallyIncreasingTime()); |
676 | 728 |
677 EXPECT_FLOAT_EQ(0.0, timer.nextFireInterval()); | 729 EXPECT_FLOAT_EQ(0.0, timer.nextFireInterval()); |
678 EXPECT_FLOAT_EQ(0.0, timer.nextUnalignedFireInterval()); | 730 EXPECT_FLOAT_EQ(0.0, timer.nextUnalignedFireInterval()); |
679 EXPECT_FLOAT_EQ(m_startTime, timer.lastFireTime()); | 731 EXPECT_FLOAT_EQ(m_startTime, timer.lastFireTime()); |
680 } | 732 } |
681 | 733 |
682 | 734 |
683 } // namespace | 735 } // namespace |
684 } // namespace blink | 736 } // namespace blink |
OLD | NEW |