1 /*
   2  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2020 SAP SE. All rights reserved.
   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 
  26 #include "precompiled.hpp"
  27 #include "memory/metaspace/msFreeChunkList.hpp"
  28 #include "utilities/globalDefinitions.hpp"
  29 #include "utilities/debug.hpp"
  30 #include "utilities/ostream.hpp"
  31 
  32 namespace metaspace {
  33 
  34 void FreeChunkList::print_on(outputStream* st) const {
  35 
  36   if (_num_chunks.get() > 0) {
  37     for (const Metachunk* c = _first; c != NULL; c = c->next()) {
  38       st->print(" - <");
  39       c->print_on(st);
  40       st->print(">");
  41     }
  42     st->print(" - total : %d chunks.", _num_chunks.get());
  43   } else {
  44     st->print("empty");
  45   }
  46 
  47 }
  48 
  49 #ifdef ASSERT
  50 
  51 bool FreeChunkList::contains(const Metachunk* c) const {
  52   for (Metachunk* c2 = _first; c2 != NULL; c2 = c2->next()) {
  53     if (c2 == c) {
  54       return true;
  55     }
  56   }
  57   return false;
  58 }
  59 
  60 void FreeChunkList::verify() const {
  61 
  62   if (_first == NULL) {
  63     assert(_last == NULL, "Sanity");
  64   } else {
  65     assert(_last != NULL, "Sanity");
  66     size_t committed = 0;
  67     int num = 0;
  68     bool uncommitted = (_first->committed_words() == 0);
  69     for (Metachunk* c = _first; c != NULL; c = c->next()) {
  70       assert(c->is_free(), "Chunks in freelist should be free");
  71       assert(c->used_words() == 0, "Chunk in freelist should have not used words.");
  72       assert(c->level() == _first->level(), "wrong level");
  73       assert(c->next() == NULL || c->next()->prev() == c, "front link broken");
  74       assert(c->prev() == NULL || c->prev()->next() == c, "back link broken");
  75       assert(c != c->prev() && c != c->next(), "circle");
  76       c->verify();
  77       committed += c->committed_words();
  78       num++;
  79     }
  80     _num_chunks.check(num);
  81     _committed_word_size.check(committed);
  82   }
  83 
  84 }
  85 
  86 #endif // ASSERT
  87 
  88 // Returns total size in all lists (regardless of commit state of underlying memory)
  89 size_t FreeChunkListVector::word_size() const {
  90   size_t sum = 0;
  91   for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) {
  92     sum += list_for_level(l)->num_chunks() * chunklevel::word_size_for_level(l);
  93   }
  94   return sum;
  95 }
  96 
  97 // Returns total committed size in all lists
  98 size_t FreeChunkListVector::committed_word_size() const {
  99   size_t sum = 0;
 100   for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) {
 101     sum += list_for_level(l)->committed_word_size();
 102   }
 103   return sum;
 104 }
 105 
 106 // Returns total committed size in all lists
 107 int FreeChunkListVector::num_chunks() const {
 108   int n = 0;
 109   for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) {
 110     n += list_for_level(l)->num_chunks();
 111   }
 112   return n;
 113 }
 114 
 115 // Look for a chunk: starting at level, up to and including max_level,
 116 //  return the first chunk whose committed words >= min_committed_words.
 117 // Return NULL if no such chunk was found.
 118 Metachunk* FreeChunkListVector::search_chunk_ascending(chunklevel_t level, chunklevel_t max_level, size_t min_committed_words) {
 119   assert(min_committed_words <= chunklevel::word_size_for_level(max_level),
 120          "min chunk size too small to hold min_committed_words");
 121   for (chunklevel_t l = level; l <= max_level; l++) {
 122     Metachunk* c = list_for_level(l)->first();
 123     if (c != NULL && c->committed_words() >= min_committed_words) {
 124       list_for_level(l)->remove(c);
 125       return c;
 126     }
 127   }
 128   return NULL;
 129 }
 130 
 131 // Look for a chunk: starting at level, down to (including) the root chunk level,
 132 // return the first chunk whose committed words >= min_committed_words.
 133 // Return NULL if no such chunk was found.
 134 Metachunk* FreeChunkListVector::search_chunk_descending(chunklevel_t level, size_t min_committed_words) {
 135   for (chunklevel_t l = level; l >= chunklevel::LOWEST_CHUNK_LEVEL; l --) {
 136     Metachunk* c = list_for_level(l)->first();
 137     if (c != NULL && c->committed_words() >= min_committed_words) {
 138       list_for_level(l)->remove(c);
 139       return c;
 140     }
 141   }
 142   return NULL;
 143 }
 144 
 145 void FreeChunkListVector::print_on(outputStream* st) const {
 146   for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) {
 147     st->print("-- List[" CHKLVL_FORMAT "]: ", l);
 148     list_for_level(l)->print_on(st);
 149     st->cr();
 150   }
 151   st->print_cr("total chunks: %d, total word size: " SIZE_FORMAT ", committed word size: " SIZE_FORMAT ".",
 152                num_chunks(), word_size(), committed_word_size());
 153 }
 154 
 155 #ifdef ASSERT
 156 
 157 void FreeChunkListVector::verify() const {
 158   for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) {
 159     list_for_level(l)->verify();
 160   }
 161 }
 162 
 163 bool FreeChunkListVector::contains(const Metachunk* c) const {
 164   for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) {
 165     if (list_for_level(l)->contains(c)) {
 166       return true;
 167     }
 168   }
 169   return false;
 170 }
 171 
 172 #endif // ASSERT
 173 
 174 } // namespace metaspace
 175