aoqi@0: /* aoqi@0: * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: * aoqi@0: */ aoqi@0: aoqi@0: #ifndef SHARE_VM_MEMORY_BINARYTREEDICTIONARY_HPP aoqi@0: #define SHARE_VM_MEMORY_BINARYTREEDICTIONARY_HPP aoqi@0: aoqi@0: #include "memory/freeBlockDictionary.hpp" aoqi@0: #include "memory/freeList.hpp" aoqi@0: aoqi@0: /* aoqi@0: * A binary tree based search structure for free blocks. aoqi@0: * This is currently used in the Concurrent Mark&Sweep implementation, but aoqi@0: * will be used for free block management for metadata. aoqi@0: */ aoqi@0: aoqi@0: // A TreeList is a FreeList which can be used to maintain a aoqi@0: // binary tree of free lists. aoqi@0: aoqi@0: template class TreeChunk; aoqi@0: template class BinaryTreeDictionary; aoqi@0: template class AscendTreeCensusClosure; aoqi@0: template class DescendTreeCensusClosure; aoqi@0: template class DescendTreeSearchClosure; aoqi@0: aoqi@0: class FreeChunk; aoqi@0: template class AdaptiveFreeList; aoqi@0: typedef BinaryTreeDictionary > AFLBinaryTreeDictionary; aoqi@0: aoqi@0: template aoqi@0: class TreeList : public FreeList_t { aoqi@0: friend class TreeChunk; aoqi@0: friend class BinaryTreeDictionary; aoqi@0: friend class AscendTreeCensusClosure; aoqi@0: friend class DescendTreeCensusClosure; aoqi@0: friend class DescendTreeSearchClosure; aoqi@0: aoqi@0: TreeList* _parent; aoqi@0: TreeList* _left; aoqi@0: TreeList* _right; aoqi@0: aoqi@0: protected: aoqi@0: aoqi@0: TreeList* parent() const { return _parent; } aoqi@0: TreeList* left() const { return _left; } aoqi@0: TreeList* right() const { return _right; } aoqi@0: aoqi@0: // Wrapper on call to base class, to get the template to compile. aoqi@0: Chunk_t* head() const { return FreeList_t::head(); } aoqi@0: Chunk_t* tail() const { return FreeList_t::tail(); } aoqi@0: void set_head(Chunk_t* head) { FreeList_t::set_head(head); } aoqi@0: void set_tail(Chunk_t* tail) { FreeList_t::set_tail(tail); } aoqi@0: aoqi@0: size_t size() const { return FreeList_t::size(); } aoqi@0: aoqi@0: // Accessors for links in tree. aoqi@0: aoqi@0: void set_left(TreeList* tl) { aoqi@0: _left = tl; aoqi@0: if (tl != NULL) aoqi@0: tl->set_parent(this); aoqi@0: } aoqi@0: void set_right(TreeList* tl) { aoqi@0: _right = tl; aoqi@0: if (tl != NULL) aoqi@0: tl->set_parent(this); aoqi@0: } aoqi@0: void set_parent(TreeList* tl) { _parent = tl; } aoqi@0: aoqi@0: void clear_left() { _left = NULL; } aoqi@0: void clear_right() { _right = NULL; } aoqi@0: void clear_parent() { _parent = NULL; } aoqi@0: void initialize() { clear_left(); clear_right(), clear_parent(); FreeList_t::initialize(); } aoqi@0: aoqi@0: // For constructing a TreeList from a Tree chunk or aoqi@0: // address and size. aoqi@0: TreeList(); aoqi@0: static TreeList* aoqi@0: as_TreeList(TreeChunk* tc); aoqi@0: static TreeList* as_TreeList(HeapWord* addr, size_t size); aoqi@0: aoqi@0: // Returns the head of the free list as a pointer to a TreeChunk. aoqi@0: TreeChunk* head_as_TreeChunk(); aoqi@0: aoqi@0: // Returns the first available chunk in the free list as a pointer aoqi@0: // to a TreeChunk. aoqi@0: TreeChunk* first_available(); aoqi@0: aoqi@0: // Returns the block with the largest heap address amongst aoqi@0: // those in the list for this size; potentially slow and expensive, aoqi@0: // use with caution! aoqi@0: TreeChunk* largest_address(); aoqi@0: aoqi@0: TreeList* get_better_list( aoqi@0: BinaryTreeDictionary* dictionary); aoqi@0: aoqi@0: // remove_chunk_replace_if_needed() removes the given "tc" from the TreeList. aoqi@0: // If "tc" is the first chunk in the list, it is also the aoqi@0: // TreeList that is the node in the tree. remove_chunk_replace_if_needed() aoqi@0: // returns the possibly replaced TreeList* for the node in aoqi@0: // the tree. It also updates the parent of the original aoqi@0: // node to point to the new node. aoqi@0: TreeList* remove_chunk_replace_if_needed(TreeChunk* tc); aoqi@0: // See FreeList. aoqi@0: void return_chunk_at_head(TreeChunk* tc); aoqi@0: void return_chunk_at_tail(TreeChunk* tc); aoqi@0: }; aoqi@0: aoqi@0: // A TreeChunk is a subclass of a Chunk that additionally aoqi@0: // maintains a pointer to the free list on which it is currently aoqi@0: // linked. aoqi@0: // A TreeChunk is also used as a node in the binary tree. This aoqi@0: // allows the binary tree to be maintained without any additional aoqi@0: // storage (the free chunks are used). In a binary tree the first aoqi@0: // chunk in the free list is also the tree node. Note that the aoqi@0: // TreeChunk has an embedded TreeList for this purpose. Because aoqi@0: // the first chunk in the list is distinguished in this fashion aoqi@0: // (also is the node in the tree), it is the last chunk to be found aoqi@0: // on the free list for a node in the tree and is only removed if aoqi@0: // it is the last chunk on the free list. aoqi@0: aoqi@0: template aoqi@0: class TreeChunk : public Chunk_t { aoqi@0: friend class TreeList; aoqi@0: TreeList* _list; aoqi@0: TreeList _embedded_list; // if non-null, this chunk is on _list aoqi@0: aoqi@0: static size_t _min_tree_chunk_size; aoqi@0: aoqi@0: protected: aoqi@0: TreeList* embedded_list() const { return (TreeList*) &_embedded_list; } aoqi@0: void set_embedded_list(TreeList* v) { _embedded_list = *v; } aoqi@0: public: aoqi@0: TreeList* list() { return _list; } aoqi@0: void set_list(TreeList* v) { _list = v; } aoqi@0: static TreeChunk* as_TreeChunk(Chunk_t* fc); aoqi@0: // Initialize fields in a TreeChunk that should be aoqi@0: // initialized when the TreeChunk is being added to aoqi@0: // a free list in the tree. aoqi@0: void initialize() { embedded_list()->initialize(); } aoqi@0: aoqi@0: Chunk_t* next() const { return Chunk_t::next(); } aoqi@0: Chunk_t* prev() const { return Chunk_t::prev(); } aoqi@0: size_t size() const volatile { return Chunk_t::size(); } aoqi@0: aoqi@0: static size_t min_size() { aoqi@0: return _min_tree_chunk_size; aoqi@0: } aoqi@0: aoqi@0: // debugging aoqi@0: void verify_tree_chunk_list() const; aoqi@0: void assert_is_mangled() const; aoqi@0: }; aoqi@0: aoqi@0: aoqi@0: template aoqi@0: class BinaryTreeDictionary: public FreeBlockDictionary { aoqi@0: friend class VMStructs; aoqi@0: size_t _total_size; aoqi@0: size_t _total_free_blocks; aoqi@0: TreeList* _root; aoqi@0: aoqi@0: // private accessors aoqi@0: void set_total_size(size_t v) { _total_size = v; } aoqi@0: virtual void inc_total_size(size_t v); aoqi@0: virtual void dec_total_size(size_t v); aoqi@0: void set_total_free_blocks(size_t v) { _total_free_blocks = v; } aoqi@0: TreeList* root() const { return _root; } aoqi@0: void set_root(TreeList* v) { _root = v; } aoqi@0: aoqi@0: // This field is added and can be set to point to the aoqi@0: // the Mutex used to synchronize access to the aoqi@0: // dictionary so that assertion checking can be done. aoqi@0: // For example it is set to point to _parDictionaryAllocLock. aoqi@0: NOT_PRODUCT(Mutex* _lock;) aoqi@0: aoqi@0: // Remove a chunk of size "size" or larger from the tree and aoqi@0: // return it. If the chunk aoqi@0: // is the last chunk of that size, remove the node for that size aoqi@0: // from the tree. aoqi@0: TreeChunk* get_chunk_from_tree(size_t size, enum FreeBlockDictionary::Dither dither); aoqi@0: // Remove this chunk from the tree. If the removal results aoqi@0: // in an empty list in the tree, remove the empty list. aoqi@0: TreeChunk* remove_chunk_from_tree(TreeChunk* tc); aoqi@0: // Remove the node in the trees starting at tl that has the aoqi@0: // minimum value and return it. Repair the tree as needed. aoqi@0: TreeList* remove_tree_minimum(TreeList* tl); aoqi@0: // Add this free chunk to the tree. aoqi@0: void insert_chunk_in_tree(Chunk_t* freeChunk); aoqi@0: public: aoqi@0: aoqi@0: // Return a list of the specified size or NULL from the tree. aoqi@0: // The list is not removed from the tree. aoqi@0: TreeList* find_list (size_t size) const; aoqi@0: aoqi@0: void verify_tree() const; aoqi@0: // verify that the given chunk is in the tree. aoqi@0: bool verify_chunk_in_free_list(Chunk_t* tc) const; aoqi@0: private: aoqi@0: void verify_tree_helper(TreeList* tl) const; aoqi@0: static size_t verify_prev_free_ptrs(TreeList* tl); aoqi@0: aoqi@0: // Returns the total number of chunks in the list. aoqi@0: size_t total_list_length(TreeList* tl) const; aoqi@0: // Returns the total number of words in the chunks in the tree aoqi@0: // starting at "tl". aoqi@0: size_t total_size_in_tree(TreeList* tl) const; aoqi@0: // Returns the sum of the square of the size of each block aoqi@0: // in the tree starting at "tl". aoqi@0: double sum_of_squared_block_sizes(TreeList* const tl) const; aoqi@0: // Returns the total number of free blocks in the tree starting aoqi@0: // at "tl". aoqi@0: size_t total_free_blocks_in_tree(TreeList* tl) const; aoqi@0: size_t num_free_blocks() const; aoqi@0: size_t tree_height() const; aoqi@0: size_t tree_height_helper(TreeList* tl) const; aoqi@0: size_t total_nodes_in_tree(TreeList* tl) const; aoqi@0: size_t total_nodes_helper(TreeList* tl) const; aoqi@0: aoqi@0: public: aoqi@0: // Constructor aoqi@0: BinaryTreeDictionary() : aoqi@0: _total_size(0), _total_free_blocks(0), _root(0) {} aoqi@0: aoqi@0: BinaryTreeDictionary(MemRegion mr); aoqi@0: aoqi@0: // Public accessors aoqi@0: size_t total_size() const { return _total_size; } aoqi@0: size_t total_free_blocks() const { return _total_free_blocks; } aoqi@0: aoqi@0: // Reset the dictionary to the initial conditions with aoqi@0: // a single free chunk. aoqi@0: void reset(MemRegion mr); aoqi@0: void reset(HeapWord* addr, size_t size); aoqi@0: // Reset the dictionary to be empty. aoqi@0: void reset(); aoqi@0: aoqi@0: // Return a chunk of size "size" or greater from aoqi@0: // the tree. aoqi@0: Chunk_t* get_chunk(size_t size, enum FreeBlockDictionary::Dither dither) { aoqi@0: FreeBlockDictionary::verify_par_locked(); aoqi@0: Chunk_t* res = get_chunk_from_tree(size, dither); aoqi@0: assert(res == NULL || res->is_free(), aoqi@0: "Should be returning a free chunk"); aoqi@0: assert(dither != FreeBlockDictionary::exactly || aoqi@0: res == NULL || res->size() == size, "Not correct size"); aoqi@0: return res; aoqi@0: } aoqi@0: aoqi@0: void return_chunk(Chunk_t* chunk) { aoqi@0: FreeBlockDictionary::verify_par_locked(); aoqi@0: insert_chunk_in_tree(chunk); aoqi@0: } aoqi@0: aoqi@0: void remove_chunk(Chunk_t* chunk) { aoqi@0: FreeBlockDictionary::verify_par_locked(); aoqi@0: remove_chunk_from_tree((TreeChunk*)chunk); aoqi@0: assert(chunk->is_free(), "Should still be a free chunk"); aoqi@0: } aoqi@0: aoqi@0: size_t max_chunk_size() const; aoqi@0: size_t total_chunk_size(debug_only(const Mutex* lock)) const { aoqi@0: debug_only( aoqi@0: if (lock != NULL && lock->owned_by_self()) { aoqi@0: assert(total_size_in_tree(root()) == total_size(), aoqi@0: "_total_size inconsistency"); aoqi@0: } aoqi@0: ) aoqi@0: return total_size(); aoqi@0: } aoqi@0: aoqi@0: size_t min_size() const { aoqi@0: return TreeChunk::min_size(); aoqi@0: } aoqi@0: aoqi@0: double sum_of_squared_block_sizes() const { aoqi@0: return sum_of_squared_block_sizes(root()); aoqi@0: } aoqi@0: aoqi@0: Chunk_t* find_chunk_ends_at(HeapWord* target) const; aoqi@0: aoqi@0: // Find the list with size "size" in the binary tree and update aoqi@0: // the statistics in the list according to "split" (chunk was aoqi@0: // split or coalesce) and "birth" (chunk was added or removed). aoqi@0: void dict_census_update(size_t size, bool split, bool birth); aoqi@0: // Return true if the dictionary is overpopulated (more chunks of aoqi@0: // this size than desired) for size "size". aoqi@0: bool coal_dict_over_populated(size_t size); aoqi@0: // Methods called at the beginning of a sweep to prepare the aoqi@0: // statistics for the sweep. aoqi@0: void begin_sweep_dict_census(double coalSurplusPercent, aoqi@0: float inter_sweep_current, aoqi@0: float inter_sweep_estimate, aoqi@0: float intra_sweep_estimate); aoqi@0: // Methods called after the end of a sweep to modify the aoqi@0: // statistics for the sweep. aoqi@0: void end_sweep_dict_census(double splitSurplusPercent); aoqi@0: // Return the largest free chunk in the tree. aoqi@0: Chunk_t* find_largest_dict() const; aoqi@0: // Accessors for statistics aoqi@0: void set_tree_surplus(double splitSurplusPercent); aoqi@0: void set_tree_hints(void); aoqi@0: // Reset statistics for all the lists in the tree. aoqi@0: void clear_tree_census(void); aoqi@0: // Print the statistcis for all the lists in the tree. Also may aoqi@0: // print out summaries. aoqi@0: void print_dict_census(void) const; aoqi@0: void print_free_lists(outputStream* st) const; aoqi@0: aoqi@0: // For debugging. Returns the sum of the _returned_bytes for aoqi@0: // all lists in the tree. aoqi@0: size_t sum_dict_returned_bytes() PRODUCT_RETURN0; aoqi@0: // Sets the _returned_bytes for all the lists in the tree to zero. aoqi@0: void initialize_dict_returned_bytes() PRODUCT_RETURN; aoqi@0: // For debugging. Return the total number of chunks in the dictionary. aoqi@0: size_t total_count() PRODUCT_RETURN0; aoqi@0: aoqi@0: void report_statistics() const; aoqi@0: aoqi@0: void verify() const; aoqi@0: }; aoqi@0: aoqi@0: #endif // SHARE_VM_MEMORY_BINARYTREEDICTIONARY_HPP