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