blob: 3d92f66049d2d7beef0f82e08e9824cdba86fd22 [file] [log] [blame]
#include "huge_page_deducer.h"
#include "base/logging.h"
#include "compat/string.h"
#include "compat/test.h"
namespace quipper {
namespace {
using PerfEvent = PerfDataProto::PerfEvent;
using MMapEvent = PerfDataProto::MMapEvent;
using ::testing::EqualsProto;
using ::testing::Pointwise;
using ::testing::proto::Partially;
// AddMmap is a helper function to create simple MMapEvents, with which
// testcases can encode "maps" entries similar to /proc/self/maps in a tabular
// one-line-per-entry.
void AddMmap(uint32_t pid, uint64_t mmap_start, uint64_t length, uint64_t pgoff,
const string& file, RepeatedPtrField<PerfEvent>* events) {
MMapEvent* ev = events->Add()->mutable_mmap_event();
ev->set_pid(pid);
ev->set_start(mmap_start);
ev->set_len(length);
ev->set_pgoff(pgoff);
ev->set_filename(file);
}
TEST(HugePageDeducer, HugePagesMappings) {
RepeatedPtrField<PerfEvent> events;
{
MMapEvent* ev = events.Add()->mutable_mmap_event();
ev->set_pid(1234);
ev->set_start(0x40000000);
ev->set_len(0x18000);
ev->set_pgoff(0);
ev->set_filename("/usr/lib/libfoo.so");
}
{
MMapEvent* ev = events.Add()->mutable_mmap_event();
ev->set_pid(1234);
ev->set_start(0x40018000);
ev->set_len(0x1e8000);
ev->set_pgoff(0);
ev->set_filename("/opt/google/chrome/chrome");
}
{
MMapEvent* ev = events.Add()->mutable_mmap_event();
ev->set_pid(1234);
ev->set_start(0x40200000);
ev->set_len(0x1c00000);
ev->set_pgoff(0);
ev->set_filename("//anon");
}
{
MMapEvent* ev = events.Add()->mutable_mmap_event();
ev->set_pid(1234);
ev->set_start(0x41e00000);
ev->set_len(0x4000000);
ev->set_pgoff(0x1de8000);
ev->set_filename("/opt/google/chrome/chrome");
}
{
MMapEvent* ev = events.Add()->mutable_mmap_event();
ev->set_pid(2345);
ev->set_start(0x45e00000);
ev->set_len(0x1e00000);
ev->set_pgoff(0);
ev->set_filename("//anon");
}
{
MMapEvent* ev = events.Add()->mutable_mmap_event();
ev->set_pid(2345);
ev->set_start(0x47c00000);
ev->set_len(0x4000000);
ev->set_pgoff(0x1e00000);
ev->set_filename("/opt/google/chrome/chrome");
}
DeduceHugePages(&events);
CombineMappings(&events);
ASSERT_GE(events.size(), 3);
EXPECT_EQ(events.size(), 3);
EXPECT_THAT(events,
Pointwise(Partially(EqualsProto()),
{
"mmap_event: { start: 0x40000000 len:0x18000 "
"pgoff: 0 filename: '/usr/lib/libfoo.so'}",
"mmap_event: { start: 0x40018000 len:0x5de8000 "
"pgoff: 0 filename: '/opt/google/chrome/chrome'}",
"mmap_event: { start: 0x45e00000 len:0x5e00000 "
"pgoff: 0 filename: '/opt/google/chrome/chrome'}",
}));
EXPECT_EQ("/usr/lib/libfoo.so", events[0].mmap_event().filename());
EXPECT_EQ(0x40000000, events[0].mmap_event().start());
EXPECT_EQ(0x18000, events[0].mmap_event().len());
EXPECT_EQ(0x0, events[0].mmap_event().pgoff());
// The split Chrome mappings should have been combined.
EXPECT_EQ("/opt/google/chrome/chrome", events[2].mmap_event().filename());
EXPECT_EQ(0x40018000, events[1].mmap_event().start());
EXPECT_EQ(0x5de8000, events[1].mmap_event().len());
EXPECT_EQ(0x0, events[1].mmap_event().pgoff());
EXPECT_EQ("/opt/google/chrome/chrome", events[2].mmap_event().filename());
EXPECT_EQ(0x45e00000, events[2].mmap_event().start());
EXPECT_EQ(0x5e00000, events[2].mmap_event().len());
EXPECT_EQ(0x0, events[2].mmap_event().pgoff());
}
enum HugepageTextStyle {
kAnonHugepageText,
kNoHugepageText,
};
class HugepageTextStyleDependent
: public ::testing::TestWithParam<HugepageTextStyle> {
protected:
void AddHugepageTextMmap(uint32_t pid, uint64_t mmap_start, uint64_t length,
uint64_t pgoff, string file,
RepeatedPtrField<PerfEvent>* events) {
// Various hugepage implementations and perf versions result in various
// quirks in how hugepages are reported.
switch (GetParam()) {
case kNoHugepageText:
// Do nothing; the maps are complete and file-backed
break;
case kAnonHugepageText:
// exec is remapped into anonymous memory, which perf reports as
// '//anon'. Anonymous sections have no pgoff.
file = "//anon";
pgoff = 0;
break;
default:
CHECK(false) << "Unimplemented";
}
AddMmap(pid, mmap_start, length, pgoff, file, events);
}
};
TEST_P(HugepageTextStyleDependent, OnlyOneMappingThatIsHuge) {
RepeatedPtrField<PerfEvent> events;
AddHugepageTextMmap(1, 0x100200000, 0x200000, 0, "file", &events);
DeduceHugePages(&events);
CombineMappings(&events);
// Don't check filename='file'; if it's backed by anonymous memory, it isn't
// possible for quipper to deduce the filename without other mmaps immediately
// adjacent.
EXPECT_THAT(
events,
Pointwise(Partially(EqualsProto()),
{"mmap_event: { start: 0x100200000 len: 0x200000 pgoff: 0}"}));
}
TEST_P(HugepageTextStyleDependent, OnlyOneMappingUnaligned) {
RepeatedPtrField<PerfEvent> events;
AddMmap(2, 0x200201000, 0x200000, 0, "file", &events);
DeduceHugePages(&events);
CombineMappings(&events);
EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
{"mmap_event: { start: 0x200201000 "
"len:0x200000 pgoff: 0 filename: 'file'}"}));
}
TEST_P(HugepageTextStyleDependent, FirstPageIsHugeWithSmallTail) {
RepeatedPtrField<PerfEvent> events;
AddHugepageTextMmap(3, 0x300400000, 0x400000, 0, "file", &events);
AddMmap(3, 0x300800000, 0x001000, 0x400000, "file", &events);
DeduceHugePages(&events);
CombineMappings(&events);
EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
{"mmap_event: { start: 0x300400000 "
"len:0x401000 pgoff: 0 filename: 'file'}"}));
}
TEST_P(HugepageTextStyleDependent, DISABLED_FirstPageIsSmallWithHugeTail) {
// This test is disabled because DeduceHugePage requires a non-zero pgoff
// *after* a hugepage_text section in order to correctly deduce it, so it
// is unable to deduce these cases.
RepeatedPtrField<PerfEvent> events;
AddMmap(4, 0x4003ff000, 0x001000, 0, "file", &events);
AddHugepageTextMmap(4, 0x400400000, 0x200000, 0x001000, "file", &events);
DeduceHugePages(&events);
CombineMappings(&events);
EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
{"mmap_event: { start: 0x4003ff000 "
"len:0x201000 pgoff: 0 filename: 'file'}"}));
}
TEST_P(HugepageTextStyleDependent, HugePageBetweenTwoSmallSections) {
RepeatedPtrField<PerfEvent> events;
AddMmap(5, 0x5003ff000, 0x001000, 0, "file", &events);
AddHugepageTextMmap(5, 0x500400000, 0x200000, 0x001000, "file", &events);
AddMmap(5, 0x500600000, 0x001000, 0x201000, "file", &events);
DeduceHugePages(&events);
CombineMappings(&events);
EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
{"mmap_event: { start: 0x5003ff000 "
"len:0x202000 pgoff: 0 filename: 'file'}"}));
}
TEST_P(HugepageTextStyleDependent, HugePageSplitByEarlyMlockBetweenTwoSmall) {
RepeatedPtrField<PerfEvent> events;
AddMmap(6, 0x6003ff000, 0x001000, 0, "file", &events);
AddHugepageTextMmap(6, 0x600400000, 0x3f8000, 0x001000, "file", &events);
AddHugepageTextMmap(6, 0x6007f8000, 0x008000, 0x3f9000, "file", &events);
AddMmap(6, 0x600800000, 0x001000, 0x401000, "file", &events);
DeduceHugePages(&events);
CombineMappings(&events);
EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
{"mmap_event: { start: 0x6003ff000 "
"len:0x402000 pgoff: 0 filename: 'file'}"}));
}
TEST_P(HugepageTextStyleDependent, HugePageSplitByLateMlockBetweenTwoSmall) {
RepeatedPtrField<PerfEvent> events;
AddMmap(7, 0x7003ff000, 0x001000, 0, "file", &events);
AddHugepageTextMmap(7, 0x700400000, 0x008000, 0x001000, "file", &events);
AddHugepageTextMmap(7, 0x700408000, 0x3f8000, 0x009000, "file", &events);
AddMmap(7, 0x700800000, 0x001000, 0x401000, "file", &events);
DeduceHugePages(&events);
CombineMappings(&events);
EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
{"mmap_event: { start: 0x7003ff000 "
"len:0x402000 pgoff: 0 filename: 'file'}"}));
}
TEST_P(HugepageTextStyleDependent, HugePageSplitEvenlyByMlockBetweenTwoSmall) {
RepeatedPtrField<PerfEvent> events;
AddMmap(8, 0x8003ff000, 0x001000, 0, "file", &events);
AddHugepageTextMmap(8, 0x800400000, 0x0f8000, 0x001000, "file", &events);
AddHugepageTextMmap(8, 0x8004f8000, 0x008000, 0x0f9000, "file", &events);
AddHugepageTextMmap(8, 0x800500000, 0x100000, 0x101000, "file", &events);
AddMmap(8, 0x800600000, 0x001000, 0x201000, "file", &events);
DeduceHugePages(&events);
CombineMappings(&events);
EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
{"mmap_event: { start: 0x8003ff000 "
"len:0x202000 pgoff: 0 filename: 'file'}"}));
}
TEST_P(HugepageTextStyleDependent, MultipleContiguousHugepages) {
RepeatedPtrField<PerfEvent> events;
AddMmap(9, 0x9003ff000, 0x001000, 0, "file", &events);
AddHugepageTextMmap(9, 0x900400000, 0x200000, 0x001000, "file", &events);
AddHugepageTextMmap(9, 0x900600000, 0x200000, 0x201000, "file", &events);
AddMmap(9, 0x900800000, 0x001000, 0x401000, "file", &events);
DeduceHugePages(&events);
CombineMappings(&events);
EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
{"mmap_event: { start: 0x9003ff000 "
"len:0x402000 pgoff: 0 filename: 'file'}"}));
}
TEST_P(HugepageTextStyleDependent, MultipleContiguousMlockSplitHugepages) {
// Think:
// - hugepage_text 4MiB range
// - mlock alternating 512-KiB chunks
RepeatedPtrField<PerfEvent> events;
AddMmap(10, 0xa003ff000, 0x001000, 0, "file", &events);
AddHugepageTextMmap(10, 0xa00400000, 0x080000, 0x001000, "file", &events);
AddHugepageTextMmap(10, 0xa00480000, 0x080000, 0x081000, "file", &events);
AddHugepageTextMmap(10, 0xa00500000, 0x080000, 0x101000, "file", &events);
AddHugepageTextMmap(10, 0xa00580000, 0x080000, 0x181000, "file", &events);
AddHugepageTextMmap(10, 0xa00600000, 0x080000, 0x201000, "file", &events);
AddHugepageTextMmap(10, 0xa00680000, 0x080000, 0x281000, "file", &events);
AddHugepageTextMmap(10, 0xa00700000, 0x080000, 0x301000, "file", &events);
AddHugepageTextMmap(10, 0xa00780000, 0x080000, 0x381000, "file", &events);
AddMmap(10, 0xa00800000, 0x001000, 0x401000, "file", &events);
DeduceHugePages(&events);
CombineMappings(&events);
EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
{"mmap_event: { start: 0xa003ff000 "
"len:0x402000 pgoff: 0 filename: 'file'}"}));
}
TEST_P(HugepageTextStyleDependent, MultipleWithUnalignedInitialHugePage) {
// Base on real program
RepeatedPtrField<PerfEvent> events;
AddHugepageTextMmap(11, 0x85d32e000, 0x6d2000, 0x0, "file", &events);
AddHugepageTextMmap(11, 0x85da00000, 0x6a00000, 0x6d2000, "file", &events);
AddMmap(11, 0x864400000, 0x200000, 0x70d2000, "file", &events);
AddHugepageTextMmap(11, 0x864600000, 0x200000, 0x72d2000, "file", &events);
AddMmap(11, 0x864800000, 0x600000, 0x74d2000, "file", &events);
AddHugepageTextMmap(11, 0x864e00000, 0x200000, 0x7ad2000, "file", &events);
AddMmap(11, 0x865000000, 0x4a000, 0x7cd2000, "file", &events);
AddMmap(11, 0x86504a000, 0x1000, 0x7d1c000, "file", &events);
AddMmap(11, 0xa3d368000, 0x3a96000, 0x0, "file2", &events);
AddMmap(11, 0xa467cc000, 0x2000, 0x0, "file3", &events);
DeduceHugePages(&events);
CombineMappings(&events);
EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
{
"mmap_event: { start: 0x85d32e000 "
"len:0x7d1d000 pgoff: 0 filename: 'file'}",
"mmap_event: { start: 0xa3d368000 "
"len:0x3a96000 pgoff: 0 filename: 'file2'}",
"mmap_event: { start: 0xa467cc000 "
"len:0x2000, pgoff: 0 filename: 'file3'}",
}));
}
TEST_P(HugepageTextStyleDependent, MultipleWithUnalignedInitialHugePage2) {
// Base on real program
RepeatedPtrField<PerfEvent> events;
AddHugepageTextMmap(12, 0xbcff6000, 0x200000, 0x00000000, "file", &events);
AddMmap(12, 0xbd1f6000, 0x300a000, 0x200000, "file", &events);
AddHugepageTextMmap(12, 0xc0200000, 0x2b374000, 0x320a000, "file", &events);
AddHugepageTextMmap(12, 0xeb574000, 0x514000, 0x2e57e000, "file", &events);
AddHugepageTextMmap(12, 0xeba88000, 0x1d78000, 0x2ea92000, "file", &events);
AddMmap(12, 0xed800000, 0x1200000, 0x3080a000, "file", &events);
AddHugepageTextMmap(12, 0xeea00000, 0x200000, 0x31a0a000, "file", &events);
AddMmap(12, 0xeec00000, 0x2800000, 0x31c0a000, "file", &events);
AddHugepageTextMmap(12, 0xf1400000, 0x200000, 0x3440a000, "file", &events);
AddMmap(12, 0xf1600000, 0x89f000, 0x3460a000, "file", &events);
AddMmap(12, 0xf1e9f000, 0x1000, 0x34ea9000, "file", &events);
DeduceHugePages(&events);
CombineMappings(&events);
EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
{"mmap_event: { start: 0xbcff6000 "
"len:0x34eaa000 pgoff: 0 filename: 'file'}"}));
}
TEST_P(HugepageTextStyleDependent, NoMmaps) {
RepeatedPtrField<PerfEvent> events;
events.Add();
DeduceHugePages(&events);
CombineMappings(&events);
EXPECT_THAT(events, Pointwise(EqualsProto(), std::vector<PerfEvent>(1)));
}
TEST_P(HugepageTextStyleDependent, MultipleNonMmaps) {
RepeatedPtrField<PerfEvent> events;
events.Add();
events.Add();
DeduceHugePages(&events);
CombineMappings(&events);
EXPECT_THAT(events, Pointwise(EqualsProto(), std::vector<PerfEvent>(2)));
}
TEST_P(HugepageTextStyleDependent, NonMmapFirstMmap) {
RepeatedPtrField<PerfEvent> events;
events.Add();
AddHugepageTextMmap(12, 0, 0x200000, 0, "file", &events);
DeduceHugePages(&events);
CombineMappings(&events);
EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
{"", "mmap_event: { pgoff: 0 }"}));
}
TEST_P(HugepageTextStyleDependent, NonMmapAfterLastMmap) {
RepeatedPtrField<PerfEvent> events;
AddHugepageTextMmap(12, 0, 0x200000, 0, "file", &events);
events.Add();
DeduceHugePages(&events);
CombineMappings(&events);
EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
{"mmap_event: { pgoff: 0 }", ""}));
}
INSTANTIATE_TEST_CASE_P(NoHugepageText, HugepageTextStyleDependent,
::testing::Values(kNoHugepageText));
INSTANTIATE_TEST_CASE_P(AnonHugepageText, HugepageTextStyleDependent,
::testing::Values(kAnonHugepageText));
TEST(HugePageDeducer, DoesNotChangeVirtuallyContiguousPgoffNonContiguous) {
// We've seen programs with strange memory layouts having virtually contiguous
// memory backed by non-contiguous bits of a file.
RepeatedPtrField<PerfEvent> events;
AddMmap(758463, 0x2f278000, 0x20000, 0, "lib0.so", &events);
AddMmap(758463, 0x2f29d000, 0x2000, 0, "shm", &events);
AddMmap(758463, 0x2f2a2000, 0xa000, 0, "lib1.so", &events);
AddMmap(758463, 0x3d400000, 0x9ee000, 0, "lib2.so", &events);
AddMmap(758463, 0x3e000000, 0x16000, 0, "lib3.so", &events);
AddMmap(758463, 0x3e400000, 0x270000, 0x1a00000, "shm", &events);
AddMmap(758463, 0x3e670000, 0x10000, 0x1aaac000, "shm", &events);
AddMmap(758463, 0x3e680000, 0x10000, 0x1b410000, "shm", &events);
DeduceHugePages(&events);
CombineMappings(&events);
EXPECT_THAT(events,
Pointwise(Partially(EqualsProto()),
{
"mmap_event: { pgoff: 0 filename: 'lib0.so' }",
"mmap_event: { pgoff: 0 filename: 'shm' }",
"mmap_event: { pgoff: 0 filename: 'lib1.so' }",
"mmap_event: { pgoff: 0 filename: 'lib2.so' }",
"mmap_event: { pgoff: 0 filename: 'lib3.so' }",
"mmap_event: { pgoff: 0x1a00000 filename: 'shm' }",
"mmap_event: { pgoff: 0x1aaac000 filename: 'shm' }",
"mmap_event: { pgoff: 0x1b410000 filename: 'shm' }",
}));
}
TEST(HugePageDeducer, IgnoresDynamicMmaps) {
// Now, let's watch a binary hugepage_text itself.
RepeatedPtrField<PerfEvent> events;
AddMmap(6531, 0x560d76b25000, 0x24ce000, 0, "main", &events);
events.rbegin()->set_timestamp(700413232676401);
AddMmap(6531, 0x7f686a1ec000, 0x24000, 0, "ld.so", &events);
events.rbegin()->set_timestamp(700413232691935);
AddMmap(6531, 0x7ffea5dc8000, 0x2000, 0, "[vdso]", &events);
events.rbegin()->set_timestamp(700413232701418);
AddMmap(6531, 0x7f686a1e3000, 0x5000, 0, "lib1.so", &events);
events.rbegin()->set_timestamp(700413232824216);
AddMmap(6531, 0x7f686a1a8000, 0x3a000, 0, "lib2.so", &events);
events.rbegin()->set_timestamp(700413232854520);
AddMmap(6531, 0x7f6869ea7000, 0x5000, 0, "lib3.so", &events);
events.rbegin()->set_timestamp(700413248827794);
AddMmap(6531, 0x7f6867e00000, 0x200000, 0, "/anon_hugepage (deleted)",
&events);
events.rbegin()->set_timestamp(700413295816043);
AddMmap(6531, 0x7f6867c00000, 0x200000, 0, "/anon_hugepage (deleted)",
&events);
events.rbegin()->set_timestamp(700413305947499);
AddMmap(6531, 0x7f68663f8000, 0x1e00000, 0x7f68663f8000, "//anon", &events);
events.rbegin()->set_timestamp(700413306012797);
AddMmap(6531, 0x7f6866525000, 0x1a00000, 0x7f6866525000, "//anon", &events);
events.rbegin()->set_timestamp(700413312132909);
DeduceHugePages(&events);
CombineMappings(&events);
EXPECT_THAT(
events,
Pointwise(
Partially(EqualsProto()),
{
"mmap_event: { pgoff: 0 filename: 'main' }",
"mmap_event: { pgoff: 0 filename: 'ld.so' }",
"mmap_event: { pgoff: 0 filename: '[vdso]' }",
"mmap_event: { pgoff: 0 filename: 'lib1.so' }",
"mmap_event: { pgoff: 0 filename: 'lib2.so' }",
"mmap_event: { pgoff: 0 filename: 'lib3.so' }",
"mmap_event: { pgoff: 0 filename: '/anon_hugepage (deleted)' }",
"mmap_event: { pgoff: 0 filename: '/anon_hugepage (deleted)' }",
"mmap_event: { pgoff: 0x7f68663f8000 filename: '//anon' }",
"mmap_event: { pgoff: 0x7f6866525000 filename: '//anon' }",
}));
}
TEST(HugePageDeducer, Regression62446346) {
RepeatedPtrField<PerfEvent> events;
// Perf infers the filename is "file", but at offset 0 for
// hugepage-backed, anonymous mappings.
//
// vaddr start - vaddr end vaddr-size elf-offset
// [0x55a685bfb000-55a685dfb000) (0x200000) @ 0]: file
// [0x55a685dfb000-55a687c00000) (0x1e05000) @ 0x200000]: file
// [0x55a687c00000-55a6a5200000) (0x1d600000) @ 0]: file
// [0x55a6a5200000-55a6a6400000) (0x1200000) @ 0x1f605000]: file
// [0x55a6a6400000-55a6a6600000) (0x200000) @ 0]: file
// [0x55a6a6600000-55a6a8800000) (0x2200000) @ 0x20a05000]: file
// [0x55a6a8800000-55a6a8a00000) (0x200000) @ 0]: file
// [0x55a6a8a00000-55a6a90ca000) (0x6ca000) @ 0x22e05000]: file
// [0x55a6a90ca000-55a6a90cb000) (0x1000) @ 0x234cf000]: file
{
MMapEvent* ev = events.Add()->mutable_mmap_event();
ev->set_pid(1234);
ev->set_start(0x55a685bfb000);
ev->set_len(0x200000);
ev->set_pgoff(0);
ev->set_filename("file");
}
{
MMapEvent* ev = events.Add()->mutable_mmap_event();
ev->set_pid(1234);
ev->set_start(0x55a685dfb000);
ev->set_len(0x1e05000);
ev->set_pgoff(0x200000);
ev->set_filename("file");
}
{
MMapEvent* ev = events.Add()->mutable_mmap_event();
ev->set_pid(1234);
ev->set_start(0x55a687c00000);
ev->set_len(0x1d600000);
ev->set_pgoff(0);
ev->set_filename("file");
}
{
MMapEvent* ev = events.Add()->mutable_mmap_event();
ev->set_pid(1234);
ev->set_start(0x55a6a5200000);
ev->set_len(0x1200000);
ev->set_pgoff(0x1f605000);
ev->set_filename("file");
}
{
MMapEvent* ev = events.Add()->mutable_mmap_event();
ev->set_pid(1234);
ev->set_start(0x55a6a6400000);
ev->set_len(0x200000);
ev->set_pgoff(0);
ev->set_filename("file");
}
{
MMapEvent* ev = events.Add()->mutable_mmap_event();
ev->set_pid(1234);
ev->set_start(0x55a6a6600000);
ev->set_len(0x2200000);
ev->set_pgoff(0x20a05000);
ev->set_filename("file");
}
{
MMapEvent* ev = events.Add()->mutable_mmap_event();
ev->set_pid(1234);
ev->set_start(0x55a6a8800000);
ev->set_len(0x200000);
ev->set_pgoff(0);
ev->set_filename("file");
}
{
MMapEvent* ev = events.Add()->mutable_mmap_event();
ev->set_pid(1234);
ev->set_start(0x55a6a8a00000);
ev->set_len(0x6ca000);
ev->set_pgoff(0x22e05000);
ev->set_filename("file");
}
{
MMapEvent* ev = events.Add()->mutable_mmap_event();
ev->set_pid(1234);
ev->set_start(0x55a6a90ca000);
ev->set_len(0x1000);
ev->set_pgoff(0x234cf000);
ev->set_filename("file");
}
DeduceHugePages(&events);
CombineMappings(&events);
ASSERT_EQ(1, events.size());
EXPECT_EQ("file", events[0].mmap_event().filename());
EXPECT_EQ(0x55a685bfb000, events[0].mmap_event().start());
EXPECT_EQ(0x55a6a90cb000 - 0x55a685bfb000, events[0].mmap_event().len());
EXPECT_EQ(0, events[0].mmap_event().pgoff());
}
} // namespace
} // namespace quipper