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

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: use intptr_t 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_;
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 RangeMap<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.IncrementRange(i->first, i->first + 1, 1);
142 }
143 RangeMap<MultiBufferBlockId, int32_t>::const_iterator tmp_iterator =
144 tmp.begin();
145 RangeMap<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.range_begin(), present_iterator.range_begin());
149 EXPECT_EQ(tmp_iterator.range_end(), present_iterator.range_end());
150 EXPECT_EQ(tmp_iterator.value(), present_iterator.value());
151 ++tmp_iterator;
152 ++present_iterator;
153 }
154 EXPECT_TRUE(tmp_iterator == tmp.end());
155 EXPECT_TRUE(present_iterator == present_.end());
156 }
157
158 void CheckLRUState() {
159 for (DataMap::iterator i = data_.begin(); i != data_.end(); ++i) {
160 CHECK(i->second); // Null poineters are not allowed in data_
161 CHECK_NE(!!pinned_[i->first], lru_->Contains(this, i->first))
162 << " i->first = " << i->first;
163 CHECK_EQ(1, present_[i->first]) << " i->first = " << i->first;
164 }
165 }
166
167 void SetFileSize(size_t file_size) { file_size_ = file_size; }
168
169 void SetMaxBlocksAfterDefer(int32_t max_blocks_after_defer) {
170 max_blocks_after_defer_ = max_blocks_after_defer;
171 }
172
173 void SetMustReadWholeFile(bool must_read_whole_file) {
174 must_read_whole_file_ = must_read_whole_file;
175 }
176
177 int32_t writers_created() const { return writers_created_; }
178
179 void SetRangeSupported(bool supported) { range_supported_ = supported; }
180
181 protected:
182 DataProvider* CreateWriter(const MultiBufferBlockId& pos) override {
183 DCHECK(create_ok_);
184 writers_created_++;
185 CHECK_LT(writers.size(), max_writers_);
186 return new TestMultiBufferDataProvider(
187 pos, file_size_, max_blocks_after_defer_, must_read_whole_file_);
188 }
189 void Prune(size_t max_to_free) override {
190 // Prune should not cause additional writers to be spawned.
191 create_ok_ = false;
192 MultiBuffer::Prune(max_to_free);
193 create_ok_ = true;
194 }
195
196 bool RangeSupported() const override { return range_supported_; }
197
198 private:
199 bool range_supported_;
200 bool create_ok_;
201 size_t max_writers_;
202 size_t file_size_;
203 int32_t max_blocks_after_defer_;
204 bool must_read_whole_file_;
205 int32_t writers_created_;
206 };
207 }
208
209 class MultiBufferTest : public testing::Test {
210 public:
211 MultiBufferTest()
212 : lru_(new media::MultiBuffer::GlobalLRU()),
213 multibuffer_(kBlockSizeShift, lru_),
214 rnd_(42) {}
215
216 void Advance() {
217 CHECK(media::writers.size());
218 media::writers[rand() % media::writers.size()]->Advance();
219 }
220
221 bool AdvanceAll() {
222 bool advanced = false;
223 for (size_t i = 0; i < media::writers.size(); i++) {
224 advanced |= media::writers[i]->Advance();
225 }
226 multibuffer_.CheckLRUState();
227 return advanced;
228 }
229
230 protected:
231 scoped_refptr<media::MultiBuffer::GlobalLRU> lru_;
232 media::TestMultiBuffer multibuffer_;
233 base::MessageLoop message_loop_;
234 media::TestRandom rnd_;
235 };
236
237 TEST_F(MultiBufferTest, ReadAll) {
238 multibuffer_.SetMaxWriters(1);
239 size_t pos = 0;
240 size_t end = 10000;
241 multibuffer_.SetFileSize(10000);
242 multibuffer_.SetMustReadWholeFile(true);
243 media::MultiBufferReader reader(&multibuffer_, pos, end,
244 base::Callback<void(int64_t, int64_t)>());
245 reader.SetMaxBuffer(2000, 5000);
246 reader.SetPreload(1000, 1000);
247 while (pos < end) {
248 unsigned char buffer[27];
249 buffer[17] = 17;
250 size_t to_read = std::min<size_t>(end - pos, 17);
251 int64_t bytes_read = reader.TryRead(buffer, to_read);
252 if (bytes_read) {
253 EXPECT_EQ(buffer[17], 17);
254 for (int64_t i = 0; i < bytes_read; i++) {
255 uint8_t expected = static_cast<uint8_t>((pos * 15485863) >> 16);
256 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos;
257 pos++;
258 }
259 } else {
260 Advance();
261 }
262 }
263 }
264
265 TEST_F(MultiBufferTest, ReadAllAdvanceFirst) {
266 multibuffer_.SetMaxWriters(1);
267 size_t pos = 0;
268 size_t end = 10000;
269 multibuffer_.SetFileSize(10000);
270 multibuffer_.SetMustReadWholeFile(true);
271 media::MultiBufferReader reader(&multibuffer_, pos, end,
272 base::Callback<void(int64_t, int64_t)>());
273 reader.SetMaxBuffer(2000, 5000);
274 reader.SetPreload(1000, 1000);
275 while (pos < end) {
276 unsigned char buffer[27];
277 buffer[17] = 17;
278 size_t to_read = std::min<size_t>(end - pos, 17);
279 while (AdvanceAll())
280 ;
281 int64_t bytes = reader.TryRead(buffer, to_read);
282 EXPECT_GT(bytes, 0);
283 EXPECT_EQ(buffer[17], 17);
284 for (int64_t i = 0; i < bytes; i++) {
285 uint8_t expected = static_cast<uint8_t>((pos * 15485863) >> 16);
286 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos;
287 pos++;
288 }
289 }
290 }
291
292 // Checks that if the data provider provides too much data after we told it
293 // to defer, we kill it.
294 TEST_F(MultiBufferTest, ReadAllAdvanceFirst_NeverDefer) {
295 multibuffer_.SetMaxWriters(1);
296 size_t pos = 0;
297 size_t end = 10000;
298 multibuffer_.SetFileSize(10000);
299 multibuffer_.SetMaxBlocksAfterDefer(-10000);
300 multibuffer_.SetRangeSupported(true);
301 media::MultiBufferReader reader(&multibuffer_, pos, end,
302 base::Callback<void(int64_t, int64_t)>());
303 reader.SetMaxBuffer(2000, 5000);
304 reader.SetPreload(1000, 1000);
305 while (pos < end) {
306 unsigned char buffer[27];
307 buffer[17] = 17;
308 size_t to_read = std::min<size_t>(end - pos, 17);
309 while (AdvanceAll())
310 ;
311 int64_t bytes = reader.TryRead(buffer, to_read);
312 EXPECT_GT(bytes, 0);
313 EXPECT_EQ(buffer[17], 17);
314 for (int64_t i = 0; i < bytes; i++) {
315 uint8_t expected = static_cast<uint8_t>((pos * 15485863) >> 16);
316 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos;
317 pos++;
318 }
319 }
320 EXPECT_GT(multibuffer_.writers_created(), 1);
321 }
322
323 // Same as ReadAllAdvanceFirst_NeverDefer, but the url doesn't support
324 // ranges, so we don't destroy it no matter how much data it provides.
325 TEST_F(MultiBufferTest, ReadAllAdvanceFirst_NeverDefer2) {
326 multibuffer_.SetMaxWriters(1);
327 size_t pos = 0;
328 size_t end = 10000;
329 multibuffer_.SetFileSize(10000);
330 multibuffer_.SetMustReadWholeFile(true);
331 multibuffer_.SetMaxBlocksAfterDefer(-10000);
332 media::MultiBufferReader reader(&multibuffer_, pos, end,
333 base::Callback<void(int64_t, int64_t)>());
334 reader.SetMaxBuffer(2000, 5000);
335 reader.SetPreload(1000, 1000);
336 while (pos < end) {
337 unsigned char buffer[27];
338 buffer[17] = 17;
339 size_t to_read = std::min<size_t>(end - pos, 17);
340 while (AdvanceAll())
341 ;
342 int64_t bytes = reader.TryRead(buffer, to_read);
343 EXPECT_GT(bytes, 0);
344 EXPECT_EQ(buffer[17], 17);
345 for (int64_t i = 0; i < bytes; i++) {
346 uint8_t expected = static_cast<uint8_t>((pos * 15485863) >> 16);
347 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos;
348 pos++;
349 }
350 }
351 }
352
353 TEST_F(MultiBufferTest, LRUTest) {
354 int64_t max_size = 17;
355 int64_t current_size = 0;
356 lru_->IncrementMaxSize(max_size);
357
358 multibuffer_.SetMaxWriters(1);
359 size_t pos = 0;
360 size_t end = 10000;
361 multibuffer_.SetFileSize(10000);
362 media::MultiBufferReader reader(&multibuffer_, pos, end,
363 base::Callback<void(int64_t, int64_t)>());
364 reader.SetPreload(10000, 10000);
365 // Note, no pinning, all data should end up in LRU.
366 EXPECT_EQ(current_size, lru_->Size());
367 current_size += max_size;
368 while (AdvanceAll())
369 ;
370 EXPECT_EQ(current_size, lru_->Size());
371 lru_->IncrementMaxSize(-max_size);
372 lru_->Prune(3);
373 current_size -= 3;
374 EXPECT_EQ(current_size, lru_->Size());
375 lru_->Prune(3);
376 current_size -= 3;
377 EXPECT_EQ(current_size, lru_->Size());
378 lru_->Prune(1000);
379 EXPECT_EQ(0, lru_->Size());
380 }
381
382 class ReadHelper {
383 public:
384 ReadHelper(size_t end,
385 size_t max_read_size,
386 media::MultiBuffer* multibuffer,
387 media::TestRandom* rnd)
388 : pos_(0),
389 end_(end),
390 max_read_size_(max_read_size),
391 read_size_(0),
392 rnd_(rnd),
393 reader_(multibuffer,
394 pos_,
395 end_,
396 base::Callback<void(int64_t, int64_t)>()) {
397 reader_.SetMaxBuffer(2000, 5000);
398 reader_.SetPreload(1000, 1000);
399 }
400
401 bool Read() {
402 if (read_size_ == 0)
403 return true;
404 unsigned char buffer[4096];
405 CHECK_LE(read_size_, static_cast<int64_t>(sizeof(buffer)));
406 CHECK_EQ(pos_, reader_.Tell());
407 int64_t bytes_read = reader_.TryRead(buffer, read_size_);
408 if (bytes_read) {
409 for (int64_t i = 0; i < bytes_read; i++) {
410 unsigned char expected = (pos_ * 15485863) >> 16;
411 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos_;
412 pos_++;
413 }
414 CHECK_EQ(pos_, reader_.Tell());
415 return true;
416 }
417 return false;
418 }
419
420 void StartRead() {
421 CHECK_EQ(pos_, reader_.Tell());
422 read_size_ = std::min(1 + rnd_->Rand() % (max_read_size_ - 1), end_ - pos_);
423 if (!Read()) {
424 reader_.Wait(read_size_,
425 base::Bind(&ReadHelper::WaitCB, base::Unretained(this)));
426 }
427 }
428
429 void WaitCB() { CHECK(Read()); }
430
431 void Seek() {
432 pos_ = rnd_->Rand() % end_;
433 reader_.Seek(pos_);
434 CHECK_EQ(pos_, reader_.Tell());
435 }
436
437 private:
438 int64_t pos_;
439 int64_t end_;
440 int64_t max_read_size_;
441 int64_t read_size_;
442 media::TestRandom* rnd_;
443 media::MultiBufferReader reader_;
444 };
445
446 TEST_F(MultiBufferTest, RandomTest) {
447 size_t file_size = 1000000;
448 multibuffer_.SetFileSize(file_size);
449 multibuffer_.SetMaxBlocksAfterDefer(10);
450 std::vector<ReadHelper*> read_helpers;
451 for (size_t i = 0; i < 20; i++) {
452 read_helpers.push_back(
453 new ReadHelper(file_size, 1000, &multibuffer_, &rnd_));
454 }
455 for (int i = 0; i < 10000; i++) {
456 if (rnd_.Rand() & 1) {
457 if (!media::writers.empty())
458 Advance();
459 } else {
460 size_t j = rnd_.Rand() % read_helpers.size();
461 if (rnd_.Rand() % 100 < 3)
462 read_helpers[j]->Seek();
463 read_helpers[j]->StartRead();
464 multibuffer_.CheckLRUState();
465 }
466 }
467 multibuffer_.CheckPresentState();
468 while (!read_helpers.empty()) {
469 delete read_helpers.back();
470 read_helpers.pop_back();
471 }
472 }
473
474 TEST_F(MultiBufferTest, RandomTest_RangeSupported) {
475 size_t file_size = 1000000;
476 multibuffer_.SetFileSize(file_size);
477 multibuffer_.SetMaxBlocksAfterDefer(10);
478 std::vector<ReadHelper*> read_helpers;
479 multibuffer_.SetRangeSupported(true);
480 for (size_t i = 0; i < 20; i++) {
481 read_helpers.push_back(
482 new ReadHelper(file_size, 1000, &multibuffer_, &rnd_));
483 }
484 for (int i = 0; i < 10000; i++) {
485 if (rnd_.Rand() & 1) {
486 if (!media::writers.empty())
487 Advance();
488 } else {
489 size_t j = rnd_.Rand() % read_helpers.size();
490 if (rnd_.Rand() % 100 < 3)
491 read_helpers[j]->Seek();
492 read_helpers[j]->StartRead();
493 multibuffer_.CheckLRUState();
494 }
495 }
496 multibuffer_.CheckPresentState();
497 while (!read_helpers.empty()) {
498 delete read_helpers.back();
499 read_helpers.pop_back();
500 }
501 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698