test/hotspot/gtest/memory/test_metaspace_allocation.cpp
branchstuefe-new-metaspace-branch
changeset 58063 bdf136b8ae0e
parent 58062 65cad575ace3
child 58067 b83deb51ea70
equal deleted inserted replaced
58062:65cad575ace3 58063:bdf136b8ae0e
     1 /*
       
     2  * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
       
     3  * Copyright (c) 2018, SAP.
       
     4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     5  *
       
     6  * This code is free software; you can redistribute it and/or modify it
       
     7  * under the terms of the GNU General Public License version 2 only, as
       
     8  * published by the Free Software Foundation.
       
     9  *
       
    10  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    13  * version 2 for more details (a copy is included in the LICENSE file that
       
    14  * accompanied this code).
       
    15  *
       
    16  * You should have received a copy of the GNU General Public License version
       
    17  * 2 along with this work; if not, write to the Free Software Foundation,
       
    18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    19  *
       
    20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    21  * or visit www.oracle.com if you need additional information or have any
       
    22  * questions.
       
    23  */
       
    24 
       
    25 #include "precompiled.hpp"
       
    26 #include "memory/allocation.inline.hpp"
       
    27 #include "memory/metaspace.hpp"
       
    28 #include "runtime/mutex.hpp"
       
    29 #include "runtime/mutexLocker.hpp"
       
    30 #include "runtime/os.hpp"
       
    31 #include "utilities/align.hpp"
       
    32 #include "utilities/debug.hpp"
       
    33 #include "utilities/globalDefinitions.hpp"
       
    34 #include "utilities/ostream.hpp"
       
    35 #include "unittest.hpp"
       
    36 
       
    37 #define NUM_PARALLEL_METASPACES                 50
       
    38 #define MAX_PER_METASPACE_ALLOCATION_WORDSIZE   (512 * K)
       
    39 
       
    40 //#define DEBUG_VERBOSE true
       
    41 
       
    42 #ifdef DEBUG_VERBOSE
       
    43 
       
    44 struct chunkmanager_statistics_t {
       
    45   int num_specialized_chunks;
       
    46   int num_small_chunks;
       
    47   int num_medium_chunks;
       
    48   int num_humongous_chunks;
       
    49 };
       
    50 
       
    51 extern void test_metaspace_retrieve_chunkmanager_statistics(Metaspace::MetadataType mdType, chunkmanager_statistics_t* out);
       
    52 
       
    53 static void print_chunkmanager_statistics(outputStream* st, Metaspace::MetadataType mdType) {
       
    54   chunkmanager_statistics_t stat;
       
    55   test_metaspace_retrieve_chunkmanager_statistics(mdType, &stat);
       
    56   st->print_cr("free chunks: %d / %d / %d / %d", stat.num_specialized_chunks, stat.num_small_chunks,
       
    57                stat.num_medium_chunks, stat.num_humongous_chunks);
       
    58 }
       
    59 
       
    60 #endif
       
    61 
       
    62 struct chunk_geometry_t {
       
    63   size_t specialized_chunk_word_size;
       
    64   size_t small_chunk_word_size;
       
    65   size_t medium_chunk_word_size;
       
    66 };
       
    67 
       
    68 extern void test_metaspace_retrieve_chunk_geometry(Metaspace::MetadataType mdType, chunk_geometry_t* out);
       
    69 
       
    70 
       
    71 class MetaspaceAllocationTest : public ::testing::Test {
       
    72 protected:
       
    73 
       
    74   struct {
       
    75     size_t allocated;
       
    76     Mutex* lock;
       
    77     ClassLoaderMetaspace* space;
       
    78     bool is_empty() const { return allocated == 0; }
       
    79     bool is_full() const { return allocated >= MAX_PER_METASPACE_ALLOCATION_WORDSIZE; }
       
    80   } _spaces[NUM_PARALLEL_METASPACES];
       
    81 
       
    82   chunk_geometry_t _chunk_geometry;
       
    83 
       
    84   virtual void SetUp() {
       
    85     ::memset(_spaces, 0, sizeof(_spaces));
       
    86     test_metaspace_retrieve_chunk_geometry(Metaspace::NonClassType, &_chunk_geometry);
       
    87   }
       
    88 
       
    89   virtual void TearDown() {
       
    90     for (int i = 0; i < NUM_PARALLEL_METASPACES; i ++) {
       
    91       if (_spaces[i].space != NULL) {
       
    92         delete _spaces[i].space;
       
    93         delete _spaces[i].lock;
       
    94       }
       
    95     }
       
    96   }
       
    97 
       
    98   void create_space(int i) {
       
    99     assert(i >= 0 && i < NUM_PARALLEL_METASPACES, "Sanity");
       
   100     assert(_spaces[i].space == NULL && _spaces[i].allocated == 0, "Sanity");
       
   101     if (_spaces[i].lock == NULL) {
       
   102       _spaces[i].lock = new Mutex(Monitor::native, "gtest-MetaspaceAllocationTest-lock", false, Monitor::_safepoint_check_never);
       
   103       ASSERT_TRUE(_spaces[i].lock != NULL);
       
   104     }
       
   105     // Let every ~10th space be an unsafe anonymous one to test different allocation patterns.
       
   106     const Metaspace::MetaspaceType msType = (os::random() % 100 < 10) ?
       
   107       Metaspace::UnsafeAnonymousMetaspaceType : Metaspace::StandardMetaspaceType;
       
   108     {
       
   109       // Pull lock during space creation, since this is what happens in the VM too
       
   110       // (see ClassLoaderData::metaspace_non_null(), which we mimick here).
       
   111       MutexLocker ml(_spaces[i].lock,  Mutex::_no_safepoint_check_flag);
       
   112       _spaces[i].space = new ClassLoaderMetaspace(_spaces[i].lock, msType);
       
   113     }
       
   114     _spaces[i].allocated = 0;
       
   115     ASSERT_TRUE(_spaces[i].space != NULL);
       
   116   }
       
   117 
       
   118   // Returns the index of a random space where index is [0..metaspaces) and which is
       
   119   //   empty, non-empty or full.
       
   120   // Returns -1 if no matching space exists.
       
   121   enum fillgrade { fg_empty, fg_non_empty, fg_full };
       
   122   int get_random_matching_space(int metaspaces, fillgrade fg) {
       
   123     const int start_index = os::random() % metaspaces;
       
   124     int i = start_index;
       
   125     do {
       
   126       if (fg == fg_empty && _spaces[i].is_empty()) {
       
   127         return i;
       
   128       } else if ((fg == fg_full && _spaces[i].is_full()) ||
       
   129                  (fg == fg_non_empty && !_spaces[i].is_full() && !_spaces[i].is_empty())) {
       
   130         return i;
       
   131       }
       
   132       i ++;
       
   133       if (i == metaspaces) {
       
   134         i = 0;
       
   135       }
       
   136     } while (i != start_index);
       
   137     return -1;
       
   138   }
       
   139 
       
   140   int get_random_emtpy_space(int metaspaces) { return get_random_matching_space(metaspaces, fg_empty); }
       
   141   int get_random_non_emtpy_space(int metaspaces) { return get_random_matching_space(metaspaces, fg_non_empty); }
       
   142   int get_random_full_space(int metaspaces) { return get_random_matching_space(metaspaces, fg_full); }
       
   143 
       
   144   void do_test(Metaspace::MetadataType mdType, int metaspaces, int phases, int allocs_per_phase,
       
   145                float probability_for_large_allocations // 0.0-1.0
       
   146   ) {
       
   147     // Alternate between breathing in (allocating n blocks for a random Metaspace) and
       
   148     // breathing out (deleting a random Metaspace). The intent is to stress the coalescation
       
   149     // and splitting of free chunks.
       
   150     int phases_done = 0;
       
   151     bool allocating = true;
       
   152     while (phases_done < phases) {
       
   153       bool force_switch = false;
       
   154       if (allocating) {
       
   155         // Allocate space from metaspace, with a preference for completely empty spaces. This
       
   156         // should provide a good mixture of metaspaces in the virtual space.
       
   157         int index = get_random_emtpy_space(metaspaces);
       
   158         if (index == -1) {
       
   159           index = get_random_non_emtpy_space(metaspaces);
       
   160         }
       
   161         if (index == -1) {
       
   162           // All spaces are full, switch to freeing.
       
   163           force_switch = true;
       
   164         } else {
       
   165           // create space if it does not yet exist.
       
   166           if (_spaces[index].space == NULL) {
       
   167             create_space(index);
       
   168           }
       
   169           // Allocate a bunch of blocks from it. Mostly small stuff but mix in large allocations
       
   170           //  to force humongous chunk allocations.
       
   171           int allocs_done = 0;
       
   172           while (allocs_done < allocs_per_phase && !_spaces[index].is_full()) {
       
   173             size_t size = 0;
       
   174             int r = os::random() % 1000;
       
   175             if ((float)r < probability_for_large_allocations * 1000.0) {
       
   176               size = (os::random() % _chunk_geometry.medium_chunk_word_size) + _chunk_geometry.medium_chunk_word_size;
       
   177             } else {
       
   178               size = os::random() % 64;
       
   179             }
       
   180             // Note: In contrast to space creation, no need to lock here. ClassLoaderMetaspace::allocate() will lock itself.
       
   181             MetaWord* const p = _spaces[index].space->allocate(size, mdType);
       
   182             if (p == NULL) {
       
   183               // We very probably did hit the metaspace "until-gc" limit.
       
   184 #ifdef DEBUG_VERBOSE
       
   185               tty->print_cr("OOM for " SIZE_FORMAT " words. ", size);
       
   186 #endif
       
   187               // Just switch to deallocation and resume tests.
       
   188               force_switch = true;
       
   189               break;
       
   190             } else {
       
   191               _spaces[index].allocated += size;
       
   192               allocs_done ++;
       
   193             }
       
   194           }
       
   195         }
       
   196       } else {
       
   197         // freeing: find a metaspace and delete it, with preference for completely filled spaces.
       
   198         int index = get_random_full_space(metaspaces);
       
   199         if (index == -1) {
       
   200           index = get_random_non_emtpy_space(metaspaces);
       
   201         }
       
   202         if (index == -1) {
       
   203           force_switch = true;
       
   204         } else {
       
   205           assert(_spaces[index].space != NULL && _spaces[index].allocated > 0, "Sanity");
       
   206           // Note: do not lock here. In the "wild" (the VM), we do not so either (see ~ClassLoaderData()).
       
   207           delete _spaces[index].space;
       
   208           _spaces[index].space = NULL;
       
   209           _spaces[index].allocated = 0;
       
   210         }
       
   211       }
       
   212 
       
   213       if (force_switch) {
       
   214         allocating = !allocating;
       
   215       } else {
       
   216         // periodically switch between allocating and freeing, but prefer allocation because
       
   217         // we want to intermingle allocations of multiple metaspaces.
       
   218         allocating = os::random() % 5 < 4;
       
   219       }
       
   220       phases_done ++;
       
   221 #ifdef DEBUG_VERBOSE
       
   222       int metaspaces_in_use = 0;
       
   223       size_t total_allocated = 0;
       
   224       for (int i = 0; i < metaspaces; i ++) {
       
   225         if (_spaces[i].allocated > 0) {
       
   226           total_allocated += _spaces[i].allocated;
       
   227           metaspaces_in_use ++;
       
   228         }
       
   229       }
       
   230       tty->print("%u:\tspaces: %d total words: " SIZE_FORMAT "\t\t\t", phases_done, metaspaces_in_use, total_allocated);
       
   231       print_chunkmanager_statistics(tty, mdType);
       
   232 #endif
       
   233     }
       
   234 #ifdef DEBUG_VERBOSE
       
   235     tty->print_cr("Test finished. ");
       
   236     MetaspaceUtils::print_metaspace_map(tty, mdType);
       
   237     print_chunkmanager_statistics(tty, mdType);
       
   238 #endif
       
   239   }
       
   240 };
       
   241 
       
   242 
       
   243 
       
   244 TEST_F(MetaspaceAllocationTest, chunk_geometry) {
       
   245   ASSERT_GT(_chunk_geometry.specialized_chunk_word_size, (size_t) 0);
       
   246   ASSERT_GT(_chunk_geometry.small_chunk_word_size, _chunk_geometry.specialized_chunk_word_size);
       
   247   ASSERT_EQ(_chunk_geometry.small_chunk_word_size % _chunk_geometry.specialized_chunk_word_size, (size_t)0);
       
   248   ASSERT_GT(_chunk_geometry.medium_chunk_word_size, _chunk_geometry.small_chunk_word_size);
       
   249   ASSERT_EQ(_chunk_geometry.medium_chunk_word_size % _chunk_geometry.small_chunk_word_size, (size_t)0);
       
   250 }
       
   251 
       
   252 
       
   253 TEST_VM_F(MetaspaceAllocationTest, single_space_nonclass) {
       
   254   do_test(Metaspace::NonClassType, 1, 1000, 100, 0);
       
   255 }
       
   256 
       
   257 TEST_VM_F(MetaspaceAllocationTest, single_space_class) {
       
   258   do_test(Metaspace::ClassType, 1, 1000, 100, 0);
       
   259 }
       
   260 
       
   261 TEST_VM_F(MetaspaceAllocationTest, multi_space_nonclass) {
       
   262   do_test(Metaspace::NonClassType, NUM_PARALLEL_METASPACES, 100, 1000, 0.0);
       
   263 }
       
   264 
       
   265 TEST_VM_F(MetaspaceAllocationTest, multi_space_class) {
       
   266   do_test(Metaspace::ClassType, NUM_PARALLEL_METASPACES, 100, 1000, 0.0);
       
   267 }
       
   268 
       
   269 TEST_VM_F(MetaspaceAllocationTest, multi_space_nonclass_2) {
       
   270   // many metaspaces, with humongous chunks mixed in.
       
   271   do_test(Metaspace::NonClassType, NUM_PARALLEL_METASPACES, 100, 1000, .006f);
       
   272 }
       
   273