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

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: one more compile fix 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.
DaleCurtis 2015/10/19 21:45:25 Overall there's too much use of rand() in this fil
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_;
DaleCurtis 2015/10/19 21:45:25 Again, don't use rand unless you're prepared to de
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] =
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(int32_t shift) :
122 media::MultiBuffer(shift),
123 create_ok_(true),
124 max_writers_(10000),
125 file_size_(1 << 30),
126 max_blocks_after_defer_(0),
127 must_read_whole_file_(false),
128 writers_created_(0) {
129 }
130
131 void SetMaxWriters(size_t max_writers) {
132 max_writers_ = max_writers;
133 }
134
135 void CheckPresentState() {
136 MultiBufferBlockId last;
137 for (DataMap::iterator i = data_.begin();
138 i != data_.end();
139 ++i) {
140 CHECK(i->second); // Null poineters are not allowed in data_
141 CHECK_NE(!!pinned_[i->first], lru_.Contains(i->first))
142 << " i->first = " << i->first;
143
144 if (!last.SameUrl(i->first)) {
145 last = MultiBufferBlockId(i->first.url_data(), 0);
146 }
147 while (last < i->first) {
148 CHECK_EQ(0, present_[last]) << " last = " << last;
149 ++last;
150 }
151 last = i->first;
152 CHECK_EQ(1, present_[last]) << " last = " << last;
153 ++last;
154 }
155 }
156
157 void CheckLRUState() {
158 for (DataMap::iterator i = data_.begin();
159 i != data_.end();
160 ++i) {
161 CHECK(i->second); // Null poineters are not allowed in data_
162 CHECK_NE(!!pinned_[i->first], lru_.Contains(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) {
169 file_size_ = file_size;
170 }
171
172 void SetMaxBlocksAfterDefer(int32_t max_blocks_after_defer) {
173 max_blocks_after_defer_ = max_blocks_after_defer;
174 }
175
176 void SetMustReadWholeFile(bool must_read_whole_file) {
177 must_read_whole_file_ = must_read_whole_file;
178 }
179
180 int32_t writers_created() const {
181 return writers_created_;
182 }
183 protected:
184 DataProvider* CreateWriter(const MultiBufferBlockId& pos) override {
185 DCHECK(create_ok_);
186 CHECK_LE(writers.size(), max_writers_);
187 writers_created_++;
188 return new TestMultiBufferDataProvider(
189 pos, file_size_, max_blocks_after_defer_, must_read_whole_file_);
190 }
191 void Prune(size_t max_to_free) override {
192 // Prune should not cause additional writers to be spawned.
193 create_ok_ = false;
194 MultiBuffer::Prune(max_to_free);
195 create_ok_ = true;
196 }
197 private:
198 bool create_ok_;
199 size_t max_writers_;
200 size_t file_size_;
201 int32_t max_blocks_after_defer_;
202 bool must_read_whole_file_;
203 int32_t writers_created_;
204 };
205
206 }
207
208 class MultiBufferTest : public testing::Test {
209 public:
210 MultiBufferTest() :
211 multibuffer_(kBlockSizeShift) {
212 }
213
214 void Advance() {
215 CHECK(media::writers.size());
216 media::writers[rand() % media::writers.size()]->Advance();
DaleCurtis 2015/10/19 21:45:25 Ditto.
217 }
218
219 bool AdvanceAll() {
220 bool advanced = false;
221 for (size_t i = 0; i < media::writers.size(); i++) {
222 advanced |= media::writers[i]->Advance();
223 }
224 multibuffer_.CheckLRUState();
225 return advanced;
226 }
227
228 scoped_refptr<media::UrlData> GetUrl() {
229 return url_index_.GetByUrl(GURL("http://x"), media::UrlData::kUnspecified);
230 }
231
232 protected:
233 media::TestMultiBuffer multibuffer_;
234 media::UrlIndex url_index_;
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_,
244 GetUrl(),
245 pos,
246 end,
247 base::Callback<void(int64_t, int64_t)>());
248 reader.SetMaxBuffer(2000, 5000);
249 reader.SetPreload(1000, 1000);
250 while (pos < end) {
251 unsigned char buffer[27];
252 buffer[17] = 17;
253 size_t to_read = std::min<size_t>(end - pos, 17);
254 int64_t bytes_read = reader.TryRead(buffer, to_read);
255 if (bytes_read) {
256 EXPECT_EQ(buffer[17], 17);
257 for (int64_t i = 0; i < bytes_read; i++) {
258 uint8_t expected = static_cast<uint8_t>((pos * 15485863) >> 16);
259 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos;
260 pos++;
261 }
262 } else {
263 Advance();
264 }
265 }
266 }
267
268 TEST_F(MultiBufferTest, UpdateUrlData) {
269 multibuffer_.SetMaxWriters(1);
270 size_t pos = 0;
271 size_t end = 10000;
272 multibuffer_.SetFileSize(10000);
273 scoped_refptr<media::UrlData> a = GetUrl();
274 scoped_refptr<media::UrlData> b =
275 url_index_.GetByUrl(GURL("http://y"), media::UrlData::kUnspecified);
276 media::MultiBufferReader reader(&multibuffer_,
277 a,
278 pos,
279 end,
280 base::Callback<void(int64_t, int64_t)>());
281 reader.SetPreload(1000, 1000);
282 multibuffer_.UpdateUrlData(a, b);
283 EXPECT_EQ(b, reader.GetUrlData());
284 }
285
286
287 TEST_F(MultiBufferTest, ReadAllAdvanceFirst) {
288 multibuffer_.SetMaxWriters(1);
289 size_t pos = 0;
290 size_t end = 10000;
291 multibuffer_.SetFileSize(10000);
292 multibuffer_.SetMustReadWholeFile(true);
293 media::MultiBufferReader reader(&multibuffer_,
294 GetUrl(),
295 pos,
296 end,
297 base::Callback<void(int64_t, int64_t)>());
298 reader.SetMaxBuffer(2000, 5000);
299 reader.SetPreload(1000, 1000);
300 while (pos < end) {
301 unsigned char buffer[27];
302 buffer[17] = 17;
303 size_t to_read = std::min<size_t>(end - pos, 17);
304 while (AdvanceAll());
305 int64_t bytes = reader.TryRead(buffer, to_read);
306 EXPECT_GT(bytes, 0);
307 EXPECT_EQ(buffer[17], 17);
308 for (int64_t i = 0; i < bytes; i++) {
309 uint8_t expected = static_cast<uint8_t>((pos * 15485863) >> 16);
310 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos;
311 pos++;
312 }
313 }
314 }
315
316 // Checks that if the data provider provides too much data after we told it
317 // to defer, we kill it.
318 TEST_F(MultiBufferTest, ReadAllAdvanceFirst_NeverDefer) {
319 multibuffer_.SetMaxWriters(1);
320 size_t pos = 0;
321 size_t end = 10000;
322 multibuffer_.SetFileSize(10000);
323 multibuffer_.SetMaxBlocksAfterDefer(-10000);
324 scoped_refptr<media::UrlData> url_data = GetUrl();
325 url_data->set_range_supported();
326 media::MultiBufferReader reader(&multibuffer_,
327 url_data,
328 pos,
329 end,
330 base::Callback<void(int64_t, int64_t)>());
331 reader.SetMaxBuffer(2000, 5000);
332 reader.SetPreload(1000, 1000);
333 while (pos < end) {
334 unsigned char buffer[27];
335 buffer[17] = 17;
336 size_t to_read = std::min<size_t>(end - pos, 17);
337 while (AdvanceAll());
338 int64_t bytes = reader.TryRead(buffer, to_read);
339 EXPECT_GT(bytes, 0);
340 EXPECT_EQ(buffer[17], 17);
341 for (int64_t i = 0; i < bytes; i++) {
342 uint8_t expected = static_cast<uint8_t>((pos * 15485863) >> 16);
343 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos;
344 pos++;
345 }
346 }
347 EXPECT_GT(multibuffer_.writers_created(), 1);
348 }
349
350 // Same as ReadAllAdvanceFirst_NeverDefer, but the url doesn't support
351 // ranges, so we don't destroy it no matter how much data it provides.
352 TEST_F(MultiBufferTest, ReadAllAdvanceFirst_NeverDefer2) {
353 multibuffer_.SetMaxWriters(1);
354 size_t pos = 0;
355 size_t end = 10000;
356 multibuffer_.SetFileSize(10000);
357 multibuffer_.SetMustReadWholeFile(true);
358 multibuffer_.SetMaxBlocksAfterDefer(-10000);
359 scoped_refptr<media::UrlData> url_data = GetUrl();
360 media::MultiBufferReader reader(&multibuffer_,
361 url_data,
362 pos,
363 end,
364 base::Callback<void(int64_t, int64_t)>());
365 reader.SetMaxBuffer(2000, 5000);
366 reader.SetPreload(1000, 1000);
367 while (pos < end) {
368 unsigned char buffer[27];
369 buffer[17] = 17;
370 size_t to_read = std::min<size_t>(end - pos, 17);
371 while (AdvanceAll());
372 int64_t bytes = reader.TryRead(buffer, to_read);
373 EXPECT_GT(bytes, 0);
374 EXPECT_EQ(buffer[17], 17);
375 for (int64_t i = 0; i < bytes; i++) {
376 uint8_t expected = static_cast<uint8_t>((pos * 15485863) >> 16);
377 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos;
378 pos++;
379 }
380 }
381 }
382
383 class ReadHelper {
384 public:
385 ReadHelper(scoped_refptr<media::UrlData> url,
386 size_t end,
387 size_t max_read_size,
388 media::MultiBuffer* multibuffer) :
389 pos_(0),
390 end_(end),
391 max_read_size_(max_read_size),
392 read_size_(0),
393 reader_(multibuffer,
394 url,
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) 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 + 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() {
430 CHECK(Read());
431 }
432
433 void Seek() {
434 pos_ = rand() % end_;
435 reader_.Seek(pos_);
436 CHECK_EQ(pos_, reader_.Tell());
437 }
438
439 private:
440 int64_t pos_;
441 int64_t end_;
442 int64_t max_read_size_;
443 int64_t read_size_;
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 scoped_refptr<media::UrlData> url = GetUrl();
453 for (size_t i = 0; i < 20; i++) {
454 read_helpers.push_back(new ReadHelper(url, file_size, 1000, &multibuffer_));
455 }
456 for (int i = 0; i < 10000; i++) {
457 if (rand() & 1) {
458 if (!media::writers.empty()) Advance();
459 } else {
460 size_t j = rand() % read_helpers.size();
461 if (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 scoped_refptr<media::UrlData> url = GetUrl();
480 url->set_range_supported();
481 for (size_t i = 0; i < 20; i++) {
482 read_helpers.push_back(new ReadHelper(url, file_size, 1000, &multibuffer_));
483 }
484 for (int i = 0; i < 10000; i++) {
485 if (rand() & 1) {
486 if (!media::writers.empty()) Advance();
487 } else {
488 size_t j = rand() % read_helpers.size();
489 if (rand() % 100 < 3)
490 read_helpers[j]->Seek();
491 read_helpers[j]->StartRead();
492 multibuffer_.CheckLRUState();
493 }
494 }
495 multibuffer_.CheckPresentState();
496 while (!read_helpers.empty()) {
497 delete read_helpers.back();
498 read_helpers.pop_back();
499 }
500 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698