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

Side by Side Diff: media/blink/multibuffer_unittest.cc

Issue 1420883004: Multibuffer reader implementation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@media_cache
Patch Set: merged Created 5 years, 1 month 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
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include <deque>
6 #include <string>
7 #include <vector>
8
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/message_loop/message_loop.h"
12 #include "media/blink/multibuffer.h"
13 #include "media/blink/multibuffer_reader.h"
14 #include "media/blink/test_random.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 const int kBlockSizeShift = 8;
18 const size_t kBlockSize = 1UL << kBlockSizeShift;
19
20 namespace media {
21 class TestMultiBufferDataProvider;
22
23 std::vector<TestMultiBufferDataProvider*> writers;
24
25 class TestMultiBufferDataProvider : public media::MultiBuffer::DataProvider {
26 public:
27 TestMultiBufferDataProvider(MultiBufferBlockId pos,
28 size_t file_size,
29 int max_blocks_after_defer,
30 bool must_read_whole_file)
31 : pos_(pos),
32 blocks_until_deferred_(1 << 30),
33 max_blocks_after_defer_(max_blocks_after_defer),
34 file_size_(file_size),
35 must_read_whole_file_(must_read_whole_file) {
36 writers.push_back(this);
37 }
38
39 ~TestMultiBufferDataProvider() override {
40 if (must_read_whole_file_) {
41 CHECK_GE(pos_ * kBlockSize, file_size_);
42 }
43 for (size_t i = 0; i < writers.size(); i++) {
44 if (writers[i] == this) {
45 writers[i] = writers.back();
46 writers.pop_back();
47 return;
48 }
49 }
50 LOG(FATAL) << "Couldn't find myself in writers!";
51 }
52
53 MultiBufferBlockId Tell() const override { return pos_; }
54
55 bool Available() const override { return !fifo_.empty(); }
56
57 scoped_refptr<DataBuffer> Read() override {
58 DCHECK(Available());
59 scoped_refptr<DataBuffer> ret = fifo_.front();
60 fifo_.pop_front();
61 ++pos_;
62 return ret;
63 }
64
65 void SetAvailableCallback(const base::Closure& cb) override {
66 DCHECK(!Available());
67 cb_ = cb;
68 }
69
70 void SetDeferred(bool deferred) override {
71 if (deferred) {
72 if (max_blocks_after_defer_ > 0) {
73 blocks_until_deferred_ = rand() % max_blocks_after_defer_;
DaleCurtis 2015/11/17 06:56:06 rnd_.Rand() ?
hubbe 2015/11/17 23:40:17 Done.
74 } else if (max_blocks_after_defer_ < 0) {
75 blocks_until_deferred_ = -max_blocks_after_defer_;
76 } else {
77 blocks_until_deferred_ = 0;
78 }
79 } else {
80 blocks_until_deferred_ = 1 << 30;
81 }
82 }
83
84 bool Advance() {
85 if (blocks_until_deferred_ == 0)
86 return false;
87 --blocks_until_deferred_;
88
89 bool ret = true;
90 scoped_refptr<media::DataBuffer> block = new media::DataBuffer(kBlockSize);
91 size_t x = 0;
92 size_t byte_pos = (fifo_.size() + pos_) * kBlockSize;
93 for (x = 0; x < kBlockSize; x++, byte_pos++) {
94 if (byte_pos >= file_size_)
95 break;
96 block->writable_data()[x] =
97 static_cast<uint8_t>((byte_pos * 15485863) >> 16);
98 }
99 block->set_data_size(static_cast<int>(x));
100 fifo_.push_back(block);
101 if (byte_pos == file_size_) {
102 fifo_.push_back(DataBuffer::CreateEOSBuffer());
103 ret = false;
104 }
105 cb_.Run();
106 return ret;
107 }
108
109 private:
110 std::deque<scoped_refptr<media::DataBuffer>> fifo_;
111 MultiBufferBlockId pos_;
112 int32_t blocks_until_deferred_;
113 int32_t max_blocks_after_defer_;
114 size_t file_size_;
115 bool must_read_whole_file_;
116 base::Closure cb_;
117 };
118
119 class TestMultiBuffer : public media::MultiBuffer {
120 public:
121 explicit TestMultiBuffer(
122 int32_t shift,
123 const scoped_refptr<media::MultiBuffer::GlobalLRU>& lru)
124 : media::MultiBuffer(shift, lru),
125 range_supported_(false),
126 create_ok_(true),
127 max_writers_(10000),
128 file_size_(1 << 30),
129 max_blocks_after_defer_(0),
130 must_read_whole_file_(false),
131 writers_created_(0) {}
132
133 void SetMaxWriters(size_t max_writers) { max_writers_ = max_writers; }
134
135 void CheckPresentState() {
136 IntervalMap<MultiBufferBlockId, int32_t> tmp;
137 for (DataMap::iterator i = data_.begin(); i != data_.end(); ++i) {
138 CHECK(i->second); // Null poineters are not allowed in data_
139 CHECK_NE(!!pinned_[i->first], lru_->Contains(this, i->first))
140 << " i->first = " << i->first;
141 tmp.IncrementInterval(i->first, i->first + 1, 1);
142 }
143 IntervalMap<MultiBufferBlockId, int32_t>::const_iterator tmp_iterator =
144 tmp.begin();
145 IntervalMap<MultiBufferBlockId, int32_t>::const_iterator present_iterator =
146 present_.begin();
147 while (tmp_iterator != tmp.end() && present_iterator != tmp.end()) {
148 EXPECT_EQ(tmp_iterator.interval_begin(),
149 present_iterator.interval_begin());
150 EXPECT_EQ(tmp_iterator.interval_end(), present_iterator.interval_end());
151 EXPECT_EQ(tmp_iterator.value(), present_iterator.value());
152 ++tmp_iterator;
153 ++present_iterator;
154 }
155 EXPECT_TRUE(tmp_iterator == tmp.end());
156 EXPECT_TRUE(present_iterator == present_.end());
157 }
158
159 void CheckLRUState() {
160 for (DataMap::iterator i = data_.begin(); i != data_.end(); ++i) {
161 CHECK(i->second); // Null poineters are not allowed in data_
162 CHECK_NE(!!pinned_[i->first], lru_->Contains(this, i->first))
163 << " i->first = " << i->first;
164 CHECK_EQ(1, present_[i->first]) << " i->first = " << i->first;
165 }
166 }
167
168 void SetFileSize(size_t file_size) { file_size_ = file_size; }
169
170 void SetMaxBlocksAfterDefer(int32_t max_blocks_after_defer) {
171 max_blocks_after_defer_ = max_blocks_after_defer;
172 }
173
174 void SetMustReadWholeFile(bool must_read_whole_file) {
175 must_read_whole_file_ = must_read_whole_file;
176 }
177
178 int32_t writers_created() const { return writers_created_; }
179
180 void SetRangeSupported(bool supported) { range_supported_ = supported; }
181
182 protected:
183 DataProvider* CreateWriter(const MultiBufferBlockId& pos) override {
184 DCHECK(create_ok_);
185 writers_created_++;
186 CHECK_LT(writers.size(), max_writers_);
187 return new TestMultiBufferDataProvider(
188 pos, file_size_, max_blocks_after_defer_, must_read_whole_file_);
189 }
190 void Prune(size_t max_to_free) override {
191 // Prune should not cause additional writers to be spawned.
192 create_ok_ = false;
193 MultiBuffer::Prune(max_to_free);
194 create_ok_ = true;
195 }
196
197 bool RangeSupported() const override { return range_supported_; }
198
199 private:
200 bool range_supported_;
201 bool create_ok_;
202 size_t max_writers_;
203 size_t file_size_;
204 int32_t max_blocks_after_defer_;
205 bool must_read_whole_file_;
206 int32_t writers_created_;
207 };
208 }
209
210 class MultiBufferTest : public testing::Test {
211 public:
212 MultiBufferTest()
213 : lru_(new media::MultiBuffer::GlobalLRU()),
214 multibuffer_(kBlockSizeShift, lru_),
215 rnd_(42) {}
216
217 void Advance() {
218 CHECK(media::writers.size());
219 media::writers[rand() % media::writers.size()]->Advance();
DaleCurtis 2015/11/17 06:56:06 rnd_.Rand()?
hubbe 2015/11/17 23:40:18 Done.
220 }
221
222 bool AdvanceAll() {
223 bool advanced = false;
224 for (size_t i = 0; i < media::writers.size(); i++) {
225 advanced |= media::writers[i]->Advance();
226 }
227 multibuffer_.CheckLRUState();
228 return advanced;
229 }
230
231 protected:
232 scoped_refptr<media::MultiBuffer::GlobalLRU> lru_;
233 media::TestMultiBuffer multibuffer_;
234 base::MessageLoop message_loop_;
235 media::TestRandom rnd_;
236 };
237
238 TEST_F(MultiBufferTest, ReadAll) {
239 multibuffer_.SetMaxWriters(1);
240 size_t pos = 0;
241 size_t end = 10000;
242 multibuffer_.SetFileSize(10000);
243 multibuffer_.SetMustReadWholeFile(true);
244 media::MultiBufferReader reader(&multibuffer_, pos, end,
245 base::Callback<void(int64_t, int64_t)>());
246 reader.SetMaxBuffer(2000, 5000);
247 reader.SetPreload(1000, 1000);
248 while (pos < end) {
249 unsigned char buffer[27];
250 buffer[17] = 17;
251 size_t to_read = std::min<size_t>(end - pos, 17);
252 int64_t bytes_read = reader.TryRead(buffer, to_read);
253 if (bytes_read) {
254 EXPECT_EQ(buffer[17], 17);
255 for (int64_t i = 0; i < bytes_read; i++) {
256 uint8_t expected = static_cast<uint8_t>((pos * 15485863) >> 16);
257 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos;
258 pos++;
259 }
260 } else {
261 Advance();
262 }
263 }
264 }
265
266 TEST_F(MultiBufferTest, ReadAllAdvanceFirst) {
267 multibuffer_.SetMaxWriters(1);
268 size_t pos = 0;
269 size_t end = 10000;
270 multibuffer_.SetFileSize(10000);
271 multibuffer_.SetMustReadWholeFile(true);
272 media::MultiBufferReader reader(&multibuffer_, pos, end,
273 base::Callback<void(int64_t, int64_t)>());
274 reader.SetMaxBuffer(2000, 5000);
275 reader.SetPreload(1000, 1000);
276 while (pos < end) {
277 unsigned char buffer[27];
278 buffer[17] = 17;
279 size_t to_read = std::min<size_t>(end - pos, 17);
280 while (AdvanceAll())
281 ;
282 int64_t bytes = reader.TryRead(buffer, to_read);
283 EXPECT_GT(bytes, 0);
284 EXPECT_EQ(buffer[17], 17);
285 for (int64_t i = 0; i < bytes; i++) {
286 uint8_t expected = static_cast<uint8_t>((pos * 15485863) >> 16);
287 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos;
288 pos++;
289 }
290 }
291 }
292
293 // Checks that if the data provider provides too much data after we told it
294 // to defer, we kill it.
295 TEST_F(MultiBufferTest, ReadAllAdvanceFirst_NeverDefer) {
296 multibuffer_.SetMaxWriters(1);
297 size_t pos = 0;
298 size_t end = 10000;
299 multibuffer_.SetFileSize(10000);
300 multibuffer_.SetMaxBlocksAfterDefer(-10000);
301 multibuffer_.SetRangeSupported(true);
302 media::MultiBufferReader reader(&multibuffer_, pos, end,
303 base::Callback<void(int64_t, int64_t)>());
304 reader.SetMaxBuffer(2000, 5000);
305 reader.SetPreload(1000, 1000);
306 while (pos < end) {
307 unsigned char buffer[27];
308 buffer[17] = 17;
309 size_t to_read = std::min<size_t>(end - pos, 17);
310 while (AdvanceAll())
311 ;
312 int64_t bytes = reader.TryRead(buffer, to_read);
313 EXPECT_GT(bytes, 0);
314 EXPECT_EQ(buffer[17], 17);
315 for (int64_t i = 0; i < bytes; i++) {
316 uint8_t expected = static_cast<uint8_t>((pos * 15485863) >> 16);
317 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos;
318 pos++;
319 }
320 }
321 EXPECT_GT(multibuffer_.writers_created(), 1);
322 }
323
324 // Same as ReadAllAdvanceFirst_NeverDefer, but the url doesn't support
325 // ranges, so we don't destroy it no matter how much data it provides.
326 TEST_F(MultiBufferTest, ReadAllAdvanceFirst_NeverDefer2) {
327 multibuffer_.SetMaxWriters(1);
328 size_t pos = 0;
329 size_t end = 10000;
330 multibuffer_.SetFileSize(10000);
331 multibuffer_.SetMustReadWholeFile(true);
332 multibuffer_.SetMaxBlocksAfterDefer(-10000);
333 media::MultiBufferReader reader(&multibuffer_, pos, end,
334 base::Callback<void(int64_t, int64_t)>());
335 reader.SetMaxBuffer(2000, 5000);
336 reader.SetPreload(1000, 1000);
337 while (pos < end) {
338 unsigned char buffer[27];
339 buffer[17] = 17;
340 size_t to_read = std::min<size_t>(end - pos, 17);
341 while (AdvanceAll())
342 ;
343 int64_t bytes = reader.TryRead(buffer, to_read);
344 EXPECT_GT(bytes, 0);
345 EXPECT_EQ(buffer[17], 17);
346 for (int64_t i = 0; i < bytes; i++) {
347 uint8_t expected = static_cast<uint8_t>((pos * 15485863) >> 16);
348 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos;
349 pos++;
350 }
351 }
352 }
353
354 TEST_F(MultiBufferTest, LRUTest) {
355 int64_t max_size = 17;
356 int64_t current_size = 0;
357 lru_->IncrementMaxSize(max_size);
358
359 multibuffer_.SetMaxWriters(1);
360 size_t pos = 0;
361 size_t end = 10000;
362 multibuffer_.SetFileSize(10000);
363 media::MultiBufferReader reader(&multibuffer_, pos, end,
364 base::Callback<void(int64_t, int64_t)>());
365 reader.SetPreload(10000, 10000);
366 // Note, no pinning, all data should end up in LRU.
367 EXPECT_EQ(current_size, lru_->Size());
368 current_size += max_size;
369 while (AdvanceAll())
370 ;
371 EXPECT_EQ(current_size, lru_->Size());
372 lru_->IncrementMaxSize(-max_size);
373 lru_->Prune(3);
374 current_size -= 3;
375 EXPECT_EQ(current_size, lru_->Size());
376 lru_->Prune(3);
377 current_size -= 3;
378 EXPECT_EQ(current_size, lru_->Size());
379 lru_->Prune(1000);
380 EXPECT_EQ(0, lru_->Size());
381 }
382
383 class ReadHelper {
384 public:
385 ReadHelper(size_t end,
386 size_t max_read_size,
387 media::MultiBuffer* multibuffer,
388 media::TestRandom* rnd)
389 : pos_(0),
390 end_(end),
391 max_read_size_(max_read_size),
392 read_size_(0),
393 rnd_(rnd),
394 reader_(multibuffer,
395 pos_,
396 end_,
397 base::Callback<void(int64_t, int64_t)>()) {
398 reader_.SetMaxBuffer(2000, 5000);
399 reader_.SetPreload(1000, 1000);
400 }
401
402 bool Read() {
403 if (read_size_ == 0)
404 return true;
405 unsigned char buffer[4096];
406 CHECK_LE(read_size_, static_cast<int64_t>(sizeof(buffer)));
407 CHECK_EQ(pos_, reader_.Tell());
408 int64_t bytes_read = reader_.TryRead(buffer, read_size_);
409 if (bytes_read) {
410 for (int64_t i = 0; i < bytes_read; i++) {
411 unsigned char expected = (pos_ * 15485863) >> 16;
412 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos_;
413 pos_++;
414 }
415 CHECK_EQ(pos_, reader_.Tell());
416 return true;
417 }
418 return false;
419 }
420
421 void StartRead() {
422 CHECK_EQ(pos_, reader_.Tell());
423 read_size_ = std::min(1 + rnd_->Rand() % (max_read_size_ - 1), end_ - pos_);
424 if (!Read()) {
425 reader_.Wait(read_size_,
426 base::Bind(&ReadHelper::WaitCB, base::Unretained(this)));
427 }
428 }
429
430 void WaitCB() { CHECK(Read()); }
431
432 void Seek() {
433 pos_ = rnd_->Rand() % end_;
434 reader_.Seek(pos_);
435 CHECK_EQ(pos_, reader_.Tell());
436 }
437
438 private:
439 int64_t pos_;
440 int64_t end_;
441 int64_t max_read_size_;
442 int64_t read_size_;
443 media::TestRandom* rnd_;
444 media::MultiBufferReader reader_;
445 };
446
447 TEST_F(MultiBufferTest, RandomTest) {
448 size_t file_size = 1000000;
449 multibuffer_.SetFileSize(file_size);
450 multibuffer_.SetMaxBlocksAfterDefer(10);
451 std::vector<ReadHelper*> read_helpers;
452 for (size_t i = 0; i < 20; i++) {
453 read_helpers.push_back(
454 new ReadHelper(file_size, 1000, &multibuffer_, &rnd_));
455 }
456 for (int i = 0; i < 10000; i++) {
457 if (rnd_.Rand() & 1) {
458 if (!media::writers.empty())
459 Advance();
460 } else {
461 size_t j = rnd_.Rand() % read_helpers.size();
462 if (rnd_.Rand() % 100 < 3)
463 read_helpers[j]->Seek();
464 read_helpers[j]->StartRead();
465 multibuffer_.CheckLRUState();
466 }
467 }
468 multibuffer_.CheckPresentState();
469 while (!read_helpers.empty()) {
470 delete read_helpers.back();
471 read_helpers.pop_back();
472 }
473 }
474
475 TEST_F(MultiBufferTest, RandomTest_RangeSupported) {
476 size_t file_size = 1000000;
477 multibuffer_.SetFileSize(file_size);
478 multibuffer_.SetMaxBlocksAfterDefer(10);
479 std::vector<ReadHelper*> read_helpers;
480 multibuffer_.SetRangeSupported(true);
481 for (size_t i = 0; i < 20; i++) {
482 read_helpers.push_back(
483 new ReadHelper(file_size, 1000, &multibuffer_, &rnd_));
484 }
485 for (int i = 0; i < 10000; i++) {
486 if (rnd_.Rand() & 1) {
487 if (!media::writers.empty())
488 Advance();
489 } else {
490 size_t j = rnd_.Rand() % read_helpers.size();
491 if (rnd_.Rand() % 100 < 3)
492 read_helpers[j]->Seek();
493 read_helpers[j]->StartRead();
494 multibuffer_.CheckLRUState();
495 }
496 }
497 multibuffer_.CheckPresentState();
498 while (!read_helpers.empty()) {
499 delete read_helpers.back();
500 read_helpers.pop_back();
501 }
502 }
OLDNEW
« media/blink/multibuffer_reader.cc ('K') | « media/blink/multibuffer_reader.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698