1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 #include "precompiled.hpp"
  25 
  26 // Included early because the NMT flags don't include it.
  27 #include "utilities/macros.hpp"
  28 
  29 #if INCLUDE_NMT
  30 
  31 #include "services/memTracker.hpp"
  32 #include "services/virtualMemoryTracker.hpp"
  33 #include "utilities/globalDefinitions.hpp"
  34 #include "unittest.hpp"
  35 
  36 namespace {
  37   struct R {
  38     address _addr;
  39     size_t  _size;
  40   };
  41 }
  42 
  43 #define check(rmr, regions) check_inner((rmr), (regions), ARRAY_SIZE(regions), __FILE__, __LINE__)
  44 
  45 #define check_empty(rmr)                              \
  46   do {                                                \
  47     check_inner((rmr), NULL, 0, __FILE__, __LINE__);  \
  48   } while (false)
  49 
  50 static void check_inner(ReservedMemoryRegion* rmr, R* regions, size_t regions_size, const char* file, int line) {
  51   CommittedRegionIterator iter = rmr->iterate_committed_regions();
  52   size_t i = 0;
  53   size_t size = 0;
  54 
  55 #define WHERE " from " << file << ":" << line
  56 
  57   for (const CommittedMemoryRegion* region = iter.next(); region != NULL; region = iter.next()) {
  58     EXPECT_LT(i, regions_size) << WHERE;
  59     EXPECT_EQ(region->base(), regions[i]._addr) << WHERE;
  60     EXPECT_EQ(region->size(), regions[i]._size) << WHERE;
  61     size += region->size();
  62     i++;
  63   }
  64 
  65   EXPECT_EQ(i, regions_size) << WHERE;
  66   EXPECT_EQ(size, rmr->committed_size()) << WHERE;
  67 }
  68 
  69 class VirtualMemoryTrackerTest {
  70 public:
  71   static void test_add_committed_region_adjacent() {
  72     VirtualMemoryTracker::initialize(NMT_detail);
  73     VirtualMemoryTracker::late_initialize(NMT_detail);
  74 
  75     address addr = (address)0x10000000;
  76     size_t size  = 0x01000000;
  77 
  78     address frame1 = (address)0x1234;
  79     address frame2 = (address)0x1235;
  80 
  81     NativeCallStack stack(&frame1, 1);
  82     NativeCallStack stack2(&frame2, 1);
  83 
  84     // Add the reserved memory
  85     VirtualMemoryTracker::add_reserved_region(addr, size, stack, mtTest);
  86 
  87     // Fetch the added RMR added above
  88     ReservedMemoryRegion* rmr = VirtualMemoryTracker::_reserved_regions->find(ReservedMemoryRegion(addr, size));
  89 
  90     ASSERT_EQ(rmr->size(), size);
  91     ASSERT_EQ(rmr->base(), addr);
  92 
  93     // Commit Size Granularity
  94     const size_t cs = 0x1000;
  95 
  96     // Commit adjacent regions with same stack
  97 
  98     { // Commit one region
  99       rmr->add_committed_region(addr + cs, cs, stack);
 100       R r[] = { {addr + cs, cs} };
 101       check(rmr, r);
 102     }
 103 
 104     { // Commit adjacent - lower address
 105       rmr->add_committed_region(addr, cs, stack);
 106       R r[] = { {addr, 2 * cs} };
 107       check(rmr, r);
 108     }
 109 
 110     { // Commit adjacent - higher address
 111       rmr->add_committed_region(addr + 2 * cs, cs, stack);
 112       R r[] = { {addr, 3 * cs} };
 113       check(rmr, r);
 114     }
 115 
 116     // Cleanup
 117     rmr->remove_uncommitted_region(addr, 3 * cs);
 118     ASSERT_EQ(rmr->committed_size(), 0u);
 119 
 120 
 121     // Commit adjacent regions with different stacks
 122 
 123     { // Commit one region
 124       rmr->add_committed_region(addr + cs, cs, stack);
 125       R r[] = { {addr + cs, cs} };
 126       check(rmr, r);
 127     }
 128 
 129     { // Commit adjacent - lower address
 130       rmr->add_committed_region(addr, cs, stack2);
 131       R r[] = { {addr,      cs},
 132                 {addr + cs, cs} };
 133       check(rmr, r);
 134     }
 135 
 136     { // Commit adjacent - higher address
 137       rmr->add_committed_region(addr + 2 * cs, cs, stack2);
 138       R r[] = { {addr,          cs},
 139                 {addr +     cs, cs},
 140                 {addr + 2 * cs, cs} };
 141       check(rmr, r);
 142     }
 143 
 144     // Cleanup
 145     rmr->remove_uncommitted_region(addr, 3 * cs);
 146     ASSERT_EQ(rmr->committed_size(), 0u);
 147   }
 148 
 149   static void test_add_committed_region_adjacent_overlapping() {
 150     VirtualMemoryTracker::initialize(NMT_detail);
 151     VirtualMemoryTracker::late_initialize(NMT_detail);
 152 
 153     address addr = (address)0x10000000;
 154     size_t size  = 0x01000000;
 155 
 156     address frame1 = (address)0x1234;
 157     address frame2 = (address)0x1235;
 158 
 159     NativeCallStack stack(&frame1, 1);
 160     NativeCallStack stack2(&frame2, 1);
 161 
 162     // Add the reserved memory
 163     VirtualMemoryTracker::add_reserved_region(addr, size, stack, mtTest);
 164 
 165     // Fetch the added RMR added above
 166     ReservedMemoryRegion* rmr = VirtualMemoryTracker::_reserved_regions->find(ReservedMemoryRegion(addr, size));
 167 
 168     ASSERT_EQ(rmr->size(), size);
 169     ASSERT_EQ(rmr->base(), addr);
 170 
 171     // Commit Size Granularity
 172     const size_t cs = 0x1000;
 173 
 174     // Commit adjacent and overlapping regions with same stack
 175 
 176     { // Commit two non-adjacent regions
 177       rmr->add_committed_region(addr, 2 * cs, stack);
 178       rmr->add_committed_region(addr + 3 * cs, 2 * cs, stack);
 179       R r[] = { {addr,          2 * cs},
 180                 {addr + 3 * cs, 2 * cs} };
 181       check(rmr, r);
 182     }
 183 
 184     { // Commit adjacent and overlapping
 185       rmr->add_committed_region(addr + 2 * cs, 2 * cs, stack);
 186       R r[] = { {addr, 5 * cs} };
 187       check(rmr, r);
 188     }
 189 
 190     // revert to two non-adjacent regions
 191     rmr->remove_uncommitted_region(addr + 2 * cs, cs);
 192     ASSERT_EQ(rmr->committed_size(), 4 * cs);
 193 
 194     { // Commit overlapping and adjacent
 195       rmr->add_committed_region(addr + cs, 2 * cs, stack);
 196       R r[] = { {addr, 5 * cs} };
 197       check(rmr, r);
 198     }
 199 
 200     // Cleanup
 201     rmr->remove_uncommitted_region(addr, 5 * cs);
 202     ASSERT_EQ(rmr->committed_size(), 0u);
 203 
 204 
 205     // Commit adjacent and overlapping regions with different stacks
 206 
 207     { // Commit two non-adjacent regions
 208       rmr->add_committed_region(addr, 2 * cs, stack);
 209       rmr->add_committed_region(addr + 3 * cs, 2 * cs, stack);
 210       R r[] = { {addr,          2 * cs},
 211                 {addr + 3 * cs, 2 * cs} };
 212       check(rmr, r);
 213     }
 214 
 215     { // Commit adjacent and overlapping
 216       rmr->add_committed_region(addr + 2 * cs, 2 * cs, stack2);
 217       R r[] = { {addr,          2 * cs},
 218                 {addr + 2 * cs, 2 * cs},
 219                 {addr + 4 * cs,     cs} };
 220       check(rmr, r);
 221     }
 222 
 223     // revert to two non-adjacent regions
 224     rmr->add_committed_region(addr, 5 * cs, stack);
 225     rmr->remove_uncommitted_region(addr + 2 * cs, cs);
 226     ASSERT_EQ(rmr->committed_size(), 4 * cs);
 227 
 228     { // Commit overlapping and adjacent
 229       rmr->add_committed_region(addr + cs, 2 * cs, stack2);
 230       R r[] = { {addr,              cs},
 231                 {addr +     cs, 2 * cs},
 232                 {addr + 3 * cs, 2 * cs} };
 233       check(rmr, r);
 234     }
 235   }
 236 
 237   static void test_add_committed_region_overlapping() {
 238     VirtualMemoryTracker::initialize(NMT_detail);
 239     VirtualMemoryTracker::late_initialize(NMT_detail);
 240 
 241     address addr = (address)0x10000000;
 242     size_t size  = 0x01000000;
 243 
 244     address frame1 = (address)0x1234;
 245     address frame2 = (address)0x1235;
 246 
 247     NativeCallStack stack(&frame1, 1);
 248     NativeCallStack stack2(&frame2, 1);
 249 
 250     // Add the reserved memory
 251     VirtualMemoryTracker::add_reserved_region(addr, size, stack, mtTest);
 252 
 253     // Fetch the added RMR added above
 254     ReservedMemoryRegion* rmr = VirtualMemoryTracker::_reserved_regions->find(ReservedMemoryRegion(addr, size));
 255 
 256     ASSERT_EQ(rmr->size(), size);
 257     ASSERT_EQ(rmr->base(), addr);
 258 
 259     // Commit Size Granularity
 260     const size_t cs = 0x1000;
 261 
 262     // With same stack
 263 
 264     { // Commit one region
 265       rmr->add_committed_region(addr, cs, stack);
 266       R r[] = { {addr, cs} };
 267       check(rmr, r);
 268     }
 269 
 270     { // Commit the same region
 271       rmr->add_committed_region(addr, cs, stack);
 272       R r[] = { {addr, cs} };
 273       check(rmr, r);
 274     }
 275 
 276     { // Commit a succeeding region
 277       rmr->add_committed_region(addr + cs, cs, stack);
 278       R r[] = { {addr, 2 * cs} };
 279       check(rmr, r);
 280     }
 281 
 282     { // Commit  over two regions
 283       rmr->add_committed_region(addr, 2 * cs, stack);
 284       R r[] = { {addr, 2 * cs} };
 285       check(rmr, r);
 286     }
 287 
 288     {// Commit first part of a region
 289       rmr->add_committed_region(addr, cs, stack);
 290       R r[] = { {addr, 2 * cs} };
 291       check(rmr, r);
 292     }
 293 
 294     { // Commit second part of a region
 295       rmr->add_committed_region(addr + cs, cs, stack);
 296       R r[] = { {addr, 2 * cs} };
 297       check(rmr, r);
 298     }
 299 
 300     { // Commit a third part
 301       rmr->add_committed_region(addr + 2 * cs, cs, stack);
 302       R r[] = { {addr, 3 * cs} };
 303       check(rmr, r);
 304     }
 305 
 306     { // Commit in the middle of a region
 307       rmr->add_committed_region(addr + 1 * cs, cs, stack);
 308       R r[] = { {addr, 3 * cs} };
 309       check(rmr, r);
 310     }
 311 
 312     // Cleanup
 313     rmr->remove_uncommitted_region(addr, 3 * cs);
 314     ASSERT_EQ(rmr->committed_size(), 0u);
 315 
 316     // With preceding region
 317 
 318     rmr->add_committed_region(addr,              cs, stack);
 319     rmr->add_committed_region(addr + 2 * cs, 3 * cs, stack);
 320 
 321     rmr->add_committed_region(addr + 2 * cs,     cs, stack);
 322     {
 323       R r[] = { {addr,              cs},
 324                 {addr + 2 * cs, 3 * cs} };
 325       check(rmr, r);
 326     }
 327 
 328     rmr->add_committed_region(addr + 3 * cs,     cs, stack);
 329     {
 330       R r[] = { {addr,              cs},
 331                 {addr + 2 * cs, 3 * cs} };
 332       check(rmr, r);
 333     }
 334 
 335     rmr->add_committed_region(addr + 4 * cs,     cs, stack);
 336     {
 337       R r[] = { {addr,              cs},
 338                 {addr + 2 * cs, 3 * cs} };
 339       check(rmr, r);
 340     }
 341 
 342     // Cleanup
 343     rmr->remove_uncommitted_region(addr, 5 * cs);
 344     ASSERT_EQ(rmr->committed_size(), 0u);
 345 
 346     // With different stacks
 347 
 348     { // Commit one region
 349       rmr->add_committed_region(addr, cs, stack);
 350       R r[] = { {addr, cs} };
 351       check(rmr, r);
 352     }
 353 
 354     { // Commit the same region
 355       rmr->add_committed_region(addr, cs, stack2);
 356       R r[] = { {addr, cs} };
 357       check(rmr, r);
 358     }
 359 
 360     { // Commit a succeeding region
 361       rmr->add_committed_region(addr + cs, cs, stack);
 362       R r[] = { {addr,      cs},
 363                 {addr + cs, cs} };
 364       check(rmr, r);
 365     }
 366 
 367     { // Commit  over two regions
 368       rmr->add_committed_region(addr, 2 * cs, stack);
 369       R r[] = { {addr, 2 * cs} };
 370       check(rmr, r);
 371     }
 372 
 373     {// Commit first part of a region
 374       rmr->add_committed_region(addr, cs, stack2);
 375       R r[] = { {addr,      cs},
 376                 {addr + cs, cs} };
 377       check(rmr, r);
 378     }
 379 
 380     { // Commit second part of a region
 381       rmr->add_committed_region(addr + cs, cs, stack2);
 382       R r[] = { {addr, 2 * cs} };
 383       check(rmr, r);
 384     }
 385 
 386     { // Commit a third part
 387       rmr->add_committed_region(addr + 2 * cs, cs, stack2);
 388       R r[] = { {addr, 3 * cs} };
 389       check(rmr, r);
 390     }
 391 
 392     { // Commit in the middle of a region
 393       rmr->add_committed_region(addr + 1 * cs, cs, stack);
 394       R r[] = { {addr,          cs},
 395                 {addr +     cs, cs},
 396                 {addr + 2 * cs, cs} };
 397       check(rmr, r);
 398     }
 399   }
 400 
 401   static void test_add_committed_region() {
 402     test_add_committed_region_adjacent();
 403     test_add_committed_region_adjacent_overlapping();
 404     test_add_committed_region_overlapping();
 405   }
 406 
 407   template <size_t S>
 408   static void fix(R r[S]) {
 409 
 410   }
 411 
 412   static void test_remove_uncommitted_region() {
 413     VirtualMemoryTracker::initialize(NMT_detail);
 414     VirtualMemoryTracker::late_initialize(NMT_detail);
 415 
 416     address addr = (address)0x10000000;
 417     size_t size  = 0x01000000;
 418 
 419     address frame1 = (address)0x1234;
 420     address frame2 = (address)0x1235;
 421 
 422     NativeCallStack stack(&frame1, 1);
 423     NativeCallStack stack2(&frame2, 1);
 424 
 425     // Add the reserved memory
 426     VirtualMemoryTracker::add_reserved_region(addr, size, stack, mtTest);
 427 
 428     // Fetch the added RMR added above
 429     ReservedMemoryRegion* rmr = VirtualMemoryTracker::_reserved_regions->find(ReservedMemoryRegion(addr, size));
 430 
 431     ASSERT_EQ(rmr->size(), size);
 432     ASSERT_EQ(rmr->base(), addr);
 433 
 434     // Commit Size Granularity
 435     const size_t cs = 0x1000;
 436 
 437     { // Commit regions
 438       rmr->add_committed_region(addr, 3 * cs, stack);
 439       R r[] = { {addr, 3 * cs} };
 440       check(rmr, r);
 441 
 442       // Remove only existing
 443       rmr->remove_uncommitted_region(addr, 3 * cs);
 444       check_empty(rmr);
 445     }
 446 
 447     {
 448       rmr->add_committed_region(addr + 0 * cs, cs, stack);
 449       rmr->add_committed_region(addr + 2 * cs, cs, stack);
 450       rmr->add_committed_region(addr + 4 * cs, cs, stack);
 451 
 452       { // Remove first
 453         rmr->remove_uncommitted_region(addr, cs);
 454         R r[] = { {addr + 2 * cs, cs},
 455                   {addr + 4 * cs, cs} };
 456         check(rmr, r);
 457       }
 458 
 459       // add back
 460       rmr->add_committed_region(addr,          cs, stack);
 461 
 462       { // Remove middle
 463         rmr->remove_uncommitted_region(addr + 2 * cs, cs);
 464         R r[] = { {addr + 0 * cs, cs},
 465                   {addr + 4 * cs, cs} };
 466         check(rmr, r);
 467       }
 468 
 469       // add back
 470       rmr->add_committed_region(addr + 2 * cs, cs, stack);
 471 
 472       { // Remove end
 473         rmr->remove_uncommitted_region(addr + 4 * cs, cs);
 474         R r[] = { {addr + 0 * cs, cs},
 475                   {addr + 2 * cs, cs} };
 476         check(rmr, r);
 477       }
 478 
 479       rmr->remove_uncommitted_region(addr, 5 * cs);
 480       check_empty(rmr);
 481     }
 482 
 483     { // Remove larger region
 484       rmr->add_committed_region(addr + 1 * cs, cs, stack);
 485       rmr->remove_uncommitted_region(addr, 3 * cs);
 486       check_empty(rmr);
 487     }
 488 
 489     { // Remove smaller region - in the middle
 490       rmr->add_committed_region(addr, 3 * cs, stack);
 491       rmr->remove_uncommitted_region(addr + 1 * cs, cs);
 492       R r[] = { { addr + 0 * cs, cs},
 493                 { addr + 2 * cs, cs} };
 494       check(rmr, r);
 495 
 496       rmr->remove_uncommitted_region(addr, 3 * cs);
 497       check_empty(rmr);
 498     }
 499 
 500     { // Remove smaller region - at the beginning
 501       rmr->add_committed_region(addr, 3 * cs, stack);
 502       rmr->remove_uncommitted_region(addr + 0 * cs, cs);
 503       R r[] = { { addr + 1 * cs, 2 * cs} };
 504       check(rmr, r);
 505 
 506       rmr->remove_uncommitted_region(addr, 3 * cs);
 507       check_empty(rmr);
 508     }
 509 
 510     { // Remove smaller region - at the end
 511       rmr->add_committed_region(addr, 3 * cs, stack);
 512       rmr->remove_uncommitted_region(addr + 2 * cs, cs);
 513       R r[] = { { addr, 2 * cs} };
 514       check(rmr, r);
 515 
 516       rmr->remove_uncommitted_region(addr, 3 * cs);
 517       check_empty(rmr);
 518     }
 519 
 520     { // Remove smaller, overlapping region - at the beginning
 521       rmr->add_committed_region(addr + 1 * cs, 4 * cs, stack);
 522       rmr->remove_uncommitted_region(addr, 2 * cs);
 523       R r[] = { { addr + 2 * cs, 3 * cs} };
 524       check(rmr, r);
 525 
 526       rmr->remove_uncommitted_region(addr + 1 * cs, 4 * cs);
 527       check_empty(rmr);
 528     }
 529 
 530     { // Remove smaller, overlapping region - at the end
 531       rmr->add_committed_region(addr, 3 * cs, stack);
 532       rmr->remove_uncommitted_region(addr + 2 * cs, 2 * cs);
 533       R r[] = { { addr, 2 * cs} };
 534       check(rmr, r);
 535 
 536       rmr->remove_uncommitted_region(addr, 3 * cs);
 537       check_empty(rmr);
 538     }
 539   }
 540 };
 541 
 542 TEST_VM(VirtualMemoryTracker, add_committed_region) {
 543   VirtualMemoryTrackerTest::test_add_committed_region();
 544 }
 545 
 546 TEST_VM(VirtualMemoryTracker, remove_uncommitted_region) {
 547   VirtualMemoryTrackerTest::test_remove_uncommitted_region();
 548 }
 549 
 550 #endif // INCLUDE_NMT