1 /*
   2  * Copyright (c) 2001, 2010, 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_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_BINARYTREEDICTIONARY_HPP
  26 #define SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_BINARYTREEDICTIONARY_HPP
  27 
  28 #include "gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp"
  29 #include "gc_implementation/concurrentMarkSweep/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.
  34  */
  35 
  36 // A TreeList is a FreeList which can be used to maintain a
  37 // binary tree of free lists.
  38 
  39 class TreeChunk;
  40 class BinaryTreeDictionary;
  41 class AscendTreeCensusClosure;
  42 class DescendTreeCensusClosure;
  43 class DescendTreeSearchClosure;
  44 
  45 class TreeList: public FreeList {
  46   friend class TreeChunk;
  47   friend class BinaryTreeDictionary;
  48   friend class AscendTreeCensusClosure;
  49   friend class DescendTreeCensusClosure;
  50   friend class DescendTreeSearchClosure;
  51 
  52  protected:
  53   TreeList* parent() const { return _parent; }
  54   TreeList* left()   const { return _left;   }
  55   TreeList* right()  const { return _right;  }
  56 
  57   // Accessors for links in tree.
  58 
  59   void setLeft(TreeList* tl) {
  60     _left   = tl;
  61     if (tl != NULL)
  62       tl->setParent(this);
  63   }
  64   void setRight(TreeList* tl) {
  65     _right  = tl;
  66     if (tl != NULL)
  67       tl->setParent(this);
  68   }
  69   void setParent(TreeList* tl)  { _parent = tl;   }
  70 
  71   void clearLeft()               { _left = NULL;   }
  72   void clearRight()              { _right = NULL;  }
  73   void clearParent()             { _parent = NULL; }
  74   void initialize()              { clearLeft(); clearRight(), clearParent(); }
  75 
  76   // For constructing a TreeList from a Tree chunk or
  77   // address and size.
  78   static TreeList* as_TreeList(TreeChunk* tc);
  79   static TreeList* as_TreeList(HeapWord* addr, size_t size);
  80 
  81   // Returns the head of the free list as a pointer to a TreeChunk.
  82   TreeChunk* head_as_TreeChunk();
  83 
  84   // Returns the first available chunk in the free list as a pointer
  85   // to a TreeChunk.
  86   TreeChunk* first_available();
  87 
  88   // Returns the block with the largest heap address amongst
  89   // those in the list for this size; potentially slow and expensive,
  90   // use with caution!
  91   TreeChunk* largest_address();
  92 
  93   // removeChunkReplaceIfNeeded() removes the given "tc" from the TreeList.
  94   // If "tc" is the first chunk in the list, it is also the
  95   // TreeList that is the node in the tree.  removeChunkReplaceIfNeeded()
  96   // returns the possibly replaced TreeList* for the node in
  97   // the tree.  It also updates the parent of the original
  98   // node to point to the new node.
  99   TreeList* removeChunkReplaceIfNeeded(TreeChunk* tc);
 100   // See FreeList.
 101   void returnChunkAtHead(TreeChunk* tc);
 102   void returnChunkAtTail(TreeChunk* tc);
 103 };
 104 
 105 // A TreeChunk is a subclass of a FreeChunk that additionally
 106 // maintains a pointer to the free list on which it is currently
 107 // linked.
 108 // A TreeChunk is also used as a node in the binary tree.  This
 109 // allows the binary tree to be maintained without any additional
 110 // storage (the free chunks are used).  In a binary tree the first
 111 // chunk in the free list is also the tree node.  Note that the
 112 // TreeChunk has an embedded TreeList for this purpose.  Because
 113 // the first chunk in the list is distinguished in this fashion
 114 // (also is the node in the tree), it is the last chunk to be found
 115 // on the free list for a node in the tree and is only removed if
 116 // it is the last chunk on the free list.
 117 
 118 class TreeChunk : public FreeChunk {
 119   friend class TreeList;
 120   TreeList* _list;
 121   TreeList _embedded_list;  // if non-null, this chunk is on _list
 122  protected:
 123   TreeList* embedded_list() const { return (TreeList*) &_embedded_list; }
 124   void set_embedded_list(TreeList* v) { _embedded_list = *v; }
 125  public:
 126   TreeList* list() { return _list; }
 127   void set_list(TreeList* v) { _list = v; }
 128   static TreeChunk* as_TreeChunk(FreeChunk* fc);
 129   // Initialize fields in a TreeChunk that should be
 130   // initialized when the TreeChunk is being added to
 131   // a free list in the tree.
 132   void initialize() { embedded_list()->initialize(); }
 133 
 134   // debugging
 135   void verifyTreeChunkList() const;
 136 };
 137 
 138 const size_t MIN_TREE_CHUNK_SIZE  = sizeof(TreeChunk)/HeapWordSize;
 139 
 140 class BinaryTreeDictionary: public FreeBlockDictionary {
 141   friend class VMStructs;
 142   bool       _splay;
 143   size_t     _totalSize;
 144   size_t     _totalFreeBlocks;
 145   TreeList* _root;
 146 
 147   // private accessors
 148   bool splay() const { return _splay; }
 149   void set_splay(bool v) { _splay = v; }
 150   size_t totalSize() const { return _totalSize; }
 151   void set_totalSize(size_t v) { _totalSize = v; }
 152   virtual void inc_totalSize(size_t v);
 153   virtual void dec_totalSize(size_t v);
 154   size_t totalFreeBlocks() const { return _totalFreeBlocks; }
 155   void set_totalFreeBlocks(size_t v) { _totalFreeBlocks = v; }
 156   TreeList* root() const { return _root; }
 157   void set_root(TreeList* v) { _root = v; }
 158 
 159   // Remove a chunk of size "size" or larger from the tree and
 160   // return it.  If the chunk
 161   // is the last chunk of that size, remove the node for that size
 162   // from the tree.
 163   TreeChunk* getChunkFromTree(size_t size, Dither dither, bool splay);
 164   // Return a list of the specified size or NULL from the tree.
 165   // The list is not removed from the tree.
 166   TreeList* findList (size_t size) const;
 167   // Remove this chunk from the tree.  If the removal results
 168   // in an empty list in the tree, remove the empty list.
 169   TreeChunk* removeChunkFromTree(TreeChunk* tc);
 170   // Remove the node in the trees starting at tl that has the
 171   // minimum value and return it.  Repair the tree as needed.
 172   TreeList* removeTreeMinimum(TreeList* tl);
 173   void       semiSplayStep(TreeList* tl);
 174   // Add this free chunk to the tree.
 175   void       insertChunkInTree(FreeChunk* freeChunk);
 176  public:
 177   void       verifyTree() const;
 178   // verify that the given chunk is in the tree.
 179   bool       verifyChunkInFreeLists(FreeChunk* tc) const;
 180  private:
 181   void          verifyTreeHelper(TreeList* tl) const;
 182   static size_t verifyPrevFreePtrs(TreeList* tl);
 183 
 184   // Returns the total number of chunks in the list.
 185   size_t     totalListLength(TreeList* tl) const;
 186   // Returns the total number of words in the chunks in the tree
 187   // starting at "tl".
 188   size_t     totalSizeInTree(TreeList* tl) const;
 189   // Returns the sum of the square of the size of each block
 190   // in the tree starting at "tl".
 191   double     sum_of_squared_block_sizes(TreeList* const tl) const;
 192   // Returns the total number of free blocks in the tree starting
 193   // at "tl".
 194   size_t     totalFreeBlocksInTree(TreeList* tl) const;
 195   size_t     numFreeBlocks() const;
 196   size_t     treeHeight() const;
 197   size_t     treeHeightHelper(TreeList* tl) const;
 198   size_t     totalNodesInTree(TreeList* tl) const;
 199   size_t     totalNodesHelper(TreeList* tl) const;
 200 
 201  public:
 202   // Constructor
 203   BinaryTreeDictionary(MemRegion mr, bool splay = false);
 204 
 205   // Reset the dictionary to the initial conditions with
 206   // a single free chunk.
 207   void       reset(MemRegion mr);
 208   void       reset(HeapWord* addr, size_t size);
 209   // Reset the dictionary to be empty.
 210   void       reset();
 211 
 212   // Return a chunk of size "size" or greater from
 213   // the tree.
 214   // want a better dynamic splay strategy for the future.
 215   FreeChunk* getChunk(size_t size, Dither dither) {
 216     verify_par_locked();
 217     FreeChunk* res = getChunkFromTree(size, dither, splay());
 218     assert(res == NULL || res->isFree(),
 219            "Should be returning a free chunk");
 220     return res;
 221   }
 222 
 223   void returnChunk(FreeChunk* chunk) {
 224     verify_par_locked();
 225     insertChunkInTree(chunk);
 226   }
 227 
 228   void removeChunk(FreeChunk* chunk) {
 229     verify_par_locked();
 230     removeChunkFromTree((TreeChunk*)chunk);
 231     assert(chunk->isFree(), "Should still be a free chunk");
 232   }
 233 
 234   size_t     maxChunkSize() const;
 235   size_t     totalChunkSize(debug_only(const Mutex* lock)) const {
 236     debug_only(
 237       if (lock != NULL && lock->owned_by_self()) {
 238         assert(totalSizeInTree(root()) == totalSize(),
 239                "_totalSize inconsistency");
 240       }
 241     )
 242     return totalSize();
 243   }
 244 
 245   size_t     minSize() const {
 246     return MIN_TREE_CHUNK_SIZE;
 247   }
 248 
 249   double     sum_of_squared_block_sizes() const {
 250     return sum_of_squared_block_sizes(root());
 251   }
 252 
 253   FreeChunk* find_chunk_ends_at(HeapWord* target) const;
 254 
 255   // Find the list with size "size" in the binary tree and update
 256   // the statistics in the list according to "split" (chunk was
 257   // split or coalesce) and "birth" (chunk was added or removed).
 258   void       dictCensusUpdate(size_t size, bool split, bool birth);
 259   // Return true if the dictionary is overpopulated (more chunks of
 260   // this size than desired) for size "size".
 261   bool       coalDictOverPopulated(size_t size);
 262   // Methods called at the beginning of a sweep to prepare the
 263   // statistics for the sweep.
 264   void       beginSweepDictCensus(double coalSurplusPercent,
 265                                   float inter_sweep_current,
 266                                   float inter_sweep_estimate,
 267                                   float intra_sweep_estimate);
 268   // Methods called after the end of a sweep to modify the
 269   // statistics for the sweep.
 270   void       endSweepDictCensus(double splitSurplusPercent);
 271   // Return the largest free chunk in the tree.
 272   FreeChunk* findLargestDict() const;
 273   // Accessors for statistics
 274   void       setTreeSurplus(double splitSurplusPercent);
 275   void       setTreeHints(void);
 276   // Reset statistics for all the lists in the tree.
 277   void       clearTreeCensus(void);
 278   // Print the statistcis for all the lists in the tree.  Also may
 279   // print out summaries.
 280   void       printDictCensus(void) const;
 281   void       print_free_lists(outputStream* st) const;
 282 
 283   // For debugging.  Returns the sum of the _returnedBytes for
 284   // all lists in the tree.
 285   size_t     sumDictReturnedBytes()     PRODUCT_RETURN0;
 286   // Sets the _returnedBytes for all the lists in the tree to zero.
 287   void       initializeDictReturnedBytes()      PRODUCT_RETURN;
 288   // For debugging.  Return the total number of chunks in the dictionary.
 289   size_t     totalCount()       PRODUCT_RETURN0;
 290 
 291   void       reportStatistics() const;
 292 
 293   void       verify() const;
 294 };
 295 
 296 #endif // SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_BINARYTREEDICTIONARY_HPP