Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(408)

Side by Side Diff: Source/platform/TimerTest.cpp

Issue 1134523002: Implement timers by posting delayed tasks (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Rebased. Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/platform/Timer.cpp ('k') | Source/platform/blink_platform.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « Source/platform/Timer.cpp ('k') | Source/platform/blink_platform.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698