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 #ifndef SHARE_MEMORY_METASPACE_MSBINLIST_HPP
  27 #define SHARE_MEMORY_METASPACE_MSBINLIST_HPP
  28 
  29 #include "memory/metaspace/msCommon.hpp"
  30 #include "memory/metaspace/msCounter.hpp"
  31 #include "utilities/align.hpp"
  32 #include "utilities/debug.hpp"
  33 #include "utilities/globalDefinitions.hpp"
  34 
  35 namespace metaspace {
  36 
  37 // BinList is a data structure to manage small to very small memory blocks
  38 // (only a few words). It is used to manage deallocated blocks - see
  39 // class FreeBlocks.
  40 
  41 // Memory blocks are kept in linked lists. Each list
  42 // contains blocks of only one size. There is a list for blocks of two words,
  43 // for blocks of three words, etc. The list heads are kept in a vector,
  44 // ordered by block size.
  45 //
  46 
  47 // wordsize
  48 //
  49 //       +---+   +---+   +---+      +---+
  50 //  1    |   |-->|   |-->|   |-...->|   |
  51 //       +---+   +---+   +---+      +---+
  52 //
  53 //       +----+   +----+   +----+      +----+
  54 //  2    |    |-->|    |-->|    |-...->|    |
  55 //       +----+   +----+   +----+      +----+
  56 //
  57 //       +-----+   +-----+   +-----+      +-----+
  58 //  3    |     |-->|     |-->|     |-...->|     |
  59 //       +-----+   +-----+   +-----+      +-----+
  60 //  .
  61 //  .
  62 //  .
  63 //
  64 //       +----------+   +----------+   +----------+      +----------+
  65 //  n    |          |-->|          |-->|          |-...->|          |
  66 //       +----------+   +----------+   +----------+      +----------+
  67 
  68 // Insertion is of course fast, O(1).
  69 //
  70 // On retrieval, we attempt to find the closest fit to a given size, walking the
  71 // list head vector (a bitmask is used to speed that part up).
  72 //
  73 // This structure is a bit expensive in memory costs (we pay one pointer per managed
  74 // block size) so we only use it for a small number of sizes.
  75 
  76 template <size_t smallest_word_size, int num_lists>
  77 class BinListImpl {
  78 
  79   struct Block {
  80     Block* const _next;
  81     const size_t _word_size;
  82     Block(Block* next, size_t word_size)
  83       : _next(next), _word_size(word_size)
  84     {}
  85   };
  86 
  87   // a mask to speed up searching for populated lists.
  88   // 0 marks an empty list, 1 for a non-empty one.
  89   typedef uint32_t mask_t;
  90   STATIC_ASSERT(num_lists <= sizeof(mask_t) * 8);
  91 
  92   mask_t _mask;
  93 
  94   // Smallest block size must be large enough to hold a Block structure.
  95   STATIC_ASSERT(smallest_word_size * sizeof(MetaWord) >= sizeof(Block));
  96 
  97   STATIC_ASSERT(num_lists > 0);
  98 
  99 public:
 100 
 101   // Minimal word size a block must have to be manageable by this structure.
 102   const static size_t MinWordSize = smallest_word_size;
 103 
 104   // Maximal (incl) word size a block can have to be manageable by this structure.
 105   const static size_t MaxWordSize = MinWordSize + num_lists - 1;
 106 
 107 private:
 108 
 109   Block* _blocks[num_lists];
 110 
 111   MemRangeCounter _counter;
 112 
 113   static int index_for_word_size(size_t word_size) {
 114     int index = (int)(word_size - MinWordSize);
 115     assert(index >= 0 && index < num_lists, "Invalid index %d", index);
 116     return index;
 117   }
 118 
 119   static size_t word_size_for_index(int index) {
 120     assert(index >= 0 && index < num_lists, "Invalid index %d", index);
 121     return MinWordSize + index;
 122   }
 123 
 124   // Search the range [index, _num_lists) for the smallest non-empty list. Returns -1 on fail.
 125   int index_for_next_non_empty_list(int index) {
 126     assert(index >= 0 && index < num_lists, "Invalid index %d", index);
 127     int i2 = index;
 128     mask_t m = _mask >> i2;
 129     if (m > 0) {
 130       // count leading zeros would be helpful.
 131       while ((m & 1) == 0) {
 132         assert(_blocks[i2] == NULL, "mask mismatch");
 133         i2++;
 134         m >>= 1;
 135       }
 136       // We must have found something.
 137       assert(i2 < num_lists, "sanity.");
 138       assert(_blocks[i2] != NULL, "mask mismatch");
 139       return i2;
 140     }
 141     return -1;
 142   }
 143 
 144   void mask_set_bit(int bit) { _mask |= (((mask_t)1) << bit); }
 145   void mask_clr_bit(int bit) { _mask &= ~(((mask_t)1) << bit); }
 146 
 147 public:
 148 
 149   BinListImpl() : _mask(0) {
 150     for (int i = 0; i < num_lists; i++) {
 151       _blocks[i] = NULL;
 152     }
 153   }
 154 
 155   void add_block(MetaWord* p, size_t word_size) {
 156     assert(word_size >= MinWordSize &&
 157            word_size <= MaxWordSize, "bad block size");
 158     const int index = index_for_word_size(word_size);
 159     Block* old_head = _blocks[index];
 160     Block* new_head = new(p)Block(old_head, word_size);
 161     _blocks[index] = new_head;
 162     _counter.add(word_size);
 163     mask_set_bit(index);
 164   }
 165 
 166   // Given a word_size, searches and returns a block of at least that size.
 167   // Block may be larger. Real block size is returned in *p_real_word_size.
 168   MetaWord* remove_block(size_t word_size, size_t* p_real_word_size) {
 169     assert(word_size >= MinWordSize &&
 170            word_size <= MaxWordSize, "bad block size " SIZE_FORMAT ".", word_size);
 171     int index = index_for_word_size(word_size);
 172     index = index_for_next_non_empty_list(index);
 173     if (index != -1) {
 174       assert(_blocks[index] != NULL &&
 175              _blocks[index]->_word_size >= word_size, "sanity");
 176 
 177       MetaWord* const p = (MetaWord*)_blocks[index];
 178       const size_t real_word_size = word_size_for_index(index);
 179 
 180       _blocks[index] = _blocks[index]->_next;
 181       if (_blocks[index] == NULL) {
 182         mask_clr_bit(index);
 183       }
 184 
 185       _counter.sub(real_word_size);
 186       *p_real_word_size = real_word_size;
 187 
 188       return p;
 189 
 190     } else {
 191       *p_real_word_size = 0;
 192       return NULL;
 193     }
 194   }
 195 
 196   // Returns number of blocks in this structure
 197   unsigned count() const { return _counter.count(); }
 198 
 199   // Returns total size, in words, of all elements.
 200   size_t total_size() const { return _counter.total_size(); }
 201 
 202   bool is_empty() const { return _mask == 0; }
 203 
 204 #ifdef ASSERT
 205   void verify() const {
 206     MemRangeCounter local_counter;
 207     for (int i = 0; i < num_lists; i++) {
 208       assert(((_mask >> i) & 1) == ((_blocks[i] == 0) ? 0 : 1), "sanity");
 209       const size_t s = MinWordSize + i;
 210       for (Block* b = _blocks[i]; b != NULL; b = b->_next) {
 211         assert(b->_word_size == s, "bad block size");
 212         local_counter.add(s);
 213       }
 214     }
 215     local_counter.check(_counter);
 216   }
 217 #endif // ASSERT
 218 
 219 };
 220 
 221 typedef BinListImpl<2, 32> BinList32;
 222 
 223 } // namespace metaspace
 224 
 225 #endif // SHARE_MEMORY_METASPACE_MSBINLIST_HPP