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

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

Powered by Google App Engine
This is Rietveld 408576698