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

Side by Side Diff: media/gpu/avda_codec_allocator_unittest.cc

Issue 2540593005: media: Fix a flaky AVDACodecAllocator test (Closed)
Patch Set: Delete Testinformation Created 4 years 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
« no previous file with comments | « media/gpu/avda_codec_allocator.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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 "media/gpu/avda_codec_allocator.h" 5 #include "media/gpu/avda_codec_allocator.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include <memory> 9 #include <memory>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/test/simple_test_tick_clock.h"
13 #include "base/time/tick_clock.h" 14 #include "base/time/tick_clock.h"
14 #include "testing/gmock/include/gmock/gmock.h" 15 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h" 16 #include "testing/gtest/include/gtest/gtest.h"
16 17
17 using testing::Invoke; 18 using testing::Invoke;
18 using testing::NiceMock; 19 using testing::NiceMock;
19 using testing::_; 20 using testing::_;
20 21
21 namespace media { 22 namespace media {
22 namespace { 23 namespace {
(...skipping 11 matching lines...) Expand all
34 if (about_to_wait_event) 35 if (about_to_wait_event)
35 about_to_wait_event->Signal(); 36 about_to_wait_event->Signal();
36 wait_event->Wait(); 37 wait_event->Wait();
37 } 38 }
38 39
39 void SignalImmediately(base::WaitableEvent* event) { 40 void SignalImmediately(base::WaitableEvent* event) {
40 event->Signal(); 41 event->Signal();
41 } 42 }
42 } 43 }
43 44
44 class MockTickClock : public base::TickClock {
45 public:
46 MockTickClock() {
47 // Don't start with the null time.
48 Advance(1000);
49 }
50 ~MockTickClock() override{};
51 base::TimeTicks NowTicks() override {
52 base::AutoLock auto_lock(lock_);
53 return now_;
54 }
55
56 // Handy utility.
57 void Advance(int msec) {
58 base::AutoLock auto_lock(lock_);
59 now_ += base::TimeDelta::FromMilliseconds(msec);
60 }
61
62 private:
63 base::Lock lock_;
64 base::TimeTicks now_;
65 };
66
67 class MockClient : public AVDACodecAllocatorClient { 45 class MockClient : public AVDACodecAllocatorClient {
68 public: 46 public:
69 MOCK_METHOD1(OnSurfaceAvailable, void(bool success)); 47 MOCK_METHOD1(OnSurfaceAvailable, void(bool success));
70 MOCK_METHOD0(OnSurfaceDestroyed, void()); 48 MOCK_METHOD0(OnSurfaceDestroyed, void());
71 49
72 // Gmock doesn't let us mock methods taking move-only types. 50 // Gmock doesn't let us mock methods taking move-only types.
73 MOCK_METHOD1(OnCodecConfiguredMock, void(VideoCodecBridge* media_codec)); 51 MOCK_METHOD1(OnCodecConfiguredMock, void(VideoCodecBridge* media_codec));
74 void OnCodecConfigured( 52 void OnCodecConfigured(
75 std::unique_ptr<VideoCodecBridge> media_codec) override { 53 std::unique_ptr<VideoCodecBridge> media_codec) override {
76 OnCodecConfiguredMock(media_codec.get()); 54 OnCodecConfiguredMock(media_codec.get());
77 } 55 }
78 }; 56 };
79 57
80 class AVDACodecAllocatorTest : public testing::Test { 58 class AVDACodecAllocatorTest : public testing::Test {
81 public: 59 public:
82 AVDACodecAllocatorTest() : allocator_thread_("AllocatorThread") {} 60 AVDACodecAllocatorTest()
61 : allocator_thread_("AllocatorThread"),
62 stop_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
63 base::WaitableEvent::InitialState::NOT_SIGNALED) {
64 // Don't start the clock at null.
65 tick_clock_.Advance(base::TimeDelta::FromSeconds(1));
66 }
67
83 ~AVDACodecAllocatorTest() override {} 68 ~AVDACodecAllocatorTest() override {}
84 69
85 protected: 70 protected:
86 void SetUp() override { 71 void SetUp() override {
87 // Start the main thread for the allocator. This would normally be the GPU 72 // Start the main thread for the allocator. This would normally be the GPU
88 // main thread. 73 // main thread.
89 ASSERT_TRUE(allocator_thread_.Start()); 74 ASSERT_TRUE(allocator_thread_.Start());
90 75
91 // AVDACodecAllocator likes to post tasks to the current thread. 76 // Create the first allocator on the allocator thread.
92
93 test_information_.reset(new AVDACodecAllocator::TestInformation());
94 test_information_->tick_clock_.reset(new MockTickClock());
95 test_information_->stop_event_.reset(new base::WaitableEvent(
96 base::WaitableEvent::ResetPolicy::AUTOMATIC,
97 base::WaitableEvent::InitialState::NOT_SIGNALED));
98
99 // Allocate the allocator on the appropriate thread.
100 allocator_ = PostAndWait( 77 allocator_ = PostAndWait(
101 FROM_HERE, base::Bind( 78 FROM_HERE, base::Bind(
102 [](AVDACodecAllocator::TestInformation* test_info) { 79 [](base::TickClock* clock, base::WaitableEvent* event) {
103 return new AVDACodecAllocator(test_info); 80 return new AVDACodecAllocator(clock, event);
104 }, 81 },
105 test_information_.get())); 82 &tick_clock_, &stop_event_));
106 allocator2_ = new AVDACodecAllocator(test_information_.get()); 83 allocator2_ = new AVDACodecAllocator();
107
108 // All threads should be stopped
109 ASSERT_FALSE(IsThreadRunning(TaskType::AUTO_CODEC));
110 ASSERT_FALSE(IsThreadRunning(TaskType::SW_CODEC));
111
112 // Register an AVDA instance to start the allocator's threads.
113 ASSERT_TRUE(StartThread(avda1_));
114
115 // Assert that at least the AUTO_CODEC thread is started. The other might
116 // not be.
117 ASSERT_TRUE(IsThreadRunning(TaskType::AUTO_CODEC));
118 ASSERT_EQ(TaskType::AUTO_CODEC, TaskTypeForAllocation());
119 } 84 }
120 85
121 void TearDown() override { 86 void TearDown() override {
122 // Don't leave any threads hung, or this will hang too. 87 // Don't leave any threads hung, or this will hang too.
123 // It would be nice if we could let a unique ptr handle this, but the 88 // It would be nice if we could let a unique ptr handle this, but the
124 // destructor is private. We also have to destroy it on the right thread. 89 // destructor is private. We also have to destroy it on the right thread.
125 PostAndWait(FROM_HERE, base::Bind( 90 PostAndWait(FROM_HERE, base::Bind(
126 [](AVDACodecAllocator* allocator) { 91 [](AVDACodecAllocator* allocator) {
127 delete allocator; 92 delete allocator;
128 return true; 93 return true;
(...skipping 21 matching lines...) Expand all
150 // stop has completed. It's async with respect to the allocator thread. 115 // stop has completed. It's async with respect to the allocator thread.
151 PostAndWait(FROM_HERE, base::Bind( 116 PostAndWait(FROM_HERE, base::Bind(
152 [](AVDACodecAllocator* allocator, 117 [](AVDACodecAllocator* allocator,
153 AVDACodecAllocatorClient* avda) { 118 AVDACodecAllocatorClient* avda) {
154 allocator->StopThread(avda); 119 allocator->StopThread(avda);
155 return true; 120 return true;
156 }, 121 },
157 allocator_, avda)); 122 allocator_, avda));
158 // Note that we don't do this on the allocator thread, since that's the 123 // Note that we don't do this on the allocator thread, since that's the
159 // thread that will signal it. 124 // thread that will signal it.
160 test_information_->stop_event_->Wait(); 125 stop_event_.Wait();
161 } 126 }
162 127
163 // Return the running state of |task_type|, doing the necessary thread hops. 128 // Return the running state of |task_type|, doing the necessary thread hops.
164 bool IsThreadRunning(TaskType task_type) { 129 bool IsThreadRunning(TaskType task_type) {
165 return PostAndWait( 130 return PostAndWait(
166 FROM_HERE, 131 FROM_HERE,
167 base::Bind( 132 base::Bind(
168 [](AVDACodecAllocator* allocator, TaskType task_type) { 133 [](AVDACodecAllocator* allocator, TaskType task_type) {
169 return allocator->GetThreadForTesting(task_type).IsRunning(); 134 return allocator->GetThreadForTesting(task_type).IsRunning();
170 }, 135 },
(...skipping 24 matching lines...) Expand all
195 ReturnType return_value = ReturnType(); 160 ReturnType return_value = ReturnType();
196 allocator_thread_.task_runner()->PostTask( 161 allocator_thread_.task_runner()->PostTask(
197 from_here, 162 from_here,
198 base::Bind(&RunAndSignalTask<ReturnType>, &event, &return_value, cb)); 163 base::Bind(&RunAndSignalTask<ReturnType>, &event, &return_value, cb));
199 event.Wait(); 164 event.Wait();
200 return return_value; 165 return return_value;
201 } 166 }
202 167
203 base::Thread allocator_thread_; 168 base::Thread allocator_thread_;
204 169
205 // Test info that we provide to the codec allocator. 170 // The test params for |allocator_|.
206 std::unique_ptr<AVDACodecAllocator::TestInformation> test_information_; 171 base::SimpleTestTickClock tick_clock_;
172 base::WaitableEvent stop_event_;
207 173
208 // Allocators that we own. The first is intialized to be used on the allocator 174 // Allocators that we own. The first is intialized to be used on the allocator
209 // thread and the second one is initialized on the test thread. Each test 175 // thread and the second one is initialized on the test thread. Each test
210 // should only be using one of the two. They are not unique_ptrs because the 176 // should only be using one of the two. They are not unique_ptrs because the
211 // destructor is private and they need to be destructed on the right thread. 177 // destructor is private and they need to be destructed on the right thread.
212 AVDACodecAllocator* allocator_ = nullptr; 178 AVDACodecAllocator* allocator_ = nullptr;
213 AVDACodecAllocator* allocator2_ = nullptr; 179 AVDACodecAllocator* allocator2_ = nullptr;
214 180
215 NiceMock<MockClient> client1_, client2_, client3_; 181 NiceMock<MockClient> client1_, client2_, client3_;
216 NiceMock<MockClient>* avda1_ = &client1_; 182 NiceMock<MockClient>* avda1_ = &client1_;
217 NiceMock<MockClient>* avda2_ = &client2_; 183 NiceMock<MockClient>* avda2_ = &client2_;
218 NiceMock<MockClient>* avda3_ = &client3_; 184 NiceMock<MockClient>* avda3_ = &client3_;
219 }; 185 };
220 186
221 TEST_F(AVDACodecAllocatorTest, TestMultiInstance) { 187 TEST_F(AVDACodecAllocatorTest, ThreadsStartWhenClientsStart) {
222 // Add an avda instance. This one must succeed immediately, since the last 188 ASSERT_FALSE(IsThreadRunning(TaskType::AUTO_CODEC));
223 // one is still running. 189 ASSERT_FALSE(IsThreadRunning(TaskType::SW_CODEC));
224 ASSERT_TRUE(StartThread(avda2_)); 190 ASSERT_TRUE(StartThread(avda1_));
191 // Assert that at least the AUTO_CODEC thread is started. The other might
192 // not be.
193 ASSERT_TRUE(IsThreadRunning(TaskType::AUTO_CODEC));
194 }
225 195
226 // Stop the original avda instance. 196 TEST_F(AVDACodecAllocatorTest, ThreadsStopAfterAllClientsStop) {
197 StartThread(avda1_);
198 StartThread(avda2_);
227 StopThread(avda1_); 199 StopThread(avda1_);
228
229 // Verify that the AUTO_CODEC thread is still running.
230 ASSERT_TRUE(IsThreadRunning(TaskType::AUTO_CODEC)); 200 ASSERT_TRUE(IsThreadRunning(TaskType::AUTO_CODEC));
231 ASSERT_EQ(TaskType::AUTO_CODEC, TaskTypeForAllocation());
232
233 // Remove the second instance and wait for it to stop. Remember that it
234 // stops after messages have been posted to the thread, so we don't know
235 // how long it will take.
236 StopThread(avda2_); 201 StopThread(avda2_);
237
238 // Verify that the threads have stopped.
239 ASSERT_FALSE(IsThreadRunning(TaskType::AUTO_CODEC)); 202 ASSERT_FALSE(IsThreadRunning(TaskType::AUTO_CODEC));
240 ASSERT_FALSE(IsThreadRunning(TaskType::SW_CODEC)); 203 ASSERT_FALSE(IsThreadRunning(TaskType::SW_CODEC));
liberato (no reviews please) 2016/11/30 06:47:30 i'm not sure why this thread must be stopped by no
watk 2016/11/30 20:48:42 Oh genius! I think you've got it.
241 } 204 }
242 205
243 TEST_F(AVDACodecAllocatorTest, TestHangThread) { 206 TEST_F(AVDACodecAllocatorTest, TestHangThread) {
207 StartThread(avda1_);
244 ASSERT_EQ(TaskType::AUTO_CODEC, TaskTypeForAllocation()); 208 ASSERT_EQ(TaskType::AUTO_CODEC, TaskTypeForAllocation());
245 209
246 // Hang the AUTO_CODEC thread. 210 // Hang the AUTO_CODEC thread.
247 base::WaitableEvent about_to_wait_event( 211 base::WaitableEvent about_to_wait_event(
248 base::WaitableEvent::ResetPolicy::MANUAL, 212 base::WaitableEvent::ResetPolicy::MANUAL,
249 base::WaitableEvent::InitialState::NOT_SIGNALED); 213 base::WaitableEvent::InitialState::NOT_SIGNALED);
250 base::WaitableEvent wait_event( 214 base::WaitableEvent wait_event(
251 base::WaitableEvent::ResetPolicy::MANUAL, 215 base::WaitableEvent::ResetPolicy::MANUAL,
252 base::WaitableEvent::InitialState::NOT_SIGNALED); 216 base::WaitableEvent::InitialState::NOT_SIGNALED);
253 TaskRunnerFor(TaskType::AUTO_CODEC) 217 TaskRunnerFor(TaskType::AUTO_CODEC)
254 ->PostTask(FROM_HERE, base::Bind(&WaitUntilRestarted, 218 ->PostTask(FROM_HERE, base::Bind(&WaitUntilRestarted,
255 &about_to_wait_event, &wait_event)); 219 &about_to_wait_event, &wait_event));
256 // Wait until the task starts, so that |allocator_| starts the hang timer. 220 // Wait until the task starts, so that |allocator_| starts the hang timer.
257 about_to_wait_event.Wait(); 221 about_to_wait_event.Wait();
258 222
259 // Verify that we've failed over after a long time has passed. 223 // Verify that we've failed over after a long time has passed.
260 static_cast<MockTickClock*>(test_information_->tick_clock_.get()) 224 tick_clock_.Advance(base::TimeDelta::FromSeconds(1));
261 ->Advance(1000);
262 // Note that this should return the SW codec task type even if that thread 225 // Note that this should return the SW codec task type even if that thread
263 // failed to start. TaskRunnerFor() will return the current thread in that 226 // failed to start. TaskRunnerFor() will return the current thread in that
264 // case too. 227 // case too.
265 ASSERT_EQ(TaskType::SW_CODEC, TaskTypeForAllocation()); 228 ASSERT_EQ(TaskType::SW_CODEC, TaskTypeForAllocation());
266 229
267 // Un-hang the thread and wait for it to let another task run. This will 230 // Un-hang the thread and wait for it to let another task run. This will
268 // notify |allocator_| that the thread is no longer hung. 231 // notify |allocator_| that the thread is no longer hung.
269 base::WaitableEvent done_waiting_event( 232 base::WaitableEvent done_waiting_event(
270 base::WaitableEvent::ResetPolicy::MANUAL, 233 base::WaitableEvent::ResetPolicy::MANUAL,
271 base::WaitableEvent::InitialState::NOT_SIGNALED); 234 base::WaitableEvent::InitialState::NOT_SIGNALED);
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 303
341 TEST_F(AVDACodecAllocatorTest, DeallocatingIsSafeDuringSurfaceDestroyed) { 304 TEST_F(AVDACodecAllocatorTest, DeallocatingIsSafeDuringSurfaceDestroyed) {
342 allocator2_->AllocateSurface(avda1_, 1); 305 allocator2_->AllocateSurface(avda1_, 1);
343 EXPECT_CALL(*avda1_, OnSurfaceDestroyed()).WillOnce(Invoke([=]() { 306 EXPECT_CALL(*avda1_, OnSurfaceDestroyed()).WillOnce(Invoke([=]() {
344 allocator2_->DeallocateSurface(avda1_, 1); 307 allocator2_->DeallocateSurface(avda1_, 1);
345 })); 308 }));
346 allocator2_->OnSurfaceDestroyed(1); 309 allocator2_->OnSurfaceDestroyed(1);
347 } 310 }
348 311
349 } // namespace media 312 } // namespace media
OLDNEW
« no previous file with comments | « media/gpu/avda_codec_allocator.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698