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_BINLIST_HPP
  27 #define SHARE_MEMORY_METASPACE_BINLIST_HPP
  28 
  29 #include "utilities/align.hpp"
  30 #include "utilities/debug.hpp"
  31 #include "utilities/globalDefinitions.hpp"
  32 #include "memory/metaspace/counter.hpp"
  33 #include "memory/metaspace/metaspaceCommon.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 
  69 // Insertion is of course fast, O(1).
  70 //
  71 // On retrieval, we attempt to find the closest fit to a given size, walking the
  72 // list head vector (a bitmask is used to speed that part up).
  73 //
  74 // This structure is a bit expensive in memory costs (we pay one pointer per managed
  75 // block size) so we only use it for a small number of sizes.
  76 
  77 template <size_t smallest_size, int num_lists>
  78 class BinListImpl {
  79 
  80   struct block_t { block_t* next; size_t size; };
  81 
  82   // a mask to speed up searching for populated lists.
  83   // 0 marks an empty list, 1 for a non-empty one.
  84   typedef uint32_t mask_t;
  85   STATIC_ASSERT(num_lists <= sizeof(mask_t) * 8);
  86 
  87   mask_t _mask;
  88 
  89   // minimal block size must be large enough to hold a block.
  90   STATIC_ASSERT(smallest_size * sizeof(MetaWord) >= sizeof(block_t));
  91 
  92 public:
  93 
  94   // block sizes this structure can keep are limited by [_min_block_size, _max_block_size)
  95   const static size_t minimal_word_size = smallest_size;
  96   const static size_t maximal_word_size = minimal_word_size + num_lists;
  97 
  98 private:
  99 
 100   block_t* _v[num_lists];
 101 
 102   MemRangeCounter _counter;
 103 
 104   static int index_for_word_size(size_t word_size) {
 105     int index = (int)(word_size - minimal_word_size);
 106     assert(index >= 0 && index < num_lists, "Invalid index %d", index);
 107     return index;
 108   }
 109 
 110   static size_t word_size_for_index(int index) {
 111     assert(index >= 0 && index < num_lists, "Invalid index %d", index);
 112     return minimal_word_size + index;
 113   }
 114 
 115   // Search the range [index, _num_lists) for the smallest non-empty list. Returns -1 on fail.
 116   int index_for_next_non_empty_list(int index) {
 117     assert(index >= 0 && index < num_lists, "Invalid index %d", index);
 118     int i2 = index;
 119     mask_t m = _mask >> i2;
 120     if (m > 0) {
 121       // count leading zeros would be helpful.
 122       while ((m & 1) == 0) {
 123         assert(_v[i2] == NULL, "mask mismatch");
 124         i2 ++;
 125         m >>= 1;
 126       }
 127       // We must have found something.
 128       assert(i2 < num_lists, "sanity.");
 129       assert(_v[i2] != NULL, "mask mismatch");
 130       return i2;
 131     }
 132     return -1;
 133   }
 134 
 135   void mask_set_bit(int bit) { _mask |= (((mask_t)1) << bit); }
 136   void mask_clr_bit(int bit) { _mask &= ~(((mask_t)1) << bit); }
 137 
 138 public:
 139 
 140   BinListImpl() : _mask(0) {
 141     for (int i = 0; i < num_lists; i ++) {
 142       _v[i] = NULL;
 143     }
 144   }
 145 
 146   void add_block(MetaWord* p, size_t word_size) {
 147     assert(word_size >= minimal_word_size &&
 148            word_size < maximal_word_size, "bad block size");
 149     const int index = index_for_word_size(word_size);
 150     block_t* b = (block_t*)p;
 151     b->size = word_size;
 152     b->next = _v[index];
 153     _v[index] = b;
 154     _counter.add(word_size);
 155     mask_set_bit(index);
 156   }
 157 
 158   // Given a word_size, searches and returns a block of at least that size.
 159   // Block may be larger. Real block size is returned in *p_real_word_size.
 160   MetaWord* get_block(size_t word_size, size_t* p_real_word_size) {
 161     assert(word_size >= minimal_word_size &&
 162            word_size < maximal_word_size, "bad block size " SIZE_FORMAT ".", word_size);
 163     int index = index_for_word_size(word_size);
 164     index = index_for_next_non_empty_list(index);
 165     if (index != -1) {
 166       assert(_v[index] != NULL &&
 167              _v[index]->size >= word_size, "sanity");
 168 
 169       MetaWord* const p = (MetaWord*)_v[index];
 170       const size_t real_word_size = word_size_for_index(index);
 171 
 172       _v[index] = _v[index]->next;
 173       if (_v[index] == NULL) {
 174         mask_clr_bit(index);
 175       }
 176 
 177       _counter.sub(real_word_size);
 178       *p_real_word_size = real_word_size;
 179 
 180       return p;
 181 
 182     } else {
 183 
 184       *p_real_word_size = 0;
 185       return NULL;
 186 
 187     }
 188   }
 189 
 190 
 191   // Returns number of blocks in this structure
 192   unsigned count() const { return _counter.count(); }
 193 
 194   // Returns total size, in words, of all elements.
 195   size_t total_size() const { return _counter.total_size(); }
 196 
 197   bool is_empty() const { return _mask == 0; }
 198 
 199 #ifdef ASSERT
 200   void verify() const {
 201     MemRangeCounter local_counter;
 202     for (int i = 0; i < num_lists; i ++) {
 203       assert(((_mask >> i) & 1) == ((_v[i] == 0) ? 0 : 1), "sanity");
 204       const size_t s = minimal_word_size + i;
 205       for (block_t* b = _v[i]; b != NULL; b = b->next) {
 206         assert(b->size == s, "bad block size");
 207         local_counter.add(s);
 208       }
 209     }
 210     local_counter.check(_counter);
 211   }
 212 #endif // ASSERT
 213 
 214 
 215 };
 216 
 217 typedef BinListImpl<2, 8>  BinList8;
 218 typedef BinListImpl<2, 16> BinList16;
 219 typedef BinListImpl<2, 32> BinList32;
 220 typedef BinListImpl<2, 64> BinList64;
 221 
 222 } // namespace metaspace
 223 
 224 #endif // SHARE_MEMORY_METASPACE_BINLIST_HPP