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

Side by Side Diff: base/metrics/persistent_memory_allocator_unittest.cc

Issue 2000523003: Fully support read/write memory-mapped files for persistent memory. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebased Created 4 years, 7 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
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"
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 46
47 struct TestObject2 { 47 struct TestObject2 {
48 int thiis; 48 int thiis;
49 long that; 49 long that;
50 float andthe; 50 float andthe;
51 char other; 51 char other;
52 double thing; 52 double thing;
53 }; 53 };
54 54
55 PersistentMemoryAllocatorTest() { 55 PersistentMemoryAllocatorTest() {
56 kAllocAlignment = PersistentMemoryAllocator::kAllocAlignment; 56 kAllocAlignment = GetAllocAlignment();
57 mem_segment_.reset(new char[TEST_MEMORY_SIZE]); 57 mem_segment_.reset(new char[TEST_MEMORY_SIZE]);
58 } 58 }
59 59
60 void SetUp() override { 60 void SetUp() override {
61 allocator_.reset(); 61 allocator_.reset();
62 ::memset(mem_segment_.get(), 0, TEST_MEMORY_SIZE); 62 ::memset(mem_segment_.get(), 0, TEST_MEMORY_SIZE);
63 allocator_.reset(new PersistentMemoryAllocator( 63 allocator_.reset(new PersistentMemoryAllocator(
64 mem_segment_.get(), TEST_MEMORY_SIZE, TEST_MEMORY_PAGE, 64 mem_segment_.get(), TEST_MEMORY_SIZE, TEST_MEMORY_PAGE,
65 TEST_ID, TEST_NAME, false)); 65 TEST_ID, TEST_NAME, false));
66 allocator_->CreateTrackingHistograms(allocator_->Name()); 66 allocator_->CreateTrackingHistograms(allocator_->Name());
67 } 67 }
68 68
69 void TearDown() override { 69 void TearDown() override {
70 allocator_.reset(); 70 allocator_.reset();
71 } 71 }
72 72
73 unsigned CountIterables() { 73 unsigned CountIterables() {
74 PersistentMemoryAllocator::Iterator iter(allocator_.get()); 74 PersistentMemoryAllocator::Iterator iter(allocator_.get());
75 uint32_t type; 75 uint32_t type;
76 unsigned count = 0; 76 unsigned count = 0;
77 while (iter.GetNext(&type) != 0) { 77 while (iter.GetNext(&type) != 0) {
78 ++count; 78 ++count;
79 } 79 }
80 return count; 80 return count;
81 } 81 }
82 82
83 static uint32_t GetAllocAlignment() {
84 return PersistentMemoryAllocator::kAllocAlignment;
85 }
86
83 protected: 87 protected:
84 std::unique_ptr<char[]> mem_segment_; 88 std::unique_ptr<char[]> mem_segment_;
85 std::unique_ptr<PersistentMemoryAllocator> allocator_; 89 std::unique_ptr<PersistentMemoryAllocator> allocator_;
86 }; 90 };
87 91
88 TEST_F(PersistentMemoryAllocatorTest, AllocateAndIterate) { 92 TEST_F(PersistentMemoryAllocatorTest, AllocateAndIterate) {
89 std::string base_name(TEST_NAME); 93 std::string base_name(TEST_NAME);
90 EXPECT_EQ(TEST_ID, allocator_->Id()); 94 EXPECT_EQ(TEST_ID, allocator_->Id());
91 EXPECT_TRUE(allocator_->used_histogram_); 95 EXPECT_TRUE(allocator_->used_histogram_);
92 EXPECT_EQ("UMA.PersistentAllocator." + base_name + ".UsedPct", 96 EXPECT_EQ("UMA.PersistentAllocator." + base_name + ".UsedPct",
(...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after
604 ASSERT_TRUE(writer.IsValid()); 608 ASSERT_TRUE(writer.IsValid());
605 writer.Write(0, (const char*)local.data(), local.used()); 609 writer.Write(0, (const char*)local.data(), local.used());
606 } 610 }
607 611
608 std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile()); 612 std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile());
609 mmfile->Initialize(file_path); 613 mmfile->Initialize(file_path);
610 EXPECT_TRUE(mmfile->IsValid()); 614 EXPECT_TRUE(mmfile->IsValid());
611 const size_t mmlength = mmfile->length(); 615 const size_t mmlength = mmfile->length();
612 EXPECT_GE(meminfo1.total, mmlength); 616 EXPECT_GE(meminfo1.total, mmlength);
613 617
614 FilePersistentMemoryAllocator file(std::move(mmfile), 0, ""); 618 FilePersistentMemoryAllocator file(std::move(mmfile), 0, 0, "", true);
615 EXPECT_TRUE(file.IsReadonly()); 619 EXPECT_TRUE(file.IsReadonly());
616 EXPECT_EQ(TEST_ID, file.Id()); 620 EXPECT_EQ(TEST_ID, file.Id());
617 EXPECT_FALSE(file.IsFull()); 621 EXPECT_FALSE(file.IsFull());
618 EXPECT_FALSE(file.IsCorrupt()); 622 EXPECT_FALSE(file.IsCorrupt());
619 623
620 PersistentMemoryAllocator::Iterator iter(&file); 624 PersistentMemoryAllocator::Iterator iter(&file);
621 uint32_t type; 625 uint32_t type;
622 EXPECT_EQ(r123, iter.GetNext(&type)); 626 EXPECT_EQ(r123, iter.GetNext(&type));
623 EXPECT_EQ(r789, iter.GetNext(&type)); 627 EXPECT_EQ(r789, iter.GetNext(&type));
624 EXPECT_EQ(0U, iter.GetNext(&type)); 628 EXPECT_EQ(0U, iter.GetNext(&type));
625 629
626 EXPECT_EQ(123U, file.GetType(r123)); 630 EXPECT_EQ(123U, file.GetType(r123));
627 EXPECT_EQ(654U, file.GetType(r456)); 631 EXPECT_EQ(654U, file.GetType(r456));
628 EXPECT_EQ(789U, file.GetType(r789)); 632 EXPECT_EQ(789U, file.GetType(r789));
629 633
630 PersistentMemoryAllocator::MemoryInfo meminfo2; 634 PersistentMemoryAllocator::MemoryInfo meminfo2;
631 file.GetMemoryInfo(&meminfo2); 635 file.GetMemoryInfo(&meminfo2);
632 EXPECT_GE(meminfo1.total, meminfo2.total); 636 EXPECT_GE(meminfo1.total, meminfo2.total);
633 EXPECT_GE(meminfo1.free, meminfo2.free); 637 EXPECT_GE(meminfo1.free, meminfo2.free);
634 EXPECT_EQ(mmlength, meminfo2.total); 638 EXPECT_EQ(mmlength, meminfo2.total);
635 EXPECT_EQ(0U, meminfo2.free); 639 EXPECT_EQ(0U, meminfo2.free);
636 } 640 }
637 641
638 TEST(FilePersistentMemoryAllocatorTest, AcceptableTest) { 642 TEST(FilePersistentMemoryAllocatorTest, ExtendTest) {
639 ScopedTempDir temp_dir; 643 ScopedTempDir temp_dir;
640 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 644 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
641 FilePath file_path_base = temp_dir.path().AppendASCII("persistent_memory_"); 645 FilePath file_path = temp_dir.path().AppendASCII("extend_test");
646 MemoryMappedFile::Region region = {0, 16 << 10}; // 16KiB maximum size.
647
648 // Start with a small but valid file of persistent data.
649 ASSERT_FALSE(PathExists(file_path));
650 {
651 LocalPersistentMemoryAllocator local(TEST_MEMORY_SIZE, TEST_ID, "");
652 local.Allocate(1, 1);
653 local.Allocate(11, 11);
654
655 File writer(file_path, File::FLAG_CREATE | File::FLAG_WRITE);
656 ASSERT_TRUE(writer.IsValid());
657 writer.Write(0, (const char*)local.data(), local.used());
658 }
659 ASSERT_TRUE(PathExists(file_path));
660 int64_t before_size;
661 ASSERT_TRUE(GetFileSize(file_path, &before_size));
662
663 // Map it as an extendable read/write file and append to it.
664 {
665 std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile());
666 mmfile->Initialize(
667 File(file_path, File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WRITE),
668 region, MemoryMappedFile::READ_WRITE_EXTEND);
669 FilePersistentMemoryAllocator allocator(std::move(mmfile), region.size, 0,
670 "", false);
671 EXPECT_EQ(static_cast<size_t>(before_size), allocator.used());
672
673 allocator.Allocate(111, 111);
674 EXPECT_LT(static_cast<size_t>(before_size), allocator.used());
675 }
676
677 // Validate that append worked.
678 int64_t after_size;
679 ASSERT_TRUE(GetFileSize(file_path, &after_size));
680 EXPECT_LT(before_size, after_size);
681
682 // Verify that it's still an acceptable file.
683 {
684 std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile());
685 mmfile->Initialize(
686 File(file_path, File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WRITE),
687 region, MemoryMappedFile::READ_WRITE_EXTEND);
688 EXPECT_TRUE(FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, true));
689 EXPECT_TRUE(
690 FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, false));
691 }
692 }
693
694 TEST(FilePersistentMemoryAllocatorTest, AcceptableTest) {
695 const uint32_t kAllocAlignment =
696 PersistentMemoryAllocatorTest::GetAllocAlignment();
697 ScopedTempDir temp_dir;
698 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
642 699
643 LocalPersistentMemoryAllocator local(TEST_MEMORY_SIZE, TEST_ID, ""); 700 LocalPersistentMemoryAllocator local(TEST_MEMORY_SIZE, TEST_ID, "");
644 local.MakeIterable(local.Allocate(1, 1)); 701 local.MakeIterable(local.Allocate(1, 1));
645 local.MakeIterable(local.Allocate(11, 11)); 702 local.MakeIterable(local.Allocate(11, 11));
646 const size_t minsize = local.used(); 703 const size_t minsize = local.used();
647 std::unique_ptr<char[]> garbage(new char[minsize]); 704 std::unique_ptr<char[]> garbage(new char[minsize]);
648 RandBytes(garbage.get(), minsize); 705 RandBytes(garbage.get(), minsize);
649 706
650 std::unique_ptr<MemoryMappedFile> mmfile; 707 std::unique_ptr<MemoryMappedFile> mmfile;
651 char filename[100]; 708 char filename[100];
652 for (size_t filesize = minsize; filesize > 0; --filesize) { 709 for (size_t filesize = minsize; filesize > 0; --filesize) {
653 strings::SafeSPrintf(filename, "memory_%d_A", filesize); 710 strings::SafeSPrintf(filename, "memory_%d_A", filesize);
654 FilePath file_path = temp_dir.path().AppendASCII(filename); 711 FilePath file_path = temp_dir.path().AppendASCII(filename);
655 ASSERT_FALSE(PathExists(file_path)); 712 ASSERT_FALSE(PathExists(file_path));
656 { 713 {
657 File writer(file_path, File::FLAG_CREATE | File::FLAG_WRITE); 714 File writer(file_path, File::FLAG_CREATE | File::FLAG_WRITE);
658 ASSERT_TRUE(writer.IsValid()); 715 ASSERT_TRUE(writer.IsValid());
659 writer.Write(0, (const char*)local.data(), filesize); 716 writer.Write(0, (const char*)local.data(), filesize);
660 } 717 }
661 ASSERT_TRUE(PathExists(file_path)); 718 ASSERT_TRUE(PathExists(file_path));
662 719
720 // Request read/write access for some sizes that are a multple of the
721 // allocator's alignment size. The allocator is strict about file size
722 // being a multiple of its internal alignment when doing read/write access.
723 const bool read_only = (filesize % (2 * kAllocAlignment)) != 0;
724 const uint32_t file_flags =
725 File::FLAG_OPEN | File::FLAG_READ | (read_only ? 0 : File::FLAG_WRITE);
726 const MemoryMappedFile::Access map_access =
727 read_only ? MemoryMappedFile::READ_ONLY : MemoryMappedFile::READ_WRITE;
728
663 mmfile.reset(new MemoryMappedFile()); 729 mmfile.reset(new MemoryMappedFile());
664 mmfile->Initialize(file_path); 730 mmfile->Initialize(File(file_path, file_flags), map_access);
665 EXPECT_EQ(filesize, mmfile->length()); 731 EXPECT_EQ(filesize, mmfile->length());
666 if (FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile)) { 732 if (FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, read_only)) {
667 // Make sure construction doesn't crash. It will, however, cause 733 // Make sure construction doesn't crash. It will, however, cause
668 // error messages warning about about a corrupted memory segment. 734 // error messages warning about about a corrupted memory segment.
669 FilePersistentMemoryAllocator allocator(std::move(mmfile), 0, ""); 735 FilePersistentMemoryAllocator allocator(std::move(mmfile), 0, 0, "",
736 read_only);
670 // Also make sure that iteration doesn't crash. 737 // Also make sure that iteration doesn't crash.
671 PersistentMemoryAllocator::Iterator iter(&allocator); 738 PersistentMemoryAllocator::Iterator iter(&allocator);
672 uint32_t type_id; 739 uint32_t type_id;
673 Reference ref; 740 Reference ref;
674 while ((ref = iter.GetNext(&type_id)) != 0) { 741 while ((ref = iter.GetNext(&type_id)) != 0) {
675 const char* data = allocator.GetAsObject<char>(ref, 0); 742 const char* data = allocator.GetAsObject<char>(ref, 0);
676 uint32_t type = allocator.GetType(ref); 743 uint32_t type = allocator.GetType(ref);
677 size_t size = allocator.GetAllocSize(ref); 744 size_t size = allocator.GetAllocSize(ref);
678 // Ensure compiler can't optimize-out above variables. 745 // Ensure compiler can't optimize-out above variables.
679 (void)data; 746 (void)data;
680 (void)type; 747 (void)type;
681 (void)size; 748 (void)size;
682 } 749 }
750
683 // Ensure that short files are detected as corrupt and full files are not. 751 // Ensure that short files are detected as corrupt and full files are not.
684 EXPECT_EQ(filesize != minsize, allocator.IsCorrupt()); 752 EXPECT_EQ(filesize != minsize, allocator.IsCorrupt());
685 } else { 753 } else {
686 // For filesize >= minsize, the file must be acceptable. This 754 // For filesize >= minsize, the file must be acceptable. This
687 // else clause (file-not-acceptable) should be reached only if 755 // else clause (file-not-acceptable) should be reached only if
688 // filesize < minsize. 756 // filesize < minsize.
689 EXPECT_LT(filesize, minsize); 757 EXPECT_LT(filesize, minsize);
690 } 758 }
691 759
692 strings::SafeSPrintf(filename, "memory_%d_B", filesize); 760 strings::SafeSPrintf(filename, "memory_%d_B", filesize);
693 file_path = temp_dir.path().AppendASCII(filename); 761 file_path = temp_dir.path().AppendASCII(filename);
694 ASSERT_FALSE(PathExists(file_path)); 762 ASSERT_FALSE(PathExists(file_path));
695 { 763 {
696 File writer(file_path, File::FLAG_CREATE | File::FLAG_WRITE); 764 File writer(file_path, File::FLAG_CREATE | File::FLAG_WRITE);
697 ASSERT_TRUE(writer.IsValid()); 765 ASSERT_TRUE(writer.IsValid());
698 writer.Write(0, (const char*)garbage.get(), filesize); 766 writer.Write(0, (const char*)garbage.get(), filesize);
699 } 767 }
700 ASSERT_TRUE(PathExists(file_path)); 768 ASSERT_TRUE(PathExists(file_path));
701 769
702 mmfile.reset(new MemoryMappedFile()); 770 mmfile.reset(new MemoryMappedFile());
703 mmfile->Initialize(file_path); 771 mmfile->Initialize(File(file_path, file_flags), map_access);
704 EXPECT_EQ(filesize, mmfile->length()); 772 EXPECT_EQ(filesize, mmfile->length());
705 if (FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile)) { 773 if (FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, read_only)) {
706 // Make sure construction doesn't crash. It will, however, cause 774 // Make sure construction doesn't crash. It will, however, cause
707 // error messages warning about about a corrupted memory segment. 775 // error messages warning about about a corrupted memory segment.
708 FilePersistentMemoryAllocator allocator(std::move(mmfile), 0, ""); 776 FilePersistentMemoryAllocator allocator(std::move(mmfile), 0, 0, "",
777 read_only);
709 EXPECT_TRUE(allocator.IsCorrupt()); // Garbage data so it should be. 778 EXPECT_TRUE(allocator.IsCorrupt()); // Garbage data so it should be.
710 } else { 779 } else {
711 // For filesize >= minsize, the file must be acceptable. This 780 // For filesize >= minsize, the file must be acceptable. This
712 // else clause (file-not-acceptable) should be reached only if 781 // else clause (file-not-acceptable) should be reached only if
713 // filesize < minsize. 782 // filesize < minsize.
714 EXPECT_GT(minsize, filesize); 783 EXPECT_GT(minsize, filesize);
715 } 784 }
716 } 785 }
717 } 786 }
718 787
719 } // namespace base 788 } // namespace base
OLDNEW
« no previous file with comments | « base/metrics/persistent_memory_allocator.cc ('k') | components/metrics/file_metrics_provider.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698