OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/metrics/persistent_memory_allocator.h" | 5 #include "base/metrics/persistent_memory_allocator.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "base/files/file.h" | 9 #include "base/files/file.h" |
10 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
11 #include "base/files/memory_mapped_file.h" | 11 #include "base/files/memory_mapped_file.h" |
12 #include "base/files/scoped_temp_dir.h" | 12 #include "base/files/scoped_temp_dir.h" |
13 #include "base/memory/shared_memory.h" | 13 #include "base/memory/shared_memory.h" |
14 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
15 #include "base/rand_util.h" | 15 #include "base/rand_util.h" |
16 #include "base/strings/safe_sprintf.h" | 16 #include "base/strings/safe_sprintf.h" |
| 17 #include "base/synchronization/condition_variable.h" |
| 18 #include "base/synchronization/lock.h" |
17 #include "base/threading/simple_thread.h" | 19 #include "base/threading/simple_thread.h" |
18 #include "testing/gmock/include/gmock/gmock.h" | 20 #include "testing/gmock/include/gmock/gmock.h" |
19 | 21 |
20 namespace { | 22 namespace { |
21 | 23 |
22 const uint32_t TEST_MEMORY_SIZE = 1 << 20; // 1 MiB | 24 const uint32_t TEST_MEMORY_SIZE = 1 << 20; // 1 MiB |
23 const uint32_t TEST_MEMORY_PAGE = 64 << 10; // 64 KiB | 25 const uint32_t TEST_MEMORY_PAGE = 64 << 10; // 64 KiB |
24 const uint32_t TEST_ID = 12345; | 26 const uint32_t TEST_ID = 12345; |
25 const char TEST_NAME[] = "TestAllocator"; | 27 const char TEST_NAME[] = "TestAllocator"; |
26 | 28 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
62 mem_segment_.get(), TEST_MEMORY_SIZE, TEST_MEMORY_PAGE, | 64 mem_segment_.get(), TEST_MEMORY_SIZE, TEST_MEMORY_PAGE, |
63 TEST_ID, TEST_NAME, false)); | 65 TEST_ID, TEST_NAME, false)); |
64 allocator_->CreateTrackingHistograms(allocator_->Name()); | 66 allocator_->CreateTrackingHistograms(allocator_->Name()); |
65 } | 67 } |
66 | 68 |
67 void TearDown() override { | 69 void TearDown() override { |
68 allocator_.reset(); | 70 allocator_.reset(); |
69 } | 71 } |
70 | 72 |
71 unsigned CountIterables() { | 73 unsigned CountIterables() { |
72 PersistentMemoryAllocator::Iterator iter; | 74 PersistentMemoryAllocator::Iterator iter(allocator_.get()); |
73 uint32_t type; | 75 uint32_t type; |
74 unsigned count = 0; | 76 unsigned count = 0; |
75 for (allocator_->CreateIterator(&iter); | 77 while (iter.GetNext(&type) != 0) { |
76 allocator_->GetNextIterable(&iter, &type) != 0;) { | 78 ++count; |
77 count++; | |
78 } | 79 } |
79 return count; | 80 return count; |
80 } | 81 } |
81 | 82 |
82 protected: | 83 protected: |
83 std::unique_ptr<char[]> mem_segment_; | 84 std::unique_ptr<char[]> mem_segment_; |
84 std::unique_ptr<PersistentMemoryAllocator> allocator_; | 85 std::unique_ptr<PersistentMemoryAllocator> allocator_; |
85 }; | 86 }; |
86 | 87 |
87 TEST_F(PersistentMemoryAllocatorTest, AllocateAndIterate) { | 88 TEST_F(PersistentMemoryAllocatorTest, AllocateAndIterate) { |
(...skipping 20 matching lines...) Expand all Loading... |
108 EXPECT_EQ(nullptr, allocator_->GetAsObject<TestObject2>(block1, 1)); | 109 EXPECT_EQ(nullptr, allocator_->GetAsObject<TestObject2>(block1, 1)); |
109 EXPECT_LE(sizeof(TestObject1), allocator_->GetAllocSize(block1)); | 110 EXPECT_LE(sizeof(TestObject1), allocator_->GetAllocSize(block1)); |
110 EXPECT_GT(sizeof(TestObject1) + kAllocAlignment, | 111 EXPECT_GT(sizeof(TestObject1) + kAllocAlignment, |
111 allocator_->GetAllocSize(block1)); | 112 allocator_->GetAllocSize(block1)); |
112 PersistentMemoryAllocator::MemoryInfo meminfo1; | 113 PersistentMemoryAllocator::MemoryInfo meminfo1; |
113 allocator_->GetMemoryInfo(&meminfo1); | 114 allocator_->GetMemoryInfo(&meminfo1); |
114 EXPECT_EQ(meminfo0.total, meminfo1.total); | 115 EXPECT_EQ(meminfo0.total, meminfo1.total); |
115 EXPECT_GT(meminfo0.free, meminfo1.free); | 116 EXPECT_GT(meminfo0.free, meminfo1.free); |
116 | 117 |
117 // Ensure that the test-object can be made iterable. | 118 // Ensure that the test-object can be made iterable. |
118 PersistentMemoryAllocator::Iterator iter; | 119 PersistentMemoryAllocator::Iterator iter1a(allocator_.get()); |
119 uint32_t type; | 120 uint32_t type; |
120 allocator_->CreateIterator(&iter); | 121 EXPECT_EQ(0U, iter1a.GetNext(&type)); |
121 EXPECT_EQ(0U, allocator_->GetNextIterable(&iter, &type)); | |
122 allocator_->MakeIterable(block1); | 122 allocator_->MakeIterable(block1); |
123 EXPECT_EQ(block1, allocator_->GetNextIterable(&iter, &type)); | 123 EXPECT_EQ(block1, iter1a.GetNext(&type)); |
124 EXPECT_EQ(1U, type); | 124 EXPECT_EQ(1U, type); |
125 EXPECT_EQ(0U, allocator_->GetNextIterable(&iter, &type)); | 125 EXPECT_EQ(0U, iter1a.GetNext(&type)); |
126 | 126 |
127 // Create second test-object and ensure everything is good and it cannot | 127 // Create second test-object and ensure everything is good and it cannot |
128 // be confused with test-object of another type. | 128 // be confused with test-object of another type. |
129 Reference block2 = allocator_->Allocate(sizeof(TestObject2), 2); | 129 Reference block2 = allocator_->Allocate(sizeof(TestObject2), 2); |
130 EXPECT_NE(0U, block2); | 130 EXPECT_NE(0U, block2); |
131 EXPECT_NE(nullptr, allocator_->GetAsObject<TestObject2>(block2, 2)); | 131 EXPECT_NE(nullptr, allocator_->GetAsObject<TestObject2>(block2, 2)); |
132 EXPECT_EQ(nullptr, allocator_->GetAsObject<TestObject2>(block2, 1)); | 132 EXPECT_EQ(nullptr, allocator_->GetAsObject<TestObject2>(block2, 1)); |
133 EXPECT_LE(sizeof(TestObject2), allocator_->GetAllocSize(block2)); | 133 EXPECT_LE(sizeof(TestObject2), allocator_->GetAllocSize(block2)); |
134 EXPECT_GT(sizeof(TestObject2) + kAllocAlignment, | 134 EXPECT_GT(sizeof(TestObject2) + kAllocAlignment, |
135 allocator_->GetAllocSize(block2)); | 135 allocator_->GetAllocSize(block2)); |
136 PersistentMemoryAllocator::MemoryInfo meminfo2; | 136 PersistentMemoryAllocator::MemoryInfo meminfo2; |
137 allocator_->GetMemoryInfo(&meminfo2); | 137 allocator_->GetMemoryInfo(&meminfo2); |
138 EXPECT_EQ(meminfo1.total, meminfo2.total); | 138 EXPECT_EQ(meminfo1.total, meminfo2.total); |
139 EXPECT_GT(meminfo1.free, meminfo2.free); | 139 EXPECT_GT(meminfo1.free, meminfo2.free); |
140 | 140 |
141 // Ensure that second test-object can also be made iterable. | 141 // Ensure that second test-object can also be made iterable. |
142 allocator_->MakeIterable(block2); | 142 allocator_->MakeIterable(block2); |
143 EXPECT_EQ(block2, allocator_->GetNextIterable(&iter, &type)); | 143 EXPECT_EQ(block2, iter1a.GetNext(&type)); |
144 EXPECT_EQ(2U, type); | 144 EXPECT_EQ(2U, type); |
145 EXPECT_EQ(0U, allocator_->GetNextIterable(&iter, &type)); | 145 EXPECT_EQ(0U, iter1a.GetNext(&type)); |
146 | 146 |
147 // Check that iteration can begin after an arbitrary location. | 147 // Check that iteration can begin after an arbitrary location. |
148 allocator_->CreateIterator(&iter, block1); | 148 PersistentMemoryAllocator::Iterator iter1b(allocator_.get(), block1); |
149 EXPECT_EQ(block2, allocator_->GetNextIterable(&iter, &type)); | 149 EXPECT_EQ(block2, iter1b.GetNext(&type)); |
150 EXPECT_EQ(0U, allocator_->GetNextIterable(&iter, &type)); | 150 EXPECT_EQ(0U, iter1b.GetNext(&type)); |
151 | 151 |
152 // Ensure nothing has gone noticably wrong. | 152 // Ensure nothing has gone noticably wrong. |
153 EXPECT_FALSE(allocator_->IsFull()); | 153 EXPECT_FALSE(allocator_->IsFull()); |
154 EXPECT_FALSE(allocator_->IsCorrupt()); | 154 EXPECT_FALSE(allocator_->IsCorrupt()); |
155 | 155 |
156 // Check the internal histogram record of used memory. | 156 // Check the internal histogram record of used memory. |
157 allocator_->UpdateTrackingHistograms(); | 157 allocator_->UpdateTrackingHistograms(); |
158 std::unique_ptr<HistogramSamples> used_samples( | 158 std::unique_ptr<HistogramSamples> used_samples( |
159 allocator_->used_histogram_->SnapshotSamples()); | 159 allocator_->used_histogram_->SnapshotSamples()); |
160 EXPECT_TRUE(used_samples); | 160 EXPECT_TRUE(used_samples); |
(...skipping 24 matching lines...) Expand all Loading... |
185 // Create second allocator (read/write) using the same memory segment. | 185 // Create second allocator (read/write) using the same memory segment. |
186 std::unique_ptr<PersistentMemoryAllocator> allocator2( | 186 std::unique_ptr<PersistentMemoryAllocator> allocator2( |
187 new PersistentMemoryAllocator(mem_segment_.get(), TEST_MEMORY_SIZE, | 187 new PersistentMemoryAllocator(mem_segment_.get(), TEST_MEMORY_SIZE, |
188 TEST_MEMORY_PAGE, 0, "", false)); | 188 TEST_MEMORY_PAGE, 0, "", false)); |
189 EXPECT_EQ(TEST_ID, allocator2->Id()); | 189 EXPECT_EQ(TEST_ID, allocator2->Id()); |
190 EXPECT_FALSE(allocator2->used_histogram_); | 190 EXPECT_FALSE(allocator2->used_histogram_); |
191 EXPECT_FALSE(allocator2->allocs_histogram_); | 191 EXPECT_FALSE(allocator2->allocs_histogram_); |
192 EXPECT_NE(allocator2->allocs_histogram_, allocator_->allocs_histogram_); | 192 EXPECT_NE(allocator2->allocs_histogram_, allocator_->allocs_histogram_); |
193 | 193 |
194 // Ensure that iteration and access through second allocator works. | 194 // Ensure that iteration and access through second allocator works. |
195 allocator2->CreateIterator(&iter); | 195 PersistentMemoryAllocator::Iterator iter2(allocator2.get()); |
196 EXPECT_EQ(block1, allocator2->GetNextIterable(&iter, &type)); | 196 EXPECT_EQ(block1, iter2.GetNext(&type)); |
197 EXPECT_EQ(block2, allocator2->GetNextIterable(&iter, &type)); | 197 EXPECT_EQ(block2, iter2.GetNext(&type)); |
198 EXPECT_EQ(0U, allocator2->GetNextIterable(&iter, &type)); | 198 EXPECT_EQ(0U, iter2.GetNext(&type)); |
199 EXPECT_NE(nullptr, allocator2->GetAsObject<TestObject1>(block1, 1)); | 199 EXPECT_NE(nullptr, allocator2->GetAsObject<TestObject1>(block1, 1)); |
200 EXPECT_NE(nullptr, allocator2->GetAsObject<TestObject2>(block2, 2)); | 200 EXPECT_NE(nullptr, allocator2->GetAsObject<TestObject2>(block2, 2)); |
201 | 201 |
202 // Create a third allocator (read-only) using the same memory segment. | 202 // Create a third allocator (read-only) using the same memory segment. |
203 std::unique_ptr<const PersistentMemoryAllocator> allocator3( | 203 std::unique_ptr<const PersistentMemoryAllocator> allocator3( |
204 new PersistentMemoryAllocator(mem_segment_.get(), TEST_MEMORY_SIZE, | 204 new PersistentMemoryAllocator(mem_segment_.get(), TEST_MEMORY_SIZE, |
205 TEST_MEMORY_PAGE, 0, "", true)); | 205 TEST_MEMORY_PAGE, 0, "", true)); |
206 EXPECT_EQ(TEST_ID, allocator3->Id()); | 206 EXPECT_EQ(TEST_ID, allocator3->Id()); |
207 EXPECT_FALSE(allocator3->used_histogram_); | 207 EXPECT_FALSE(allocator3->used_histogram_); |
208 EXPECT_FALSE(allocator3->allocs_histogram_); | 208 EXPECT_FALSE(allocator3->allocs_histogram_); |
209 | 209 |
210 // Ensure that iteration and access through third allocator works. | 210 // Ensure that iteration and access through third allocator works. |
211 allocator3->CreateIterator(&iter); | 211 PersistentMemoryAllocator::Iterator iter3(allocator3.get()); |
212 EXPECT_EQ(block1, allocator3->GetNextIterable(&iter, &type)); | 212 EXPECT_EQ(block1, iter3.GetNext(&type)); |
213 EXPECT_EQ(block2, allocator3->GetNextIterable(&iter, &type)); | 213 EXPECT_EQ(block2, iter3.GetNext(&type)); |
214 EXPECT_EQ(0U, allocator3->GetNextIterable(&iter, &type)); | 214 EXPECT_EQ(0U, iter3.GetNext(&type)); |
215 EXPECT_NE(nullptr, allocator3->GetAsObject<TestObject1>(block1, 1)); | 215 EXPECT_NE(nullptr, allocator3->GetAsObject<TestObject1>(block1, 1)); |
216 EXPECT_NE(nullptr, allocator3->GetAsObject<TestObject2>(block2, 2)); | 216 EXPECT_NE(nullptr, allocator3->GetAsObject<TestObject2>(block2, 2)); |
| 217 |
| 218 // Ensure that GetNextOfType works. |
| 219 PersistentMemoryAllocator::Iterator iter1c(allocator_.get()); |
| 220 EXPECT_EQ(block2, iter1c.GetNextOfType(2)); |
| 221 EXPECT_EQ(0U, iter1c.GetNextOfType(2)); |
217 } | 222 } |
218 | 223 |
219 TEST_F(PersistentMemoryAllocatorTest, PageTest) { | 224 TEST_F(PersistentMemoryAllocatorTest, PageTest) { |
220 // This allocation will go into the first memory page. | 225 // This allocation will go into the first memory page. |
221 Reference block1 = allocator_->Allocate(TEST_MEMORY_PAGE / 2, 1); | 226 Reference block1 = allocator_->Allocate(TEST_MEMORY_PAGE / 2, 1); |
222 EXPECT_LT(0U, block1); | 227 EXPECT_LT(0U, block1); |
223 EXPECT_GT(TEST_MEMORY_PAGE, block1); | 228 EXPECT_GT(TEST_MEMORY_PAGE, block1); |
224 | 229 |
225 // This allocation won't fit in same page as previous block. | 230 // This allocation won't fit in same page as previous block. |
226 Reference block2 = | 231 Reference block2 = |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
298 t4.Join(); | 303 t4.Join(); |
299 t5.Join(); | 304 t5.Join(); |
300 | 305 |
301 EXPECT_FALSE(allocator_->IsCorrupt()); | 306 EXPECT_FALSE(allocator_->IsCorrupt()); |
302 EXPECT_TRUE(allocator_->IsFull()); | 307 EXPECT_TRUE(allocator_->IsFull()); |
303 EXPECT_EQ(CountIterables(), | 308 EXPECT_EQ(CountIterables(), |
304 t1.iterable() + t2.iterable() + t3.iterable() + t4.iterable() + | 309 t1.iterable() + t2.iterable() + t3.iterable() + t4.iterable() + |
305 t5.iterable()); | 310 t5.iterable()); |
306 } | 311 } |
307 | 312 |
| 313 // A simple thread that counts objects by iterating through an allocator. |
| 314 class CounterThread : public SimpleThread { |
| 315 public: |
| 316 CounterThread(const std::string& name, |
| 317 PersistentMemoryAllocator::Iterator* iterator, |
| 318 Lock* lock, |
| 319 ConditionVariable* condition) |
| 320 : SimpleThread(name, Options()), |
| 321 iterator_(iterator), |
| 322 lock_(lock), |
| 323 condition_(condition), |
| 324 count_(0) {} |
| 325 |
| 326 void Run() override { |
| 327 // Wait so all threads can start at approximately the same time. |
| 328 // Best performance comes from releasing a single worker which then |
| 329 // releases the next, etc., etc. |
| 330 { |
| 331 AutoLock autolock(*lock_); |
| 332 condition_->Wait(); |
| 333 condition_->Signal(); |
| 334 } |
| 335 |
| 336 uint32_t type; |
| 337 while (iterator_->GetNext(&type) != 0) { |
| 338 ++count_; |
| 339 } |
| 340 } |
| 341 |
| 342 unsigned count() { return count_; } |
| 343 |
| 344 private: |
| 345 PersistentMemoryAllocator::Iterator* iterator_; |
| 346 Lock* lock_; |
| 347 ConditionVariable* condition_; |
| 348 unsigned count_; |
| 349 }; |
| 350 |
| 351 // Ensure that parallel iteration returns the same number of objects as |
| 352 // single-threaded iteration. |
| 353 TEST_F(PersistentMemoryAllocatorTest, IteratorParallelismTest) { |
| 354 // Fill the memory segment with random allocations. |
| 355 unsigned iterable_count = 0; |
| 356 for (;;) { |
| 357 uint32_t size = RandInt(1, 99); |
| 358 uint32_t type = RandInt(100, 999); |
| 359 Reference block = allocator_->Allocate(size, type); |
| 360 if (!block) |
| 361 break; |
| 362 allocator_->MakeIterable(block); |
| 363 ++iterable_count; |
| 364 } |
| 365 EXPECT_FALSE(allocator_->IsCorrupt()); |
| 366 EXPECT_TRUE(allocator_->IsFull()); |
| 367 EXPECT_EQ(iterable_count, CountIterables()); |
| 368 |
| 369 PersistentMemoryAllocator::Iterator iter(allocator_.get()); |
| 370 Lock lock; |
| 371 ConditionVariable condition(&lock); |
| 372 |
| 373 CounterThread t1("t1", &iter, &lock, &condition); |
| 374 CounterThread t2("t2", &iter, &lock, &condition); |
| 375 CounterThread t3("t3", &iter, &lock, &condition); |
| 376 CounterThread t4("t4", &iter, &lock, &condition); |
| 377 CounterThread t5("t5", &iter, &lock, &condition); |
| 378 |
| 379 t1.Start(); |
| 380 t2.Start(); |
| 381 t3.Start(); |
| 382 t4.Start(); |
| 383 t5.Start(); |
| 384 |
| 385 // This will release all the waiting threads. |
| 386 condition.Signal(); |
| 387 |
| 388 t1.Join(); |
| 389 t2.Join(); |
| 390 t3.Join(); |
| 391 t4.Join(); |
| 392 t5.Join(); |
| 393 |
| 394 EXPECT_EQ(iterable_count, |
| 395 t1.count() + t2.count() + t3.count() + t4.count() + t5.count()); |
| 396 |
| 397 #if 0 |
| 398 // These ensure that the threads don't run sequentially. It shouldn't be |
| 399 // enabled in general because it could lead to a flaky test if it happens |
| 400 // simply by chance but it is useful during development to ensure that the |
| 401 // test is working correctly. |
| 402 EXPECT_NE(iterable_count, t1.count()); |
| 403 EXPECT_NE(iterable_count, t2.count()); |
| 404 EXPECT_NE(iterable_count, t3.count()); |
| 405 EXPECT_NE(iterable_count, t4.count()); |
| 406 EXPECT_NE(iterable_count, t5.count()); |
| 407 #endif |
| 408 } |
| 409 |
308 // This test doesn't verify anything other than it doesn't crash. Its goal | 410 // This test doesn't verify anything other than it doesn't crash. Its goal |
309 // is to find coding errors that aren't otherwise tested for, much like a | 411 // is to find coding errors that aren't otherwise tested for, much like a |
310 // "fuzzer" would. | 412 // "fuzzer" would. |
311 // This test is suppsoed to fail on TSAN bot (crbug.com/579867). | 413 // This test is suppsoed to fail on TSAN bot (crbug.com/579867). |
312 #if defined(THREAD_SANITIZER) | 414 #if defined(THREAD_SANITIZER) |
313 #define MAYBE_CorruptionTest DISABLED_CorruptionTest | 415 #define MAYBE_CorruptionTest DISABLED_CorruptionTest |
314 #else | 416 #else |
315 #define MAYBE_CorruptionTest CorruptionTest | 417 #define MAYBE_CorruptionTest CorruptionTest |
316 #endif | 418 #endif |
317 TEST_F(PersistentMemoryAllocatorTest, MAYBE_CorruptionTest) { | 419 TEST_F(PersistentMemoryAllocatorTest, MAYBE_CorruptionTest) { |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
420 std::unique_ptr<SharedMemory> shmem2(new SharedMemory(shared_handle, | 522 std::unique_ptr<SharedMemory> shmem2(new SharedMemory(shared_handle, |
421 /*readonly=*/true)); | 523 /*readonly=*/true)); |
422 ASSERT_TRUE(shmem2->Map(TEST_MEMORY_SIZE)); | 524 ASSERT_TRUE(shmem2->Map(TEST_MEMORY_SIZE)); |
423 | 525 |
424 SharedPersistentMemoryAllocator shalloc2(std::move(shmem2), 0, "", true); | 526 SharedPersistentMemoryAllocator shalloc2(std::move(shmem2), 0, "", true); |
425 EXPECT_TRUE(shalloc2.IsReadonly()); | 527 EXPECT_TRUE(shalloc2.IsReadonly()); |
426 EXPECT_EQ(TEST_ID, shalloc2.Id()); | 528 EXPECT_EQ(TEST_ID, shalloc2.Id()); |
427 EXPECT_FALSE(shalloc2.IsFull()); | 529 EXPECT_FALSE(shalloc2.IsFull()); |
428 EXPECT_FALSE(shalloc2.IsCorrupt()); | 530 EXPECT_FALSE(shalloc2.IsCorrupt()); |
429 | 531 |
430 PersistentMemoryAllocator::Iterator iter2; | 532 PersistentMemoryAllocator::Iterator iter2(&shalloc2); |
431 uint32_t type; | 533 uint32_t type; |
432 shalloc2.CreateIterator(&iter2); | 534 EXPECT_EQ(r123, iter2.GetNext(&type)); |
433 EXPECT_EQ(r123, shalloc2.GetNextIterable(&iter2, &type)); | 535 EXPECT_EQ(r789, iter2.GetNext(&type)); |
434 EXPECT_EQ(r789, shalloc2.GetNextIterable(&iter2, &type)); | 536 EXPECT_EQ(0U, iter2.GetNext(&type)); |
435 EXPECT_EQ(0U, shalloc2.GetNextIterable(&iter2, &type)); | |
436 | 537 |
437 EXPECT_EQ(123U, shalloc2.GetType(r123)); | 538 EXPECT_EQ(123U, shalloc2.GetType(r123)); |
438 EXPECT_EQ(654U, shalloc2.GetType(r456)); | 539 EXPECT_EQ(654U, shalloc2.GetType(r456)); |
439 EXPECT_EQ(789U, shalloc2.GetType(r789)); | 540 EXPECT_EQ(789U, shalloc2.GetType(r789)); |
440 | 541 |
441 PersistentMemoryAllocator::MemoryInfo meminfo2; | 542 PersistentMemoryAllocator::MemoryInfo meminfo2; |
442 shalloc2.GetMemoryInfo(&meminfo2); | 543 shalloc2.GetMemoryInfo(&meminfo2); |
443 EXPECT_EQ(meminfo1.total, meminfo2.total); | 544 EXPECT_EQ(meminfo1.total, meminfo2.total); |
444 EXPECT_EQ(meminfo1.free, meminfo2.free); | 545 EXPECT_EQ(meminfo1.free, meminfo2.free); |
445 | 546 |
446 // Read/write test. | 547 // Read/write test. |
447 std::unique_ptr<SharedMemory> shmem3(new SharedMemory(shared_handle, | 548 std::unique_ptr<SharedMemory> shmem3(new SharedMemory(shared_handle, |
448 /*readonly=*/false)); | 549 /*readonly=*/false)); |
449 ASSERT_TRUE(shmem3->Map(TEST_MEMORY_SIZE)); | 550 ASSERT_TRUE(shmem3->Map(TEST_MEMORY_SIZE)); |
450 | 551 |
451 SharedPersistentMemoryAllocator shalloc3(std::move(shmem3), 0, "", false); | 552 SharedPersistentMemoryAllocator shalloc3(std::move(shmem3), 0, "", false); |
452 EXPECT_FALSE(shalloc3.IsReadonly()); | 553 EXPECT_FALSE(shalloc3.IsReadonly()); |
453 EXPECT_EQ(TEST_ID, shalloc3.Id()); | 554 EXPECT_EQ(TEST_ID, shalloc3.Id()); |
454 EXPECT_FALSE(shalloc3.IsFull()); | 555 EXPECT_FALSE(shalloc3.IsFull()); |
455 EXPECT_FALSE(shalloc3.IsCorrupt()); | 556 EXPECT_FALSE(shalloc3.IsCorrupt()); |
456 | 557 |
457 PersistentMemoryAllocator::Iterator iter3; | 558 PersistentMemoryAllocator::Iterator iter3(&shalloc3); |
458 shalloc3.CreateIterator(&iter3); | 559 EXPECT_EQ(r123, iter3.GetNext(&type)); |
459 EXPECT_EQ(r123, shalloc3.GetNextIterable(&iter3, &type)); | 560 EXPECT_EQ(r789, iter3.GetNext(&type)); |
460 EXPECT_EQ(r789, shalloc3.GetNextIterable(&iter3, &type)); | 561 EXPECT_EQ(0U, iter3.GetNext(&type)); |
461 EXPECT_EQ(0U, shalloc3.GetNextIterable(&iter3, &type)); | |
462 | 562 |
463 EXPECT_EQ(123U, shalloc3.GetType(r123)); | 563 EXPECT_EQ(123U, shalloc3.GetType(r123)); |
464 EXPECT_EQ(654U, shalloc3.GetType(r456)); | 564 EXPECT_EQ(654U, shalloc3.GetType(r456)); |
465 EXPECT_EQ(789U, shalloc3.GetType(r789)); | 565 EXPECT_EQ(789U, shalloc3.GetType(r789)); |
466 | 566 |
467 PersistentMemoryAllocator::MemoryInfo meminfo3; | 567 PersistentMemoryAllocator::MemoryInfo meminfo3; |
468 shalloc3.GetMemoryInfo(&meminfo3); | 568 shalloc3.GetMemoryInfo(&meminfo3); |
469 EXPECT_EQ(meminfo1.total, meminfo3.total); | 569 EXPECT_EQ(meminfo1.total, meminfo3.total); |
470 EXPECT_EQ(meminfo1.free, meminfo3.free); | 570 EXPECT_EQ(meminfo1.free, meminfo3.free); |
471 | 571 |
472 // Interconnectivity test. | 572 // Interconnectivity test. |
473 Reference obj = shalloc3.Allocate(42, 42); | 573 Reference obj = shalloc3.Allocate(42, 42); |
474 ASSERT_TRUE(obj); | 574 ASSERT_TRUE(obj); |
475 shalloc3.MakeIterable(obj); | 575 shalloc3.MakeIterable(obj); |
476 EXPECT_EQ(obj, shalloc2.GetNextIterable(&iter2, &type)); | 576 EXPECT_EQ(obj, iter2.GetNext(&type)); |
477 EXPECT_EQ(42U, type); | 577 EXPECT_EQ(42U, type); |
478 } | 578 } |
479 | 579 |
480 | 580 |
481 //----- FilePersistentMemoryAllocator ------------------------------------------ | 581 //----- FilePersistentMemoryAllocator ------------------------------------------ |
482 | 582 |
483 TEST(FilePersistentMemoryAllocatorTest, CreationTest) { | 583 TEST(FilePersistentMemoryAllocatorTest, CreationTest) { |
484 ScopedTempDir temp_dir; | 584 ScopedTempDir temp_dir; |
485 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | 585 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
486 FilePath file_path = temp_dir.path().AppendASCII("persistent_memory"); | 586 FilePath file_path = temp_dir.path().AppendASCII("persistent_memory"); |
(...skipping 23 matching lines...) Expand all Loading... |
510 EXPECT_TRUE(mmfile->IsValid()); | 610 EXPECT_TRUE(mmfile->IsValid()); |
511 const size_t mmlength = mmfile->length(); | 611 const size_t mmlength = mmfile->length(); |
512 EXPECT_GE(meminfo1.total, mmlength); | 612 EXPECT_GE(meminfo1.total, mmlength); |
513 | 613 |
514 FilePersistentMemoryAllocator file(std::move(mmfile), 0, ""); | 614 FilePersistentMemoryAllocator file(std::move(mmfile), 0, ""); |
515 EXPECT_TRUE(file.IsReadonly()); | 615 EXPECT_TRUE(file.IsReadonly()); |
516 EXPECT_EQ(TEST_ID, file.Id()); | 616 EXPECT_EQ(TEST_ID, file.Id()); |
517 EXPECT_FALSE(file.IsFull()); | 617 EXPECT_FALSE(file.IsFull()); |
518 EXPECT_FALSE(file.IsCorrupt()); | 618 EXPECT_FALSE(file.IsCorrupt()); |
519 | 619 |
520 PersistentMemoryAllocator::Iterator iter; | 620 PersistentMemoryAllocator::Iterator iter(&file); |
521 uint32_t type; | 621 uint32_t type; |
522 file.CreateIterator(&iter); | 622 EXPECT_EQ(r123, iter.GetNext(&type)); |
523 EXPECT_EQ(r123, file.GetNextIterable(&iter, &type)); | 623 EXPECT_EQ(r789, iter.GetNext(&type)); |
524 EXPECT_EQ(r789, file.GetNextIterable(&iter, &type)); | 624 EXPECT_EQ(0U, iter.GetNext(&type)); |
525 EXPECT_EQ(0U, file.GetNextIterable(&iter, &type)); | |
526 | 625 |
527 EXPECT_EQ(123U, file.GetType(r123)); | 626 EXPECT_EQ(123U, file.GetType(r123)); |
528 EXPECT_EQ(654U, file.GetType(r456)); | 627 EXPECT_EQ(654U, file.GetType(r456)); |
529 EXPECT_EQ(789U, file.GetType(r789)); | 628 EXPECT_EQ(789U, file.GetType(r789)); |
530 | 629 |
531 PersistentMemoryAllocator::MemoryInfo meminfo2; | 630 PersistentMemoryAllocator::MemoryInfo meminfo2; |
532 file.GetMemoryInfo(&meminfo2); | 631 file.GetMemoryInfo(&meminfo2); |
533 EXPECT_GE(meminfo1.total, meminfo2.total); | 632 EXPECT_GE(meminfo1.total, meminfo2.total); |
534 EXPECT_GE(meminfo1.free, meminfo2.free); | 633 EXPECT_GE(meminfo1.free, meminfo2.free); |
535 EXPECT_EQ(mmlength, meminfo2.total); | 634 EXPECT_EQ(mmlength, meminfo2.total); |
536 EXPECT_EQ(0U, meminfo2.free); | 635 EXPECT_EQ(0U, meminfo2.free); |
537 } | 636 } |
538 | 637 |
539 TEST(FilePersistentMemoryAllocatorTest, AcceptableTest) { | 638 TEST(FilePersistentMemoryAllocatorTest, AcceptableTest) { |
540 ScopedTempDir temp_dir; | 639 ScopedTempDir temp_dir; |
541 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | 640 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
542 FilePath file_path_base = temp_dir.path().AppendASCII("persistent_memory_"); | 641 FilePath file_path_base = temp_dir.path().AppendASCII("persistent_memory_"); |
543 | 642 |
544 LocalPersistentMemoryAllocator local(TEST_MEMORY_SIZE, TEST_ID, ""); | 643 LocalPersistentMemoryAllocator local(TEST_MEMORY_SIZE, TEST_ID, ""); |
545 local.Allocate(1, 1); | 644 local.MakeIterable(local.Allocate(1, 1)); |
546 local.Allocate(11, 11); | 645 local.MakeIterable(local.Allocate(11, 11)); |
547 const size_t minsize = local.used(); | 646 const size_t minsize = local.used(); |
548 std::unique_ptr<char[]> garbage(new char[minsize]); | 647 std::unique_ptr<char[]> garbage(new char[minsize]); |
549 RandBytes(garbage.get(), minsize); | 648 RandBytes(garbage.get(), minsize); |
550 | 649 |
551 std::unique_ptr<MemoryMappedFile> mmfile; | 650 std::unique_ptr<MemoryMappedFile> mmfile; |
552 char filename[100]; | 651 char filename[100]; |
553 for (size_t filesize = minsize; filesize > 0; --filesize) { | 652 for (size_t filesize = minsize; filesize > 0; --filesize) { |
554 strings::SafeSPrintf(filename, "memory_%d_A", filesize); | 653 strings::SafeSPrintf(filename, "memory_%d_A", filesize); |
555 FilePath file_path = temp_dir.path().AppendASCII(filename); | 654 FilePath file_path = temp_dir.path().AppendASCII(filename); |
556 ASSERT_FALSE(PathExists(file_path)); | 655 ASSERT_FALSE(PathExists(file_path)); |
557 { | 656 { |
558 File writer(file_path, File::FLAG_CREATE | File::FLAG_WRITE); | 657 File writer(file_path, File::FLAG_CREATE | File::FLAG_WRITE); |
559 ASSERT_TRUE(writer.IsValid()); | 658 ASSERT_TRUE(writer.IsValid()); |
560 writer.Write(0, (const char*)local.data(), filesize); | 659 writer.Write(0, (const char*)local.data(), filesize); |
561 } | 660 } |
562 ASSERT_TRUE(PathExists(file_path)); | 661 ASSERT_TRUE(PathExists(file_path)); |
563 | 662 |
564 mmfile.reset(new MemoryMappedFile()); | 663 mmfile.reset(new MemoryMappedFile()); |
565 mmfile->Initialize(file_path); | 664 mmfile->Initialize(file_path); |
566 EXPECT_EQ(filesize, mmfile->length()); | 665 EXPECT_EQ(filesize, mmfile->length()); |
567 if (FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile)) { | 666 if (FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile)) { |
568 // Make sure construction doesn't crash. It will, however, cause | 667 // Make sure construction doesn't crash. It will, however, cause |
569 // error messages warning about about a corrupted memory segment. | 668 // error messages warning about about a corrupted memory segment. |
570 FilePersistentMemoryAllocator allocator(std::move(mmfile), 0, ""); | 669 FilePersistentMemoryAllocator allocator(std::move(mmfile), 0, ""); |
571 // Also make sure that iteration doesn't crash. | 670 // Also make sure that iteration doesn't crash. |
572 PersistentMemoryAllocator::Iterator iter; | 671 PersistentMemoryAllocator::Iterator iter(&allocator); |
573 allocator.CreateIterator(&iter); | 672 uint32_t type_id; |
574 for (;;) { | 673 Reference ref; |
575 Reference ref = allocator.GetNextIterable(&iter, 0); | 674 while ((ref = iter.GetNext(&type_id)) != 0) { |
576 if (!ref) | |
577 break; | |
578 const char* data = allocator.GetAsObject<char>(ref, 0); | 675 const char* data = allocator.GetAsObject<char>(ref, 0); |
579 uint32_t type = allocator.GetType(ref); | 676 uint32_t type = allocator.GetType(ref); |
580 size_t size = allocator.GetAllocSize(ref); | 677 size_t size = allocator.GetAllocSize(ref); |
581 // Ensure compiler can't optimize-out above variables. | 678 // Ensure compiler can't optimize-out above variables. |
582 (void)data; | 679 (void)data; |
583 (void)type; | 680 (void)type; |
584 (void)size; | 681 (void)size; |
585 // Ensure that corruption-detected flag gets properly set. | |
586 EXPECT_EQ(filesize != minsize, allocator.IsCorrupt()); | |
587 } | 682 } |
| 683 // Ensure that short files are detected as corrupt and full files are not. |
| 684 EXPECT_EQ(filesize != minsize, allocator.IsCorrupt()); |
588 } else { | 685 } else { |
589 // For filesize >= minsize, the file must be acceptable. This | 686 // For filesize >= minsize, the file must be acceptable. This |
590 // else clause (file-not-acceptable) should be reached only if | 687 // else clause (file-not-acceptable) should be reached only if |
591 // filesize < minsize. | 688 // filesize < minsize. |
592 EXPECT_LT(filesize, minsize); | 689 EXPECT_LT(filesize, minsize); |
593 } | 690 } |
594 | 691 |
595 strings::SafeSPrintf(filename, "memory_%d_B", filesize); | 692 strings::SafeSPrintf(filename, "memory_%d_B", filesize); |
596 file_path = temp_dir.path().AppendASCII(filename); | 693 file_path = temp_dir.path().AppendASCII(filename); |
597 ASSERT_FALSE(PathExists(file_path)); | 694 ASSERT_FALSE(PathExists(file_path)); |
(...skipping 15 matching lines...) Expand all Loading... |
613 } else { | 710 } else { |
614 // For filesize >= minsize, the file must be acceptable. This | 711 // For filesize >= minsize, the file must be acceptable. This |
615 // else clause (file-not-acceptable) should be reached only if | 712 // else clause (file-not-acceptable) should be reached only if |
616 // filesize < minsize. | 713 // filesize < minsize. |
617 EXPECT_GT(minsize, filesize); | 714 EXPECT_GT(minsize, filesize); |
618 } | 715 } |
619 } | 716 } |
620 } | 717 } |
621 | 718 |
622 } // namespace base | 719 } // namespace base |
OLD | NEW |