1 /*
   2  * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #ifndef SHARE_VM_MEMORY_BINARYTREEDICTIONARY_HPP
  26 #define SHARE_VM_MEMORY_BINARYTREEDICTIONARY_HPP
  27 
  28 #include "memory/freeBlockDictionary.hpp"
  29 #include "memory/freeList.hpp"
  30 
  31 /*
  32  * A binary tree based search structure for free blocks.
  33  * This is currently used in the Concurrent Mark&Sweep implementation, but
  34  * will be used for free block management for metadata.
  35  */
  36 
  37 // A TreeList is a FreeList which can be used to maintain a
  38 // binary tree of free lists.
  39 
  40 template <class Chunk_t, class FreeList_t> class TreeChunk;
  41 template <class Chunk_t, class FreeList_t> class BinaryTreeDictionary;
  42 template <class Chunk_t, class FreeList_t> class AscendTreeCensusClosure;
  43 template <class Chunk_t, class FreeList_t> class DescendTreeCensusClosure;
  44 template <class Chunk_t, class FreeList_t> class DescendTreeSearchClosure;
  45 
  46 class FreeChunk;
  47 template <class> class AdaptiveFreeList;
  48 typedef BinaryTreeDictionary<FreeChunk, AdaptiveFreeList<FreeChunk> > AFLBinaryTreeDictionary;
  49 
  50 template <class Chunk_t, class FreeList_t>
  51 class TreeList : public FreeList_t {
  52   friend class TreeChunk<Chunk_t, FreeList_t>;
  53   friend class BinaryTreeDictionary<Chunk_t, FreeList_t>;
  54   friend class AscendTreeCensusClosure<Chunk_t, FreeList_t>;
  55   friend class DescendTreeCensusClosure<Chunk_t, FreeList_t>;
  56   friend class DescendTreeSearchClosure<Chunk_t, FreeList_t>;
  57 
  58   TreeList<Chunk_t, FreeList_t>* _parent;
  59   TreeList<Chunk_t, FreeList_t>* _left;
  60   TreeList<Chunk_t, FreeList_t>* _right;
  61 
  62  protected:
  63 
  64   TreeList<Chunk_t, FreeList_t>* parent() const { return _parent; }
  65   TreeList<Chunk_t, FreeList_t>* left()   const { return _left;   }
  66   TreeList<Chunk_t, FreeList_t>* right()  const { return _right;  }
  67 
  68   // Wrapper on call to base class, to get the template to compile.
  69   Chunk_t* head() const { return FreeList_t::head(); }
  70   Chunk_t* tail() const { return FreeList_t::tail(); }
  71   void set_head(Chunk_t* head) { FreeList_t::set_head(head); }
  72   void set_tail(Chunk_t* tail) { FreeList_t::set_tail(tail); }
  73 
  74   size_t size() const { return FreeList_t::size(); }
  75 
  76   // Accessors for links in tree.
  77 
  78   void set_left(TreeList<Chunk_t, FreeList_t>* tl) {
  79     _left   = tl;
  80     if (tl != NULL)
  81       tl->set_parent(this);
  82   }
  83   void set_right(TreeList<Chunk_t, FreeList_t>* tl) {
  84     _right  = tl;
  85     if (tl != NULL)
  86       tl->set_parent(this);
  87   }
  88   void set_parent(TreeList<Chunk_t, FreeList_t>* tl)  { _parent = tl;   }
  89 
  90   void clear_left()               { _left = NULL;   }
  91   void clear_right()              { _right = NULL;  }
  92   void clear_parent()             { _parent = NULL; }
  93   void initialize()               { clear_left(); clear_right(), clear_parent(); FreeList_t::initialize(); }
  94 
  95   // For constructing a TreeList from a Tree chunk or
  96   // address and size.
  97   TreeList();
  98   static TreeList<Chunk_t, FreeList_t>*
  99           as_TreeList(TreeChunk<Chunk_t, FreeList_t>* tc);
 100   static TreeList<Chunk_t, FreeList_t>* as_TreeList(HeapWord* addr, size_t size);
 101 
 102   // Returns the head of the free list as a pointer to a TreeChunk.
 103   TreeChunk<Chunk_t, FreeList_t>* head_as_TreeChunk();
 104 
 105   // Returns the first available chunk in the free list as a pointer
 106   // to a TreeChunk.
 107   TreeChunk<Chunk_t, FreeList_t>* first_available();
 108 
 109   // Returns the block with the largest heap address amongst
 110   // those in the list for this size; potentially slow and expensive,
 111   // use with caution!
 112   TreeChunk<Chunk_t, FreeList_t>* largest_address();
 113 
 114   TreeList<Chunk_t, FreeList_t>* get_better_list(
 115     BinaryTreeDictionary<Chunk_t, FreeList_t>* dictionary);
 116 
 117   // remove_chunk_replace_if_needed() removes the given "tc" from the TreeList.
 118   // If "tc" is the first chunk in the list, it is also the
 119   // TreeList that is the node in the tree.  remove_chunk_replace_if_needed()
 120   // returns the possibly replaced TreeList* for the node in
 121   // the tree.  It also updates the parent of the original
 122   // node to point to the new node.
 123   TreeList<Chunk_t, FreeList_t>* remove_chunk_replace_if_needed(TreeChunk<Chunk_t, FreeList_t>* tc);
 124   // See FreeList.
 125   void return_chunk_at_head(TreeChunk<Chunk_t, FreeList_t>* tc);
 126   void return_chunk_at_tail(TreeChunk<Chunk_t, FreeList_t>* tc);
 127 };
 128 
 129 // A TreeChunk is a subclass of a Chunk that additionally
 130 // maintains a pointer to the free list on which it is currently
 131 // linked.
 132 // A TreeChunk is also used as a node in the binary tree.  This
 133 // allows the binary tree to be maintained without any additional
 134 // storage (the free chunks are used).  In a binary tree the first
 135 // chunk in the free list is also the tree node.  Note that the
 136 // TreeChunk has an embedded TreeList for this purpose.  Because
 137 // the first chunk in the list is distinguished in this fashion
 138 // (also is the node in the tree), it is the last chunk to be found
 139 // on the free list for a node in the tree and is only removed if
 140 // it is the last chunk on the free list.
 141 
 142 template <class Chunk_t, class FreeList_t>
 143 class TreeChunk : public Chunk_t {
 144  private:
 145   friend class TreeList<Chunk_t, FreeList_t>;
 146   TreeList<Chunk_t, FreeList_t>* _list;
 147   TreeList<Chunk_t, FreeList_t> _embedded_list;  // if non-null, this chunk is on _list
 148 
 149   static size_t _min_tree_chunk_size;
 150 
 151  protected:
 152   TreeList<Chunk_t, FreeList_t>* embedded_list() const { return (TreeList<Chunk_t, FreeList_t>*) &_embedded_list; }
 153   void set_embedded_list(TreeList<Chunk_t, FreeList_t>* v) { _embedded_list = *v; }
 154  public:
 155   TreeList<Chunk_t, FreeList_t>* list() { return _list; }
 156   void set_list(TreeList<Chunk_t, FreeList_t>* v) { _list = v; }
 157   static TreeChunk<Chunk_t, FreeList_t>* as_TreeChunk(Chunk_t* fc);
 158   // Initialize fields in a TreeChunk that should be
 159   // initialized when the TreeChunk is being added to
 160   // a free list in the tree.
 161   void initialize() { embedded_list()->initialize(); }
 162 
 163   Chunk_t* next() const { return Chunk_t::next(); }
 164   Chunk_t* prev() const { return Chunk_t::prev(); }
 165   size_t size() const volatile { return Chunk_t::size(); }
 166 
 167   static size_t min_size();
 168 
 169   // debugging
 170   void verify_tree_chunk_list() const;
 171   void assert_is_mangled() const;
 172 };
 173 
 174 template <class Chunk_t, class FreeList_t>
 175 size_t TreeChunk<Chunk_t, FreeList_t>::_min_tree_chunk_size = sizeof(TreeChunk<Chunk_t, FreeList_t>)/HeapWordSize;
 176 template <class Chunk_t, class FreeList_t>
 177 size_t TreeChunk<Chunk_t, FreeList_t>::min_size() { return _min_tree_chunk_size; }
 178  
 179 template <class Chunk_t, class FreeList_t>
 180 class BinaryTreeDictionary: public FreeBlockDictionary<Chunk_t> {
 181   friend class VMStructs;
 182   size_t     _total_size;
 183   size_t     _total_free_blocks;
 184   TreeList<Chunk_t, FreeList_t>* _root;
 185 
 186   // private accessors
 187   void set_total_size(size_t v) { _total_size = v; }
 188   virtual void inc_total_size(size_t v);
 189   virtual void dec_total_size(size_t v);
 190   void set_total_free_blocks(size_t v) { _total_free_blocks = v; }
 191   TreeList<Chunk_t, FreeList_t>* root() const { return _root; }
 192   void set_root(TreeList<Chunk_t, FreeList_t>* v) { _root = v; }
 193 
 194   // This field is added and can be set to point to the
 195   // the Mutex used to synchronize access to the
 196   // dictionary so that assertion checking can be done.
 197   // For example it is set to point to _parDictionaryAllocLock.
 198   NOT_PRODUCT(Mutex* _lock;)
 199 
 200   // Remove a chunk of size "size" or larger from the tree and
 201   // return it.  If the chunk
 202   // is the last chunk of that size, remove the node for that size
 203   // from the tree.
 204   TreeChunk<Chunk_t, FreeList_t>* get_chunk_from_tree(size_t size, enum FreeBlockDictionary<Chunk_t>::Dither dither);
 205   // Remove this chunk from the tree.  If the removal results
 206   // in an empty list in the tree, remove the empty list.
 207   TreeChunk<Chunk_t, FreeList_t>* remove_chunk_from_tree(TreeChunk<Chunk_t, FreeList_t>* tc);
 208   // Remove the node in the trees starting at tl that has the
 209   // minimum value and return it.  Repair the tree as needed.
 210   TreeList<Chunk_t, FreeList_t>* remove_tree_minimum(TreeList<Chunk_t, FreeList_t>* tl);
 211   // Add this free chunk to the tree.
 212   void       insert_chunk_in_tree(Chunk_t* freeChunk);
 213  public:
 214 
 215   // Return a list of the specified size or NULL from the tree.
 216   // The list is not removed from the tree.
 217   TreeList<Chunk_t, FreeList_t>* find_list (size_t size) const;
 218 
 219   void       verify_tree() const;
 220   // verify that the given chunk is in the tree.
 221   bool       verify_chunk_in_free_list(Chunk_t* tc) const;
 222  private:
 223   void          verify_tree_helper(TreeList<Chunk_t, FreeList_t>* tl) const;
 224   static size_t verify_prev_free_ptrs(TreeList<Chunk_t, FreeList_t>* tl);
 225 
 226   // Returns the total number of chunks in the list.
 227   size_t     total_list_length(TreeList<Chunk_t, FreeList_t>* tl) const;
 228   // Returns the total number of words in the chunks in the tree
 229   // starting at "tl".
 230   size_t     total_size_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const;
 231   // Returns the sum of the square of the size of each block
 232   // in the tree starting at "tl".
 233   double     sum_of_squared_block_sizes(TreeList<Chunk_t, FreeList_t>* const tl) const;
 234   // Returns the total number of free blocks in the tree starting
 235   // at "tl".
 236   size_t     total_free_blocks_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const;
 237   size_t     num_free_blocks()  const;
 238   size_t     tree_height() const;
 239   size_t     tree_height_helper(TreeList<Chunk_t, FreeList_t>* tl) const;
 240   size_t     total_nodes_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const;
 241   size_t     total_nodes_helper(TreeList<Chunk_t, FreeList_t>* tl) const;
 242 
 243  public:
 244   // Constructor
 245   BinaryTreeDictionary() :
 246     _total_size(0), _total_free_blocks(0), _root(0) {}
 247 
 248   BinaryTreeDictionary(MemRegion mr);
 249 
 250   // Public accessors
 251   size_t total_size() const { return _total_size; }
 252   size_t total_free_blocks() const { return _total_free_blocks; }
 253 
 254   // Reset the dictionary to the initial conditions with
 255   // a single free chunk.
 256   void       reset(MemRegion mr);
 257   void       reset(HeapWord* addr, size_t size);
 258   // Reset the dictionary to be empty.
 259   void       reset();
 260 
 261   // Return a chunk of size "size" or greater from
 262   // the tree.
 263   Chunk_t* get_chunk(size_t size, enum FreeBlockDictionary<Chunk_t>::Dither dither) {
 264     FreeBlockDictionary<Chunk_t>::verify_par_locked();
 265     Chunk_t* res = get_chunk_from_tree(size, dither);
 266     assert(res == NULL || res->is_free(),
 267            "Should be returning a free chunk");
 268     assert(dither != FreeBlockDictionary<Chunk_t>::exactly ||
 269            res == NULL || res->size() == size, "Not correct size");
 270     return res;
 271   }
 272 
 273   void return_chunk(Chunk_t* chunk) {
 274     FreeBlockDictionary<Chunk_t>::verify_par_locked();
 275     insert_chunk_in_tree(chunk);
 276   }
 277 
 278   void remove_chunk(Chunk_t* chunk) {
 279     FreeBlockDictionary<Chunk_t>::verify_par_locked();
 280     remove_chunk_from_tree((TreeChunk<Chunk_t, FreeList_t>*)chunk);
 281     assert(chunk->is_free(), "Should still be a free chunk");
 282   }
 283 
 284   size_t     max_chunk_size() const;
 285   size_t     total_chunk_size(debug_only(const Mutex* lock)) const {
 286     debug_only(
 287       if (lock != NULL && lock->owned_by_self()) {
 288         assert(total_size_in_tree(root()) == total_size(),
 289                "_total_size inconsistency");
 290       }
 291     )
 292     return total_size();
 293   }
 294 
 295   size_t     min_size() const {
 296     return TreeChunk<Chunk_t, FreeList_t>::min_size();
 297   }
 298 
 299   double     sum_of_squared_block_sizes() const {
 300     return sum_of_squared_block_sizes(root());
 301   }
 302 
 303   Chunk_t* find_chunk_ends_at(HeapWord* target) const;
 304 
 305   // Find the list with size "size" in the binary tree and update
 306   // the statistics in the list according to "split" (chunk was
 307   // split or coalesce) and "birth" (chunk was added or removed).
 308   void       dict_census_update(size_t size, bool split, bool birth);
 309   // Return true if the dictionary is overpopulated (more chunks of
 310   // this size than desired) for size "size".
 311   bool       coal_dict_over_populated(size_t size);
 312   // Methods called at the beginning of a sweep to prepare the
 313   // statistics for the sweep.
 314   void       begin_sweep_dict_census(double coalSurplusPercent,
 315                                   float inter_sweep_current,
 316                                   float inter_sweep_estimate,
 317                                   float intra_sweep_estimate);
 318   // Methods called after the end of a sweep to modify the
 319   // statistics for the sweep.
 320   void       end_sweep_dict_census(double splitSurplusPercent);
 321   // Return the largest free chunk in the tree.
 322   Chunk_t* find_largest_dict() const;
 323   // Accessors for statistics
 324   void       set_tree_surplus(double splitSurplusPercent);
 325   void       set_tree_hints(void);
 326   // Reset statistics for all the lists in the tree.
 327   void       clear_tree_census(void);
 328   // Print the statistics for all the lists in the tree.  Also may
 329   // print out summaries.
 330   void       print_dict_census(outputStream* st) const;
 331   void       print_free_lists(outputStream* st) const;
 332 
 333   // For debugging.  Returns the sum of the _returned_bytes for
 334   // all lists in the tree.
 335   size_t     sum_dict_returned_bytes()     PRODUCT_RETURN0;
 336   // Sets the _returned_bytes for all the lists in the tree to zero.
 337   void       initialize_dict_returned_bytes()      PRODUCT_RETURN;
 338   // For debugging.  Return the total number of chunks in the dictionary.
 339   size_t     total_count()       PRODUCT_RETURN0;
 340 
 341   void       report_statistics(outputStream* st) const;
 342 
 343   void       verify() const;
 344 };
 345 
 346 #endif // SHARE_VM_MEMORY_BINARYTREEDICTIONARY_HPP