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

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

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

Powered by Google App Engine
This is Rietveld 408576698