Home | History | Annotate | Download | only in quipper
      1 #include "huge_page_deducer.h"
      2 
      3 #include "base/logging.h"
      4 #include "compat/string.h"
      5 #include "compat/test.h"
      6 
      7 
      8 namespace quipper {
      9 namespace {
     10 using PerfEvent = PerfDataProto::PerfEvent;
     11 using MMapEvent = PerfDataProto::MMapEvent;
     12 using ::testing::EqualsProto;
     13 using ::testing::Pointwise;
     14 using ::testing::proto::Partially;
     15 
     16 // AddMmap is a helper function to create simple MMapEvents, with which
     17 // testcases can encode "maps" entries similar to /proc/self/maps in a tabular
     18 // one-line-per-entry.
     19 void AddMmap(uint32_t pid, uint64_t mmap_start, uint64_t length, uint64_t pgoff,
     20              const string& file, RepeatedPtrField<PerfEvent>* events) {
     21   MMapEvent* ev = events->Add()->mutable_mmap_event();
     22   ev->set_pid(pid);
     23   ev->set_start(mmap_start);
     24   ev->set_len(length);
     25   ev->set_pgoff(pgoff);
     26   ev->set_filename(file);
     27 }
     28 
     29 TEST(HugePageDeducer, HugePagesMappings) {
     30   RepeatedPtrField<PerfEvent> events;
     31   {
     32     MMapEvent* ev = events.Add()->mutable_mmap_event();
     33     ev->set_pid(1234);
     34     ev->set_start(0x40000000);
     35     ev->set_len(0x18000);
     36     ev->set_pgoff(0);
     37     ev->set_filename("/usr/lib/libfoo.so");
     38   }
     39   {
     40     MMapEvent* ev = events.Add()->mutable_mmap_event();
     41     ev->set_pid(1234);
     42     ev->set_start(0x40018000);
     43     ev->set_len(0x1e8000);
     44     ev->set_pgoff(0);
     45     ev->set_filename("/opt/google/chrome/chrome");
     46   }
     47   {
     48     MMapEvent* ev = events.Add()->mutable_mmap_event();
     49     ev->set_pid(1234);
     50     ev->set_start(0x40200000);
     51     ev->set_len(0x1c00000);
     52     ev->set_pgoff(0);
     53     ev->set_filename("//anon");
     54   }
     55   {
     56     MMapEvent* ev = events.Add()->mutable_mmap_event();
     57     ev->set_pid(1234);
     58     ev->set_start(0x41e00000);
     59     ev->set_len(0x4000000);
     60     ev->set_pgoff(0x1de8000);
     61     ev->set_filename("/opt/google/chrome/chrome");
     62   }
     63   {
     64     MMapEvent* ev = events.Add()->mutable_mmap_event();
     65     ev->set_pid(2345);
     66     ev->set_start(0x45e00000);
     67     ev->set_len(0x1e00000);
     68     ev->set_pgoff(0);
     69     ev->set_filename("//anon");
     70   }
     71   {
     72     MMapEvent* ev = events.Add()->mutable_mmap_event();
     73     ev->set_pid(2345);
     74     ev->set_start(0x47c00000);
     75     ev->set_len(0x4000000);
     76     ev->set_pgoff(0x1e00000);
     77     ev->set_filename("/opt/google/chrome/chrome");
     78   }
     79 
     80   DeduceHugePages(&events);
     81   CombineMappings(&events);
     82 
     83   ASSERT_GE(events.size(), 3);
     84   EXPECT_EQ(events.size(), 3);
     85 
     86   EXPECT_THAT(events,
     87               Pointwise(Partially(EqualsProto()),
     88                         {
     89                             "mmap_event: { start: 0x40000000 len:0x18000 "
     90                             "pgoff: 0 filename: '/usr/lib/libfoo.so'}",
     91                             "mmap_event: { start: 0x40018000 len:0x5de8000 "
     92                             "pgoff: 0 filename: '/opt/google/chrome/chrome'}",
     93                             "mmap_event: { start: 0x45e00000 len:0x5e00000 "
     94                             "pgoff: 0 filename: '/opt/google/chrome/chrome'}",
     95                         }));
     96 
     97   EXPECT_EQ("/usr/lib/libfoo.so", events[0].mmap_event().filename());
     98   EXPECT_EQ(0x40000000, events[0].mmap_event().start());
     99   EXPECT_EQ(0x18000, events[0].mmap_event().len());
    100   EXPECT_EQ(0x0, events[0].mmap_event().pgoff());
    101 
    102   // The split Chrome mappings should have been combined.
    103   EXPECT_EQ("/opt/google/chrome/chrome", events[2].mmap_event().filename());
    104   EXPECT_EQ(0x40018000, events[1].mmap_event().start());
    105   EXPECT_EQ(0x5de8000, events[1].mmap_event().len());
    106   EXPECT_EQ(0x0, events[1].mmap_event().pgoff());
    107 
    108   EXPECT_EQ("/opt/google/chrome/chrome", events[2].mmap_event().filename());
    109   EXPECT_EQ(0x45e00000, events[2].mmap_event().start());
    110   EXPECT_EQ(0x5e00000, events[2].mmap_event().len());
    111   EXPECT_EQ(0x0, events[2].mmap_event().pgoff());
    112 }
    113 
    114 enum HugepageTextStyle {
    115   kAnonHugepageText,
    116   kNoHugepageText,
    117 };
    118 
    119 class HugepageTextStyleDependent
    120     : public ::testing::TestWithParam<HugepageTextStyle> {
    121  protected:
    122   void AddHugepageTextMmap(uint32_t pid, uint64_t mmap_start, uint64_t length,
    123                            uint64_t pgoff, string file,
    124                            RepeatedPtrField<PerfEvent>* events) {
    125     // Various hugepage implementations and perf versions result in various
    126     // quirks in how hugepages are reported.
    127 
    128     switch (GetParam()) {
    129       case kNoHugepageText:
    130         // Do nothing; the maps are complete and file-backed
    131         break;
    132       case kAnonHugepageText:
    133         // exec is remapped into anonymous memory, which perf reports as
    134         // '//anon'. Anonymous sections have no pgoff.
    135         file = "//anon";
    136         pgoff = 0;
    137         break;
    138       default:
    139         CHECK(false) << "Unimplemented";
    140     }
    141     AddMmap(pid, mmap_start, length, pgoff, file, events);
    142   }
    143 };
    144 
    145 TEST_P(HugepageTextStyleDependent, OnlyOneMappingThatIsHuge) {
    146   RepeatedPtrField<PerfEvent> events;
    147   AddHugepageTextMmap(1, 0x100200000, 0x200000, 0, "file", &events);
    148 
    149   DeduceHugePages(&events);
    150   CombineMappings(&events);
    151 
    152   // Don't check filename='file'; if it's backed by anonymous memory, it isn't
    153   // possible for quipper to deduce the filename without other mmaps immediately
    154   // adjacent.
    155   EXPECT_THAT(
    156       events,
    157       Pointwise(Partially(EqualsProto()),
    158                 {"mmap_event: { start: 0x100200000 len: 0x200000 pgoff: 0}"}));
    159 }
    160 
    161 TEST_P(HugepageTextStyleDependent, OnlyOneMappingUnaligned) {
    162   RepeatedPtrField<PerfEvent> events;
    163   AddMmap(2, 0x200201000, 0x200000, 0, "file", &events);
    164 
    165   DeduceHugePages(&events);
    166   CombineMappings(&events);
    167 
    168   EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
    169                                 {"mmap_event: { start: 0x200201000 "
    170                                  "len:0x200000 pgoff: 0 filename: 'file'}"}));
    171 }
    172 
    173 TEST_P(HugepageTextStyleDependent, FirstPageIsHugeWithSmallTail) {
    174   RepeatedPtrField<PerfEvent> events;
    175   AddHugepageTextMmap(3, 0x300400000, 0x400000, 0, "file", &events);
    176   AddMmap(3, 0x300800000, 0x001000, 0x400000, "file", &events);
    177 
    178   DeduceHugePages(&events);
    179   CombineMappings(&events);
    180 
    181   EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
    182                                 {"mmap_event: { start: 0x300400000 "
    183                                  "len:0x401000 pgoff: 0 filename: 'file'}"}));
    184 }
    185 
    186 TEST_P(HugepageTextStyleDependent, DISABLED_FirstPageIsSmallWithHugeTail) {
    187   // This test is disabled because DeduceHugePage requires a non-zero pgoff
    188   // *after* a hugepage_text section in order to correctly deduce it, so it
    189   // is unable to deduce these cases.
    190   RepeatedPtrField<PerfEvent> events;
    191   AddMmap(4, 0x4003ff000, 0x001000, 0, "file", &events);
    192   AddHugepageTextMmap(4, 0x400400000, 0x200000, 0x001000, "file", &events);
    193 
    194   DeduceHugePages(&events);
    195   CombineMappings(&events);
    196 
    197   EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
    198                                 {"mmap_event: { start: 0x4003ff000 "
    199                                  "len:0x201000 pgoff: 0 filename: 'file'}"}));
    200 }
    201 
    202 TEST_P(HugepageTextStyleDependent, HugePageBetweenTwoSmallSections) {
    203   RepeatedPtrField<PerfEvent> events;
    204   AddMmap(5, 0x5003ff000, 0x001000, 0, "file", &events);
    205   AddHugepageTextMmap(5, 0x500400000, 0x200000, 0x001000, "file", &events);
    206   AddMmap(5, 0x500600000, 0x001000, 0x201000, "file", &events);
    207 
    208   DeduceHugePages(&events);
    209   CombineMappings(&events);
    210 
    211   EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
    212                                 {"mmap_event: { start: 0x5003ff000 "
    213                                  "len:0x202000 pgoff: 0 filename: 'file'}"}));
    214 }
    215 
    216 TEST_P(HugepageTextStyleDependent, HugePageSplitByEarlyMlockBetweenTwoSmall) {
    217   RepeatedPtrField<PerfEvent> events;
    218   AddMmap(6, 0x6003ff000, 0x001000, 0, "file", &events);
    219   AddHugepageTextMmap(6, 0x600400000, 0x3f8000, 0x001000, "file", &events);
    220   AddHugepageTextMmap(6, 0x6007f8000, 0x008000, 0x3f9000, "file", &events);
    221   AddMmap(6, 0x600800000, 0x001000, 0x401000, "file", &events);
    222 
    223   DeduceHugePages(&events);
    224   CombineMappings(&events);
    225 
    226   EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
    227                                 {"mmap_event: { start: 0x6003ff000 "
    228                                  "len:0x402000 pgoff: 0 filename: 'file'}"}));
    229 }
    230 
    231 TEST_P(HugepageTextStyleDependent, HugePageSplitByLateMlockBetweenTwoSmall) {
    232   RepeatedPtrField<PerfEvent> events;
    233   AddMmap(7, 0x7003ff000, 0x001000, 0, "file", &events);
    234   AddHugepageTextMmap(7, 0x700400000, 0x008000, 0x001000, "file", &events);
    235   AddHugepageTextMmap(7, 0x700408000, 0x3f8000, 0x009000, "file", &events);
    236   AddMmap(7, 0x700800000, 0x001000, 0x401000, "file", &events);
    237 
    238   DeduceHugePages(&events);
    239   CombineMappings(&events);
    240 
    241   EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
    242                                 {"mmap_event: { start: 0x7003ff000 "
    243                                  "len:0x402000 pgoff: 0 filename: 'file'}"}));
    244 }
    245 
    246 TEST_P(HugepageTextStyleDependent, HugePageSplitEvenlyByMlockBetweenTwoSmall) {
    247   RepeatedPtrField<PerfEvent> events;
    248   AddMmap(8, 0x8003ff000, 0x001000, 0, "file", &events);
    249   AddHugepageTextMmap(8, 0x800400000, 0x0f8000, 0x001000, "file", &events);
    250   AddHugepageTextMmap(8, 0x8004f8000, 0x008000, 0x0f9000, "file", &events);
    251   AddHugepageTextMmap(8, 0x800500000, 0x100000, 0x101000, "file", &events);
    252   AddMmap(8, 0x800600000, 0x001000, 0x201000, "file", &events);
    253 
    254   DeduceHugePages(&events);
    255   CombineMappings(&events);
    256 
    257   EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
    258                                 {"mmap_event: { start: 0x8003ff000 "
    259                                  "len:0x202000 pgoff: 0 filename: 'file'}"}));
    260 }
    261 
    262 TEST_P(HugepageTextStyleDependent, MultipleContiguousHugepages) {
    263   RepeatedPtrField<PerfEvent> events;
    264   AddMmap(9, 0x9003ff000, 0x001000, 0, "file", &events);
    265   AddHugepageTextMmap(9, 0x900400000, 0x200000, 0x001000, "file", &events);
    266   AddHugepageTextMmap(9, 0x900600000, 0x200000, 0x201000, "file", &events);
    267   AddMmap(9, 0x900800000, 0x001000, 0x401000, "file", &events);
    268 
    269   DeduceHugePages(&events);
    270   CombineMappings(&events);
    271 
    272   EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
    273                                 {"mmap_event: { start: 0x9003ff000 "
    274                                  "len:0x402000 pgoff: 0 filename: 'file'}"}));
    275 }
    276 
    277 TEST_P(HugepageTextStyleDependent, MultipleContiguousMlockSplitHugepages) {
    278   // Think:
    279   // - hugepage_text 4MiB range
    280   // - mlock alternating 512-KiB chunks
    281   RepeatedPtrField<PerfEvent> events;
    282   AddMmap(10, 0xa003ff000, 0x001000, 0, "file", &events);
    283   AddHugepageTextMmap(10, 0xa00400000, 0x080000, 0x001000, "file", &events);
    284   AddHugepageTextMmap(10, 0xa00480000, 0x080000, 0x081000, "file", &events);
    285   AddHugepageTextMmap(10, 0xa00500000, 0x080000, 0x101000, "file", &events);
    286   AddHugepageTextMmap(10, 0xa00580000, 0x080000, 0x181000, "file", &events);
    287   AddHugepageTextMmap(10, 0xa00600000, 0x080000, 0x201000, "file", &events);
    288   AddHugepageTextMmap(10, 0xa00680000, 0x080000, 0x281000, "file", &events);
    289   AddHugepageTextMmap(10, 0xa00700000, 0x080000, 0x301000, "file", &events);
    290   AddHugepageTextMmap(10, 0xa00780000, 0x080000, 0x381000, "file", &events);
    291   AddMmap(10, 0xa00800000, 0x001000, 0x401000, "file", &events);
    292 
    293   DeduceHugePages(&events);
    294   CombineMappings(&events);
    295 
    296   EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
    297                                 {"mmap_event: { start: 0xa003ff000 "
    298                                  "len:0x402000 pgoff: 0 filename: 'file'}"}));
    299 }
    300 
    301 TEST_P(HugepageTextStyleDependent, MultipleWithUnalignedInitialHugePage) {
    302   // Base on real program
    303   RepeatedPtrField<PerfEvent> events;
    304 
    305   AddHugepageTextMmap(11, 0x85d32e000, 0x6d2000, 0x0, "file", &events);
    306   AddHugepageTextMmap(11, 0x85da00000, 0x6a00000, 0x6d2000, "file", &events);
    307   AddMmap(11, 0x864400000, 0x200000, 0x70d2000, "file", &events);
    308   AddHugepageTextMmap(11, 0x864600000, 0x200000, 0x72d2000, "file", &events);
    309   AddMmap(11, 0x864800000, 0x600000, 0x74d2000, "file", &events);
    310   AddHugepageTextMmap(11, 0x864e00000, 0x200000, 0x7ad2000, "file", &events);
    311   AddMmap(11, 0x865000000, 0x4a000, 0x7cd2000, "file", &events);
    312   AddMmap(11, 0x86504a000, 0x1000, 0x7d1c000, "file", &events);
    313   AddMmap(11, 0xa3d368000, 0x3a96000, 0x0, "file2", &events);
    314   AddMmap(11, 0xa467cc000, 0x2000, 0x0, "file3", &events);
    315 
    316   DeduceHugePages(&events);
    317   CombineMappings(&events);
    318 
    319   EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
    320                                 {
    321                                     "mmap_event: { start: 0x85d32e000 "
    322                                     "len:0x7d1d000 pgoff: 0 filename: 'file'}",
    323                                     "mmap_event: { start: 0xa3d368000 "
    324                                     "len:0x3a96000 pgoff: 0 filename: 'file2'}",
    325                                     "mmap_event: { start: 0xa467cc000 "
    326                                     "len:0x2000,  pgoff: 0 filename: 'file3'}",
    327                                 }));
    328 }
    329 
    330 TEST_P(HugepageTextStyleDependent, MultipleWithUnalignedInitialHugePage2) {
    331   // Base on real program
    332   RepeatedPtrField<PerfEvent> events;
    333   AddHugepageTextMmap(12, 0xbcff6000, 0x200000, 0x00000000, "file", &events);
    334   AddMmap(12, 0xbd1f6000, 0x300a000, 0x200000, "file", &events);
    335   AddHugepageTextMmap(12, 0xc0200000, 0x2b374000, 0x320a000, "file", &events);
    336   AddHugepageTextMmap(12, 0xeb574000, 0x514000, 0x2e57e000, "file", &events);
    337   AddHugepageTextMmap(12, 0xeba88000, 0x1d78000, 0x2ea92000, "file", &events);
    338   AddMmap(12, 0xed800000, 0x1200000, 0x3080a000, "file", &events);
    339   AddHugepageTextMmap(12, 0xeea00000, 0x200000, 0x31a0a000, "file", &events);
    340   AddMmap(12, 0xeec00000, 0x2800000, 0x31c0a000, "file", &events);
    341   AddHugepageTextMmap(12, 0xf1400000, 0x200000, 0x3440a000, "file", &events);
    342   AddMmap(12, 0xf1600000, 0x89f000, 0x3460a000, "file", &events);
    343   AddMmap(12, 0xf1e9f000, 0x1000, 0x34ea9000, "file", &events);
    344 
    345   DeduceHugePages(&events);
    346   CombineMappings(&events);
    347 
    348   EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
    349                                 {"mmap_event: { start: 0xbcff6000 "
    350                                  "len:0x34eaa000 pgoff: 0 filename: 'file'}"}));
    351 }
    352 
    353 TEST_P(HugepageTextStyleDependent, NoMmaps) {
    354   RepeatedPtrField<PerfEvent> events;
    355   events.Add();
    356 
    357   DeduceHugePages(&events);
    358   CombineMappings(&events);
    359 
    360   EXPECT_THAT(events, Pointwise(EqualsProto(), std::vector<PerfEvent>(1)));
    361 }
    362 TEST_P(HugepageTextStyleDependent, MultipleNonMmaps) {
    363   RepeatedPtrField<PerfEvent> events;
    364   events.Add();
    365   events.Add();
    366 
    367   DeduceHugePages(&events);
    368   CombineMappings(&events);
    369 
    370   EXPECT_THAT(events, Pointwise(EqualsProto(), std::vector<PerfEvent>(2)));
    371 }
    372 TEST_P(HugepageTextStyleDependent, NonMmapFirstMmap) {
    373   RepeatedPtrField<PerfEvent> events;
    374   events.Add();
    375   AddHugepageTextMmap(12, 0, 0x200000, 0, "file", &events);
    376 
    377   DeduceHugePages(&events);
    378   CombineMappings(&events);
    379 
    380   EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
    381                                 {"", "mmap_event: { pgoff: 0 }"}));
    382 }
    383 TEST_P(HugepageTextStyleDependent, NonMmapAfterLastMmap) {
    384   RepeatedPtrField<PerfEvent> events;
    385   AddHugepageTextMmap(12, 0, 0x200000, 0, "file", &events);
    386   events.Add();
    387 
    388   DeduceHugePages(&events);
    389   CombineMappings(&events);
    390 
    391   EXPECT_THAT(events, Pointwise(Partially(EqualsProto()),
    392                                 {"mmap_event: { pgoff: 0 }", ""}));
    393 }
    394 
    395 INSTANTIATE_TEST_CASE_P(NoHugepageText, HugepageTextStyleDependent,
    396                         ::testing::Values(kNoHugepageText));
    397 INSTANTIATE_TEST_CASE_P(AnonHugepageText, HugepageTextStyleDependent,
    398                         ::testing::Values(kAnonHugepageText));
    399 
    400 TEST(HugePageDeducer, DoesNotChangeVirtuallyContiguousPgoffNonContiguous) {
    401   // We've seen programs with strange memory layouts having virtually contiguous
    402   // memory backed by non-contiguous bits of a file.
    403   RepeatedPtrField<PerfEvent> events;
    404   AddMmap(758463, 0x2f278000, 0x20000, 0, "lib0.so", &events);
    405   AddMmap(758463, 0x2f29d000, 0x2000, 0, "shm", &events);
    406   AddMmap(758463, 0x2f2a2000, 0xa000, 0, "lib1.so", &events);
    407   AddMmap(758463, 0x3d400000, 0x9ee000, 0, "lib2.so", &events);
    408   AddMmap(758463, 0x3e000000, 0x16000, 0, "lib3.so", &events);
    409   AddMmap(758463, 0x3e400000, 0x270000, 0x1a00000, "shm", &events);
    410   AddMmap(758463, 0x3e670000, 0x10000, 0x1aaac000, "shm", &events);
    411   AddMmap(758463, 0x3e680000, 0x10000, 0x1b410000, "shm", &events);
    412 
    413   DeduceHugePages(&events);
    414   CombineMappings(&events);
    415 
    416   EXPECT_THAT(events,
    417               Pointwise(Partially(EqualsProto()),
    418                         {
    419                             "mmap_event: { pgoff: 0 filename: 'lib0.so' }",
    420                             "mmap_event: { pgoff: 0 filename: 'shm' }",
    421                             "mmap_event: { pgoff: 0 filename: 'lib1.so' }",
    422                             "mmap_event: { pgoff: 0 filename: 'lib2.so' }",
    423                             "mmap_event: { pgoff: 0 filename: 'lib3.so' }",
    424                             "mmap_event: { pgoff: 0x1a00000 filename: 'shm' }",
    425                             "mmap_event: { pgoff: 0x1aaac000 filename: 'shm' }",
    426                             "mmap_event: { pgoff: 0x1b410000 filename: 'shm' }",
    427                         }));
    428 }
    429 
    430 TEST(HugePageDeducer, IgnoresDynamicMmaps) {
    431   // Now, let's watch a binary hugepage_text itself.
    432   RepeatedPtrField<PerfEvent> events;
    433   AddMmap(6531, 0x560d76b25000, 0x24ce000, 0, "main", &events);
    434   events.rbegin()->set_timestamp(700413232676401);
    435   AddMmap(6531, 0x7f686a1ec000, 0x24000, 0, "ld.so", &events);
    436   events.rbegin()->set_timestamp(700413232691935);
    437   AddMmap(6531, 0x7ffea5dc8000, 0x2000, 0, "[vdso]", &events);
    438   events.rbegin()->set_timestamp(700413232701418);
    439   AddMmap(6531, 0x7f686a1e3000, 0x5000, 0, "lib1.so", &events);
    440   events.rbegin()->set_timestamp(700413232824216);
    441   AddMmap(6531, 0x7f686a1a8000, 0x3a000, 0, "lib2.so", &events);
    442   events.rbegin()->set_timestamp(700413232854520);
    443   AddMmap(6531, 0x7f6869ea7000, 0x5000, 0, "lib3.so", &events);
    444   events.rbegin()->set_timestamp(700413248827794);
    445   AddMmap(6531, 0x7f6867e00000, 0x200000, 0, "/anon_hugepage (deleted)",
    446           &events);
    447   events.rbegin()->set_timestamp(700413295816043);
    448   AddMmap(6531, 0x7f6867c00000, 0x200000, 0, "/anon_hugepage (deleted)",
    449           &events);
    450   events.rbegin()->set_timestamp(700413305947499);
    451   AddMmap(6531, 0x7f68663f8000, 0x1e00000, 0x7f68663f8000, "//anon", &events);
    452   events.rbegin()->set_timestamp(700413306012797);
    453   AddMmap(6531, 0x7f6866525000, 0x1a00000, 0x7f6866525000, "//anon", &events);
    454   events.rbegin()->set_timestamp(700413312132909);
    455 
    456   DeduceHugePages(&events);
    457   CombineMappings(&events);
    458 
    459   EXPECT_THAT(
    460       events,
    461       Pointwise(
    462           Partially(EqualsProto()),
    463           {
    464               "mmap_event: { pgoff: 0 filename: 'main' }",
    465               "mmap_event: { pgoff: 0 filename: 'ld.so' }",
    466               "mmap_event: { pgoff: 0 filename: '[vdso]' }",
    467               "mmap_event: { pgoff: 0 filename: 'lib1.so' }",
    468               "mmap_event: { pgoff: 0 filename: 'lib2.so' }",
    469               "mmap_event: { pgoff: 0 filename: 'lib3.so' }",
    470               "mmap_event: { pgoff: 0 filename: '/anon_hugepage (deleted)' }",
    471               "mmap_event: { pgoff: 0 filename: '/anon_hugepage (deleted)' }",
    472               "mmap_event: { pgoff: 0x7f68663f8000 filename: '//anon' }",
    473               "mmap_event: { pgoff: 0x7f6866525000 filename: '//anon' }",
    474           }));
    475 }
    476 
    477 TEST(HugePageDeducer, Regression62446346) {
    478   RepeatedPtrField<PerfEvent> events;
    479 
    480   // Perf infers the filename is "file", but at offset 0 for
    481   // hugepage-backed, anonymous mappings.
    482   //
    483   // vaddr start   - vaddr end     vaddr-size    elf-offset
    484   // [0x55a685bfb000-55a685dfb000) (0x200000)   @ 0]:          file
    485   // [0x55a685dfb000-55a687c00000) (0x1e05000)  @ 0x200000]:   file
    486   // [0x55a687c00000-55a6a5200000) (0x1d600000) @ 0]:          file
    487   // [0x55a6a5200000-55a6a6400000) (0x1200000)  @ 0x1f605000]: file
    488   // [0x55a6a6400000-55a6a6600000) (0x200000)   @ 0]:          file
    489   // [0x55a6a6600000-55a6a8800000) (0x2200000)  @ 0x20a05000]: file
    490   // [0x55a6a8800000-55a6a8a00000) (0x200000)   @ 0]:          file
    491   // [0x55a6a8a00000-55a6a90ca000) (0x6ca000)   @ 0x22e05000]: file
    492   // [0x55a6a90ca000-55a6a90cb000) (0x1000)     @ 0x234cf000]: file
    493   {
    494     MMapEvent* ev = events.Add()->mutable_mmap_event();
    495     ev->set_pid(1234);
    496     ev->set_start(0x55a685bfb000);
    497     ev->set_len(0x200000);
    498     ev->set_pgoff(0);
    499     ev->set_filename("file");
    500   }
    501   {
    502     MMapEvent* ev = events.Add()->mutable_mmap_event();
    503     ev->set_pid(1234);
    504     ev->set_start(0x55a685dfb000);
    505     ev->set_len(0x1e05000);
    506     ev->set_pgoff(0x200000);
    507     ev->set_filename("file");
    508   }
    509   {
    510     MMapEvent* ev = events.Add()->mutable_mmap_event();
    511     ev->set_pid(1234);
    512     ev->set_start(0x55a687c00000);
    513     ev->set_len(0x1d600000);
    514     ev->set_pgoff(0);
    515     ev->set_filename("file");
    516   }
    517   {
    518     MMapEvent* ev = events.Add()->mutable_mmap_event();
    519     ev->set_pid(1234);
    520     ev->set_start(0x55a6a5200000);
    521     ev->set_len(0x1200000);
    522     ev->set_pgoff(0x1f605000);
    523     ev->set_filename("file");
    524   }
    525   {
    526     MMapEvent* ev = events.Add()->mutable_mmap_event();
    527     ev->set_pid(1234);
    528     ev->set_start(0x55a6a6400000);
    529     ev->set_len(0x200000);
    530     ev->set_pgoff(0);
    531     ev->set_filename("file");
    532   }
    533   {
    534     MMapEvent* ev = events.Add()->mutable_mmap_event();
    535     ev->set_pid(1234);
    536     ev->set_start(0x55a6a6600000);
    537     ev->set_len(0x2200000);
    538     ev->set_pgoff(0x20a05000);
    539     ev->set_filename("file");
    540   }
    541   {
    542     MMapEvent* ev = events.Add()->mutable_mmap_event();
    543     ev->set_pid(1234);
    544     ev->set_start(0x55a6a8800000);
    545     ev->set_len(0x200000);
    546     ev->set_pgoff(0);
    547     ev->set_filename("file");
    548   }
    549   {
    550     MMapEvent* ev = events.Add()->mutable_mmap_event();
    551     ev->set_pid(1234);
    552     ev->set_start(0x55a6a8a00000);
    553     ev->set_len(0x6ca000);
    554     ev->set_pgoff(0x22e05000);
    555     ev->set_filename("file");
    556   }
    557   {
    558     MMapEvent* ev = events.Add()->mutable_mmap_event();
    559     ev->set_pid(1234);
    560     ev->set_start(0x55a6a90ca000);
    561     ev->set_len(0x1000);
    562     ev->set_pgoff(0x234cf000);
    563     ev->set_filename("file");
    564   }
    565 
    566   DeduceHugePages(&events);
    567   CombineMappings(&events);
    568 
    569   ASSERT_EQ(1, events.size());
    570 
    571   EXPECT_EQ("file", events[0].mmap_event().filename());
    572   EXPECT_EQ(0x55a685bfb000, events[0].mmap_event().start());
    573   EXPECT_EQ(0x55a6a90cb000 - 0x55a685bfb000, events[0].mmap_event().len());
    574   EXPECT_EQ(0, events[0].mmap_event().pgoff());
    575 }
    576 
    577 }  // namespace
    578 }  // namespace quipper
    579