mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-19 01:47:52 +00:00
8200735: Move CMS specific code from binaryTreeDictionary and freeList to CMS files
Reviewed-by: shade, adinn
This commit is contained in:
parent
82847e4ec0
commit
f05f8de48f
@ -26,6 +26,7 @@
|
||||
#include "gc/cms/adaptiveFreeList.hpp"
|
||||
#include "gc/cms/freeChunk.hpp"
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "memory/freeList.inline.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "runtime/mutex.hpp"
|
||||
#include "runtime/orderAccess.inline.hpp"
|
||||
|
||||
@ -35,6 +35,7 @@
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/binaryTreeDictionary.inline.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
#include "oops/access.inline.hpp"
|
||||
@ -49,6 +50,244 @@
|
||||
#include "utilities/align.hpp"
|
||||
#include "utilities/copy.hpp"
|
||||
|
||||
// Specialize for AdaptiveFreeList which tries to avoid
|
||||
// splitting a chunk of a size that is under populated in favor of
|
||||
// an over populated size. The general get_better_list() just returns
|
||||
// the current list.
|
||||
template <>
|
||||
TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >*
|
||||
TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >::get_better_list(
|
||||
BinaryTreeDictionary<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* dictionary) {
|
||||
// A candidate chunk has been found. If it is already under
|
||||
// populated, get a chunk associated with the hint for this
|
||||
// chunk.
|
||||
|
||||
TreeList<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* curTL = this;
|
||||
if (curTL->surplus() <= 0) {
|
||||
/* Use the hint to find a size with a surplus, and reset the hint. */
|
||||
TreeList<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* hintTL = this;
|
||||
while (hintTL->hint() != 0) {
|
||||
assert(hintTL->hint() > hintTL->size(),
|
||||
"hint points in the wrong direction");
|
||||
hintTL = dictionary->find_list(hintTL->hint());
|
||||
assert(curTL != hintTL, "Infinite loop");
|
||||
if (hintTL == NULL ||
|
||||
hintTL == curTL /* Should not happen but protect against it */ ) {
|
||||
// No useful hint. Set the hint to NULL and go on.
|
||||
curTL->set_hint(0);
|
||||
break;
|
||||
}
|
||||
assert(hintTL->size() > curTL->size(), "hint is inconsistent");
|
||||
if (hintTL->surplus() > 0) {
|
||||
// The hint led to a list that has a surplus. Use it.
|
||||
// Set the hint for the candidate to an overpopulated
|
||||
// size.
|
||||
curTL->set_hint(hintTL->size());
|
||||
// Change the candidate.
|
||||
curTL = hintTL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return curTL;
|
||||
}
|
||||
|
||||
void AFLBinaryTreeDictionary::dict_census_update(size_t size, bool split, bool birth) {
|
||||
TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >* nd = find_list(size);
|
||||
if (nd) {
|
||||
if (split) {
|
||||
if (birth) {
|
||||
nd->increment_split_births();
|
||||
nd->increment_surplus();
|
||||
} else {
|
||||
nd->increment_split_deaths();
|
||||
nd->decrement_surplus();
|
||||
}
|
||||
} else {
|
||||
if (birth) {
|
||||
nd->increment_coal_births();
|
||||
nd->increment_surplus();
|
||||
} else {
|
||||
nd->increment_coal_deaths();
|
||||
nd->decrement_surplus();
|
||||
}
|
||||
}
|
||||
}
|
||||
// A list for this size may not be found (nd == 0) if
|
||||
// This is a death where the appropriate list is now
|
||||
// empty and has been removed from the list.
|
||||
// This is a birth associated with a LinAB. The chunk
|
||||
// for the LinAB is not in the dictionary.
|
||||
}
|
||||
|
||||
bool AFLBinaryTreeDictionary::coal_dict_over_populated(size_t size) {
|
||||
if (FLSAlwaysCoalesceLarge) return true;
|
||||
|
||||
TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >* list_of_size = find_list(size);
|
||||
// None of requested size implies overpopulated.
|
||||
return list_of_size == NULL || list_of_size->coal_desired() <= 0 ||
|
||||
list_of_size->count() > list_of_size->coal_desired();
|
||||
}
|
||||
|
||||
// For each list in the tree, calculate the desired, desired
|
||||
// coalesce, count before sweep, and surplus before sweep.
|
||||
class BeginSweepClosure : public AscendTreeCensusClosure<FreeChunk, AdaptiveFreeList<FreeChunk> > {
|
||||
double _percentage;
|
||||
float _inter_sweep_current;
|
||||
float _inter_sweep_estimate;
|
||||
float _intra_sweep_estimate;
|
||||
|
||||
public:
|
||||
BeginSweepClosure(double p, float inter_sweep_current,
|
||||
float inter_sweep_estimate,
|
||||
float intra_sweep_estimate) :
|
||||
_percentage(p),
|
||||
_inter_sweep_current(inter_sweep_current),
|
||||
_inter_sweep_estimate(inter_sweep_estimate),
|
||||
_intra_sweep_estimate(intra_sweep_estimate) { }
|
||||
|
||||
void do_list(AdaptiveFreeList<FreeChunk>* fl) {
|
||||
double coalSurplusPercent = _percentage;
|
||||
fl->compute_desired(_inter_sweep_current, _inter_sweep_estimate, _intra_sweep_estimate);
|
||||
fl->set_coal_desired((ssize_t)((double)fl->desired() * coalSurplusPercent));
|
||||
fl->set_before_sweep(fl->count());
|
||||
fl->set_bfr_surp(fl->surplus());
|
||||
}
|
||||
};
|
||||
|
||||
void AFLBinaryTreeDictionary::begin_sweep_dict_census(double coalSurplusPercent,
|
||||
float inter_sweep_current, float inter_sweep_estimate, float intra_sweep_estimate) {
|
||||
BeginSweepClosure bsc(coalSurplusPercent, inter_sweep_current,
|
||||
inter_sweep_estimate,
|
||||
intra_sweep_estimate);
|
||||
bsc.do_tree(root());
|
||||
}
|
||||
|
||||
// Calculate surpluses for the lists in the tree.
|
||||
class setTreeSurplusClosure : public AscendTreeCensusClosure<FreeChunk, AdaptiveFreeList<FreeChunk> > {
|
||||
double percentage;
|
||||
public:
|
||||
setTreeSurplusClosure(double v) { percentage = v; }
|
||||
|
||||
void do_list(AdaptiveFreeList<FreeChunk>* fl) {
|
||||
double splitSurplusPercent = percentage;
|
||||
fl->set_surplus(fl->count() -
|
||||
(ssize_t)((double)fl->desired() * splitSurplusPercent));
|
||||
}
|
||||
};
|
||||
|
||||
void AFLBinaryTreeDictionary::set_tree_surplus(double splitSurplusPercent) {
|
||||
setTreeSurplusClosure sts(splitSurplusPercent);
|
||||
sts.do_tree(root());
|
||||
}
|
||||
|
||||
// Set hints for the lists in the tree.
|
||||
class setTreeHintsClosure : public DescendTreeCensusClosure<FreeChunk, AdaptiveFreeList<FreeChunk> > {
|
||||
size_t hint;
|
||||
public:
|
||||
setTreeHintsClosure(size_t v) { hint = v; }
|
||||
|
||||
void do_list(AdaptiveFreeList<FreeChunk>* fl) {
|
||||
fl->set_hint(hint);
|
||||
assert(fl->hint() == 0 || fl->hint() > fl->size(),
|
||||
"Current hint is inconsistent");
|
||||
if (fl->surplus() > 0) {
|
||||
hint = fl->size();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void AFLBinaryTreeDictionary::set_tree_hints(void) {
|
||||
setTreeHintsClosure sth(0);
|
||||
sth.do_tree(root());
|
||||
}
|
||||
|
||||
// Save count before previous sweep and splits and coalesces.
|
||||
class clearTreeCensusClosure : public AscendTreeCensusClosure<FreeChunk, AdaptiveFreeList<FreeChunk> > {
|
||||
void do_list(AdaptiveFreeList<FreeChunk>* fl) {
|
||||
fl->set_prev_sweep(fl->count());
|
||||
fl->set_coal_births(0);
|
||||
fl->set_coal_deaths(0);
|
||||
fl->set_split_births(0);
|
||||
fl->set_split_deaths(0);
|
||||
}
|
||||
};
|
||||
|
||||
void AFLBinaryTreeDictionary::clear_tree_census(void) {
|
||||
clearTreeCensusClosure ctc;
|
||||
ctc.do_tree(root());
|
||||
}
|
||||
|
||||
// Do reporting and post sweep clean up.
|
||||
void AFLBinaryTreeDictionary::end_sweep_dict_census(double splitSurplusPercent) {
|
||||
// Does walking the tree 3 times hurt?
|
||||
set_tree_surplus(splitSurplusPercent);
|
||||
set_tree_hints();
|
||||
LogTarget(Trace, gc, freelist, stats) log;
|
||||
if (log.is_enabled()) {
|
||||
LogStream out(log);
|
||||
report_statistics(&out);
|
||||
}
|
||||
clear_tree_census();
|
||||
}
|
||||
|
||||
// Print census information - counts, births, deaths, etc.
|
||||
// for each list in the tree. Also print some summary
|
||||
// information.
|
||||
class PrintTreeCensusClosure : public AscendTreeCensusClosure<FreeChunk, AdaptiveFreeList<FreeChunk> > {
|
||||
int _print_line;
|
||||
size_t _total_free;
|
||||
AdaptiveFreeList<FreeChunk> _total;
|
||||
|
||||
public:
|
||||
PrintTreeCensusClosure() {
|
||||
_print_line = 0;
|
||||
_total_free = 0;
|
||||
}
|
||||
AdaptiveFreeList<FreeChunk>* total() { return &_total; }
|
||||
size_t total_free() { return _total_free; }
|
||||
|
||||
void do_list(AdaptiveFreeList<FreeChunk>* fl) {
|
||||
LogStreamHandle(Debug, gc, freelist, census) out;
|
||||
|
||||
if (++_print_line >= 40) {
|
||||
AdaptiveFreeList<FreeChunk>::print_labels_on(&out, "size");
|
||||
_print_line = 0;
|
||||
}
|
||||
fl->print_on(&out);
|
||||
_total_free += fl->count() * fl->size() ;
|
||||
total()->set_count( total()->count() + fl->count() );
|
||||
total()->set_bfr_surp( total()->bfr_surp() + fl->bfr_surp() );
|
||||
total()->set_surplus( total()->split_deaths() + fl->surplus() );
|
||||
total()->set_desired( total()->desired() + fl->desired() );
|
||||
total()->set_prev_sweep( total()->prev_sweep() + fl->prev_sweep() );
|
||||
total()->set_before_sweep(total()->before_sweep() + fl->before_sweep());
|
||||
total()->set_coal_births( total()->coal_births() + fl->coal_births() );
|
||||
total()->set_coal_deaths( total()->coal_deaths() + fl->coal_deaths() );
|
||||
total()->set_split_births(total()->split_births() + fl->split_births());
|
||||
total()->set_split_deaths(total()->split_deaths() + fl->split_deaths());
|
||||
}
|
||||
};
|
||||
|
||||
void AFLBinaryTreeDictionary::print_dict_census(outputStream* st) const {
|
||||
|
||||
st->print_cr("BinaryTree");
|
||||
AdaptiveFreeList<FreeChunk>::print_labels_on(st, "size");
|
||||
PrintTreeCensusClosure ptc;
|
||||
ptc.do_tree(root());
|
||||
|
||||
AdaptiveFreeList<FreeChunk>* total = ptc.total();
|
||||
AdaptiveFreeList<FreeChunk>::print_labels_on(st, " ");
|
||||
total->print_on(st, "TOTAL\t");
|
||||
st->print_cr("total_free(words): " SIZE_FORMAT_W(16) " growth: %8.5f deficit: %8.5f",
|
||||
ptc.total_free(),
|
||||
(double)(total->split_births() + total->coal_births()
|
||||
- total->split_deaths() - total->coal_deaths())
|
||||
/(total->prev_sweep() != 0 ? (double)total->prev_sweep() : 1.0),
|
||||
(double)(total->desired() - total->count())
|
||||
/(total->desired() != 0 ? (double)total->desired() : 1.0));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//// CompactibleFreeListSpace
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -48,6 +48,37 @@ class UpwardsObjectClosure;
|
||||
class ObjectClosureCareful;
|
||||
class Klass;
|
||||
|
||||
class AFLBinaryTreeDictionary : public BinaryTreeDictionary<FreeChunk, AdaptiveFreeList<FreeChunk> > {
|
||||
public:
|
||||
AFLBinaryTreeDictionary(MemRegion mr)
|
||||
: BinaryTreeDictionary<FreeChunk, AdaptiveFreeList<FreeChunk> >(mr) {}
|
||||
|
||||
// Find the list with size "size" in the binary tree and update
|
||||
// the statistics in the list according to "split" (chunk was
|
||||
// split or coalesce) and "birth" (chunk was added or removed).
|
||||
void dict_census_update(size_t size, bool split, bool birth);
|
||||
// Return true if the dictionary is overpopulated (more chunks of
|
||||
// this size than desired) for size "size".
|
||||
bool coal_dict_over_populated(size_t size);
|
||||
// Methods called at the beginning of a sweep to prepare the
|
||||
// statistics for the sweep.
|
||||
void begin_sweep_dict_census(double coalSurplusPercent,
|
||||
float inter_sweep_current,
|
||||
float inter_sweep_estimate,
|
||||
float intra_sweep_estimate);
|
||||
// Methods called after the end of a sweep to modify the
|
||||
// statistics for the sweep.
|
||||
void end_sweep_dict_census(double splitSurplusPercent);
|
||||
// Accessors for statistics
|
||||
void set_tree_surplus(double splitSurplusPercent);
|
||||
void set_tree_hints(void);
|
||||
// Reset statistics for all the lists in the tree.
|
||||
void clear_tree_census(void);
|
||||
// Print the statistics for all the lists in the tree. Also may
|
||||
// print out summaries.
|
||||
void print_dict_census(outputStream* st) const;
|
||||
};
|
||||
|
||||
class LinearAllocBlock {
|
||||
public:
|
||||
LinearAllocBlock() : _ptr(0), _word_size(0), _refillSize(0),
|
||||
|
||||
@ -59,6 +59,7 @@
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/binaryTreeDictionary.inline.hpp"
|
||||
#include "memory/iterator.inline.hpp"
|
||||
#include "memory/padded.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
|
||||
@ -42,10 +42,6 @@ template <class Chunk_t, class FreeList_t> class AscendTreeCensusClosure;
|
||||
template <class Chunk_t, class FreeList_t> class DescendTreeCensusClosure;
|
||||
template <class Chunk_t, class FreeList_t> class DescendTreeSearchClosure;
|
||||
|
||||
class FreeChunk;
|
||||
template <class> class AdaptiveFreeList;
|
||||
typedef BinaryTreeDictionary<FreeChunk, AdaptiveFreeList<FreeChunk> > AFLBinaryTreeDictionary;
|
||||
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
class TreeList : public FreeList_t {
|
||||
friend class TreeChunk<Chunk_t, FreeList_t>;
|
||||
@ -177,6 +173,8 @@ size_t TreeChunk<Chunk_t, FreeList_t>::min_size() { return _min_tree_chunk_size;
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
class BinaryTreeDictionary: public CHeapObj<mtGC> {
|
||||
friend class VMStructs;
|
||||
|
||||
protected:
|
||||
size_t _total_size;
|
||||
size_t _total_free_blocks;
|
||||
TreeList<Chunk_t, FreeList_t>* _root;
|
||||
@ -298,32 +296,9 @@ class BinaryTreeDictionary: public CHeapObj<mtGC> {
|
||||
|
||||
Chunk_t* find_chunk_ends_at(HeapWord* target) const;
|
||||
|
||||
// Find the list with size "size" in the binary tree and update
|
||||
// the statistics in the list according to "split" (chunk was
|
||||
// split or coalesce) and "birth" (chunk was added or removed).
|
||||
void dict_census_update(size_t size, bool split, bool birth);
|
||||
// Return true if the dictionary is overpopulated (more chunks of
|
||||
// this size than desired) for size "size".
|
||||
bool coal_dict_over_populated(size_t size);
|
||||
// Methods called at the beginning of a sweep to prepare the
|
||||
// statistics for the sweep.
|
||||
void begin_sweep_dict_census(double coalSurplusPercent,
|
||||
float inter_sweep_current,
|
||||
float inter_sweep_estimate,
|
||||
float intra_sweep_estimate);
|
||||
// Methods called after the end of a sweep to modify the
|
||||
// statistics for the sweep.
|
||||
void end_sweep_dict_census(double splitSurplusPercent);
|
||||
// Return the largest free chunk in the tree.
|
||||
Chunk_t* find_largest_dict() const;
|
||||
// Accessors for statistics
|
||||
void set_tree_surplus(double splitSurplusPercent);
|
||||
void set_tree_hints(void);
|
||||
// Reset statistics for all the lists in the tree.
|
||||
void clear_tree_census(void);
|
||||
// Print the statistics for all the lists in the tree. Also may
|
||||
// print out summaries.
|
||||
void print_dict_census(outputStream* st) const;
|
||||
|
||||
void print_free_lists(outputStream* st) const;
|
||||
|
||||
// For debugging. Returns the sum of the _returned_bytes for
|
||||
@ -343,4 +318,83 @@ class BinaryTreeDictionary: public CHeapObj<mtGC> {
|
||||
void verify_par_locked() const PRODUCT_RETURN;
|
||||
};
|
||||
|
||||
|
||||
// Closures for walking the binary tree.
|
||||
// do_list() walks the free list in a node applying the closure
|
||||
// to each free chunk in the list
|
||||
// do_tree() walks the nodes in the binary tree applying do_list()
|
||||
// to each list at each node.
|
||||
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
class TreeCensusClosure : public StackObj {
|
||||
protected:
|
||||
virtual void do_list(FreeList_t* fl) = 0;
|
||||
public:
|
||||
virtual void do_tree(TreeList<Chunk_t, FreeList_t>* tl) = 0;
|
||||
};
|
||||
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
class AscendTreeCensusClosure : public TreeCensusClosure<Chunk_t, FreeList_t> {
|
||||
public:
|
||||
void do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
|
||||
if (tl != NULL) {
|
||||
do_tree(tl->left());
|
||||
this->do_list(tl);
|
||||
do_tree(tl->right());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
class DescendTreeCensusClosure : public TreeCensusClosure<Chunk_t, FreeList_t> {
|
||||
public:
|
||||
void do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
|
||||
if (tl != NULL) {
|
||||
do_tree(tl->right());
|
||||
this->do_list(tl);
|
||||
do_tree(tl->left());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Used to search the tree until a condition is met.
|
||||
// Similar to TreeCensusClosure but searches the
|
||||
// tree and returns promptly when found.
|
||||
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
class TreeSearchClosure : public StackObj {
|
||||
protected:
|
||||
virtual bool do_list(FreeList_t* fl) = 0;
|
||||
public:
|
||||
virtual bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) = 0;
|
||||
};
|
||||
|
||||
#if 0 // Don't need this yet but here for symmetry.
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
class AscendTreeSearchClosure : public TreeSearchClosure<Chunk_t> {
|
||||
public:
|
||||
bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
|
||||
if (tl != NULL) {
|
||||
if (do_tree(tl->left())) return true;
|
||||
if (do_list(tl)) return true;
|
||||
if (do_tree(tl->right())) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
class DescendTreeSearchClosure : public TreeSearchClosure<Chunk_t, FreeList_t> {
|
||||
public:
|
||||
bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
|
||||
if (tl != NULL) {
|
||||
if (do_tree(tl->right())) return true;
|
||||
if (this->do_list(tl)) return true;
|
||||
if (do_tree(tl->left())) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_MEMORY_BINARYTREEDICTIONARY_HPP
|
||||
|
||||
@ -22,22 +22,19 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/cms/allocationStats.hpp"
|
||||
#ifndef SHARE_VM_MEMORY_BINARYTREEDICTIONARY_INLINE_HPP
|
||||
#define SHARE_VM_MEMORY_BINARYTREEDICTIONARY_INLINE_HPP
|
||||
|
||||
#include "gc/shared/spaceDecorator.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
#include "memory/binaryTreeDictionary.hpp"
|
||||
#include "memory/freeList.hpp"
|
||||
#include "memory/freeList.inline.hpp"
|
||||
#include "memory/metachunk.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
#if INCLUDE_ALL_GCS
|
||||
#include "gc/cms/adaptiveFreeList.hpp"
|
||||
#include "gc/cms/freeChunk.hpp"
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// A binary tree based search structure for free blocks.
|
||||
@ -103,50 +100,6 @@ TreeList<Chunk_t, FreeList_t>::as_TreeList(HeapWord* addr, size_t size) {
|
||||
}
|
||||
|
||||
|
||||
#if INCLUDE_ALL_GCS
|
||||
// Specialize for AdaptiveFreeList which tries to avoid
|
||||
// splitting a chunk of a size that is under populated in favor of
|
||||
// an over populated size. The general get_better_list() just returns
|
||||
// the current list.
|
||||
template <>
|
||||
TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >*
|
||||
TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >::get_better_list(
|
||||
BinaryTreeDictionary<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* dictionary) {
|
||||
// A candidate chunk has been found. If it is already under
|
||||
// populated, get a chunk associated with the hint for this
|
||||
// chunk.
|
||||
|
||||
TreeList<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* curTL = this;
|
||||
if (curTL->surplus() <= 0) {
|
||||
/* Use the hint to find a size with a surplus, and reset the hint. */
|
||||
TreeList<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* hintTL = this;
|
||||
while (hintTL->hint() != 0) {
|
||||
assert(hintTL->hint() > hintTL->size(),
|
||||
"hint points in the wrong direction");
|
||||
hintTL = dictionary->find_list(hintTL->hint());
|
||||
assert(curTL != hintTL, "Infinite loop");
|
||||
if (hintTL == NULL ||
|
||||
hintTL == curTL /* Should not happen but protect against it */ ) {
|
||||
// No useful hint. Set the hint to NULL and go on.
|
||||
curTL->set_hint(0);
|
||||
break;
|
||||
}
|
||||
assert(hintTL->size() > curTL->size(), "hint is inconsistent");
|
||||
if (hintTL->surplus() > 0) {
|
||||
// The hint led to a list that has a surplus. Use it.
|
||||
// Set the hint for the candidate to an overpopulated
|
||||
// size.
|
||||
curTL->set_hint(hintTL->size());
|
||||
// Change the candidate.
|
||||
curTL = hintTL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return curTL;
|
||||
}
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
TreeList<Chunk_t, FreeList_t>*
|
||||
TreeList<Chunk_t, FreeList_t>::get_better_list(
|
||||
@ -849,168 +802,6 @@ size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_nodes_in_tree(TreeList<C
|
||||
return total_nodes_helper(root());
|
||||
}
|
||||
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
void BinaryTreeDictionary<Chunk_t, FreeList_t>::dict_census_update(size_t size, bool split, bool birth){}
|
||||
|
||||
#if INCLUDE_ALL_GCS
|
||||
template <>
|
||||
void AFLBinaryTreeDictionary::dict_census_update(size_t size, bool split, bool birth) {
|
||||
TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >* nd = find_list(size);
|
||||
if (nd) {
|
||||
if (split) {
|
||||
if (birth) {
|
||||
nd->increment_split_births();
|
||||
nd->increment_surplus();
|
||||
} else {
|
||||
nd->increment_split_deaths();
|
||||
nd->decrement_surplus();
|
||||
}
|
||||
} else {
|
||||
if (birth) {
|
||||
nd->increment_coal_births();
|
||||
nd->increment_surplus();
|
||||
} else {
|
||||
nd->increment_coal_deaths();
|
||||
nd->decrement_surplus();
|
||||
}
|
||||
}
|
||||
}
|
||||
// A list for this size may not be found (nd == 0) if
|
||||
// This is a death where the appropriate list is now
|
||||
// empty and has been removed from the list.
|
||||
// This is a birth associated with a LinAB. The chunk
|
||||
// for the LinAB is not in the dictionary.
|
||||
}
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
bool BinaryTreeDictionary<Chunk_t, FreeList_t>::coal_dict_over_populated(size_t size) {
|
||||
// For the general type of freelists, encourage coalescing by
|
||||
// returning true.
|
||||
return true;
|
||||
}
|
||||
|
||||
#if INCLUDE_ALL_GCS
|
||||
template <>
|
||||
bool AFLBinaryTreeDictionary::coal_dict_over_populated(size_t size) {
|
||||
if (FLSAlwaysCoalesceLarge) return true;
|
||||
|
||||
TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >* list_of_size = find_list(size);
|
||||
// None of requested size implies overpopulated.
|
||||
return list_of_size == NULL || list_of_size->coal_desired() <= 0 ||
|
||||
list_of_size->count() > list_of_size->coal_desired();
|
||||
}
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
|
||||
// Closures for walking the binary tree.
|
||||
// do_list() walks the free list in a node applying the closure
|
||||
// to each free chunk in the list
|
||||
// do_tree() walks the nodes in the binary tree applying do_list()
|
||||
// to each list at each node.
|
||||
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
class TreeCensusClosure : public StackObj {
|
||||
protected:
|
||||
virtual void do_list(FreeList_t* fl) = 0;
|
||||
public:
|
||||
virtual void do_tree(TreeList<Chunk_t, FreeList_t>* tl) = 0;
|
||||
};
|
||||
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
class AscendTreeCensusClosure : public TreeCensusClosure<Chunk_t, FreeList_t> {
|
||||
public:
|
||||
void do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
|
||||
if (tl != NULL) {
|
||||
do_tree(tl->left());
|
||||
this->do_list(tl);
|
||||
do_tree(tl->right());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
class DescendTreeCensusClosure : public TreeCensusClosure<Chunk_t, FreeList_t> {
|
||||
public:
|
||||
void do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
|
||||
if (tl != NULL) {
|
||||
do_tree(tl->right());
|
||||
this->do_list(tl);
|
||||
do_tree(tl->left());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// For each list in the tree, calculate the desired, desired
|
||||
// coalesce, count before sweep, and surplus before sweep.
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
class BeginSweepClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
|
||||
double _percentage;
|
||||
float _inter_sweep_current;
|
||||
float _inter_sweep_estimate;
|
||||
float _intra_sweep_estimate;
|
||||
|
||||
public:
|
||||
BeginSweepClosure(double p, float inter_sweep_current,
|
||||
float inter_sweep_estimate,
|
||||
float intra_sweep_estimate) :
|
||||
_percentage(p),
|
||||
_inter_sweep_current(inter_sweep_current),
|
||||
_inter_sweep_estimate(inter_sweep_estimate),
|
||||
_intra_sweep_estimate(intra_sweep_estimate) { }
|
||||
|
||||
void do_list(FreeList<Chunk_t>* fl) {}
|
||||
|
||||
#if INCLUDE_ALL_GCS
|
||||
void do_list(AdaptiveFreeList<Chunk_t>* fl) {
|
||||
double coalSurplusPercent = _percentage;
|
||||
fl->compute_desired(_inter_sweep_current, _inter_sweep_estimate, _intra_sweep_estimate);
|
||||
fl->set_coal_desired((ssize_t)((double)fl->desired() * coalSurplusPercent));
|
||||
fl->set_before_sweep(fl->count());
|
||||
fl->set_bfr_surp(fl->surplus());
|
||||
}
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
};
|
||||
|
||||
// Used to search the tree until a condition is met.
|
||||
// Similar to TreeCensusClosure but searches the
|
||||
// tree and returns promptly when found.
|
||||
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
class TreeSearchClosure : public StackObj {
|
||||
protected:
|
||||
virtual bool do_list(FreeList_t* fl) = 0;
|
||||
public:
|
||||
virtual bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) = 0;
|
||||
};
|
||||
|
||||
#if 0 // Don't need this yet but here for symmetry.
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
class AscendTreeSearchClosure : public TreeSearchClosure<Chunk_t> {
|
||||
public:
|
||||
bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
|
||||
if (tl != NULL) {
|
||||
if (do_tree(tl->left())) return true;
|
||||
if (do_list(tl)) return true;
|
||||
if (do_tree(tl->right())) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
class DescendTreeSearchClosure : public TreeSearchClosure<Chunk_t, FreeList_t> {
|
||||
public:
|
||||
bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
|
||||
if (tl != NULL) {
|
||||
if (do_tree(tl->right())) return true;
|
||||
if (this->do_list(tl)) return true;
|
||||
if (do_tree(tl->left())) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Searches the tree for a chunk that ends at the
|
||||
// specified address.
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
@ -1043,15 +834,6 @@ Chunk_t* BinaryTreeDictionary<Chunk_t, FreeList_t>::find_chunk_ends_at(HeapWord*
|
||||
return etsc.found();
|
||||
}
|
||||
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
void BinaryTreeDictionary<Chunk_t, FreeList_t>::begin_sweep_dict_census(double coalSurplusPercent,
|
||||
float inter_sweep_current, float inter_sweep_estimate, float intra_sweep_estimate) {
|
||||
BeginSweepClosure<Chunk_t, FreeList_t> bsc(coalSurplusPercent, inter_sweep_current,
|
||||
inter_sweep_estimate,
|
||||
intra_sweep_estimate);
|
||||
bsc.do_tree(root());
|
||||
}
|
||||
|
||||
// Closures and methods for calculating total bytes returned to the
|
||||
// free lists in the tree.
|
||||
#ifndef PRODUCT
|
||||
@ -1128,91 +910,6 @@ void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_par_locked() const {
|
||||
}
|
||||
#endif // PRODUCT
|
||||
|
||||
// Calculate surpluses for the lists in the tree.
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
class setTreeSurplusClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
|
||||
double percentage;
|
||||
public:
|
||||
setTreeSurplusClosure(double v) { percentage = v; }
|
||||
void do_list(FreeList<Chunk_t>* fl) {}
|
||||
|
||||
#if INCLUDE_ALL_GCS
|
||||
void do_list(AdaptiveFreeList<Chunk_t>* fl) {
|
||||
double splitSurplusPercent = percentage;
|
||||
fl->set_surplus(fl->count() -
|
||||
(ssize_t)((double)fl->desired() * splitSurplusPercent));
|
||||
}
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
};
|
||||
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
void BinaryTreeDictionary<Chunk_t, FreeList_t>::set_tree_surplus(double splitSurplusPercent) {
|
||||
setTreeSurplusClosure<Chunk_t, FreeList_t> sts(splitSurplusPercent);
|
||||
sts.do_tree(root());
|
||||
}
|
||||
|
||||
// Set hints for the lists in the tree.
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
class setTreeHintsClosure : public DescendTreeCensusClosure<Chunk_t, FreeList_t> {
|
||||
size_t hint;
|
||||
public:
|
||||
setTreeHintsClosure(size_t v) { hint = v; }
|
||||
void do_list(FreeList<Chunk_t>* fl) {}
|
||||
|
||||
#if INCLUDE_ALL_GCS
|
||||
void do_list(AdaptiveFreeList<Chunk_t>* fl) {
|
||||
fl->set_hint(hint);
|
||||
assert(fl->hint() == 0 || fl->hint() > fl->size(),
|
||||
"Current hint is inconsistent");
|
||||
if (fl->surplus() > 0) {
|
||||
hint = fl->size();
|
||||
}
|
||||
}
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
};
|
||||
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
void BinaryTreeDictionary<Chunk_t, FreeList_t>::set_tree_hints(void) {
|
||||
setTreeHintsClosure<Chunk_t, FreeList_t> sth(0);
|
||||
sth.do_tree(root());
|
||||
}
|
||||
|
||||
// Save count before previous sweep and splits and coalesces.
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
class clearTreeCensusClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
|
||||
void do_list(FreeList<Chunk_t>* fl) {}
|
||||
|
||||
#if INCLUDE_ALL_GCS
|
||||
void do_list(AdaptiveFreeList<Chunk_t>* fl) {
|
||||
fl->set_prev_sweep(fl->count());
|
||||
fl->set_coal_births(0);
|
||||
fl->set_coal_deaths(0);
|
||||
fl->set_split_births(0);
|
||||
fl->set_split_deaths(0);
|
||||
}
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
};
|
||||
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
void BinaryTreeDictionary<Chunk_t, FreeList_t>::clear_tree_census(void) {
|
||||
clearTreeCensusClosure<Chunk_t, FreeList_t> ctc;
|
||||
ctc.do_tree(root());
|
||||
}
|
||||
|
||||
// Do reporting and post sweep clean up.
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
void BinaryTreeDictionary<Chunk_t, FreeList_t>::end_sweep_dict_census(double splitSurplusPercent) {
|
||||
// Does walking the tree 3 times hurt?
|
||||
set_tree_surplus(splitSurplusPercent);
|
||||
set_tree_hints();
|
||||
LogTarget(Trace, gc, freelist, stats) log;
|
||||
if (log.is_enabled()) {
|
||||
LogStream out(log);
|
||||
report_statistics(&out);
|
||||
}
|
||||
clear_tree_census();
|
||||
}
|
||||
|
||||
// Print summary statistics
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
void BinaryTreeDictionary<Chunk_t, FreeList_t>::report_statistics(outputStream* st) const {
|
||||
@ -1230,92 +927,6 @@ void BinaryTreeDictionary<Chunk_t, FreeList_t>::report_statistics(outputStream*
|
||||
st->print_cr("Tree Height: " SIZE_FORMAT, tree_height());
|
||||
}
|
||||
|
||||
// Print census information - counts, births, deaths, etc.
|
||||
// for each list in the tree. Also print some summary
|
||||
// information.
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
class PrintTreeCensusClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
|
||||
int _print_line;
|
||||
size_t _total_free;
|
||||
FreeList_t _total;
|
||||
|
||||
public:
|
||||
PrintTreeCensusClosure() {
|
||||
_print_line = 0;
|
||||
_total_free = 0;
|
||||
}
|
||||
FreeList_t* total() { return &_total; }
|
||||
size_t total_free() { return _total_free; }
|
||||
void do_list(FreeList<Chunk_t>* fl) {
|
||||
LogStreamHandle(Debug, gc, freelist, census) out;
|
||||
|
||||
if (++_print_line >= 40) {
|
||||
FreeList_t::print_labels_on(&out, "size");
|
||||
_print_line = 0;
|
||||
}
|
||||
fl->print_on(&out);
|
||||
_total_free += fl->count() * fl->size();
|
||||
total()->set_count(total()->count() + fl->count());
|
||||
}
|
||||
|
||||
#if INCLUDE_ALL_GCS
|
||||
void do_list(AdaptiveFreeList<Chunk_t>* fl) {
|
||||
LogStreamHandle(Debug, gc, freelist, census) out;
|
||||
|
||||
if (++_print_line >= 40) {
|
||||
FreeList_t::print_labels_on(&out, "size");
|
||||
_print_line = 0;
|
||||
}
|
||||
fl->print_on(&out);
|
||||
_total_free += fl->count() * fl->size() ;
|
||||
total()->set_count( total()->count() + fl->count() );
|
||||
total()->set_bfr_surp( total()->bfr_surp() + fl->bfr_surp() );
|
||||
total()->set_surplus( total()->split_deaths() + fl->surplus() );
|
||||
total()->set_desired( total()->desired() + fl->desired() );
|
||||
total()->set_prev_sweep( total()->prev_sweep() + fl->prev_sweep() );
|
||||
total()->set_before_sweep(total()->before_sweep() + fl->before_sweep());
|
||||
total()->set_coal_births( total()->coal_births() + fl->coal_births() );
|
||||
total()->set_coal_deaths( total()->coal_deaths() + fl->coal_deaths() );
|
||||
total()->set_split_births(total()->split_births() + fl->split_births());
|
||||
total()->set_split_deaths(total()->split_deaths() + fl->split_deaths());
|
||||
}
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
};
|
||||
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
void BinaryTreeDictionary<Chunk_t, FreeList_t>::print_dict_census(outputStream* st) const {
|
||||
|
||||
st->print("BinaryTree");
|
||||
FreeList_t::print_labels_on(st, "size");
|
||||
PrintTreeCensusClosure<Chunk_t, FreeList_t> ptc;
|
||||
ptc.do_tree(root());
|
||||
|
||||
FreeList_t* total = ptc.total();
|
||||
FreeList_t::print_labels_on(st, " ");
|
||||
}
|
||||
|
||||
#if INCLUDE_ALL_GCS
|
||||
template <>
|
||||
void AFLBinaryTreeDictionary::print_dict_census(outputStream* st) const {
|
||||
|
||||
st->print_cr("BinaryTree");
|
||||
AdaptiveFreeList<FreeChunk>::print_labels_on(st, "size");
|
||||
PrintTreeCensusClosure<FreeChunk, AdaptiveFreeList<FreeChunk> > ptc;
|
||||
ptc.do_tree(root());
|
||||
|
||||
AdaptiveFreeList<FreeChunk>* total = ptc.total();
|
||||
AdaptiveFreeList<FreeChunk>::print_labels_on(st, " ");
|
||||
total->print_on(st, "TOTAL\t");
|
||||
st->print_cr("total_free(words): " SIZE_FORMAT_W(16) " growth: %8.5f deficit: %8.5f",
|
||||
ptc.total_free(),
|
||||
(double)(total->split_births() + total->coal_births()
|
||||
- total->split_deaths() - total->coal_deaths())
|
||||
/(total->prev_sweep() != 0 ? (double)total->prev_sweep() : 1.0),
|
||||
(double)(total->desired() - total->count())
|
||||
/(total->desired() != 0 ? (double)total->desired() : 1.0));
|
||||
}
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
|
||||
template <class Chunk_t, class FreeList_t>
|
||||
class PrintFreeListsClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
|
||||
outputStream* _st;
|
||||
@ -1411,19 +1022,4 @@ void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify() const {
|
||||
guarantee(total_size() == total_size_in_tree(root()), "Total Size inconsistency");
|
||||
}
|
||||
|
||||
template class TreeList<Metablock, FreeList<Metablock> >;
|
||||
template class BinaryTreeDictionary<Metablock, FreeList<Metablock> >;
|
||||
template class TreeChunk<Metablock, FreeList<Metablock> >;
|
||||
|
||||
template class TreeList<Metachunk, FreeList<Metachunk> >;
|
||||
template class BinaryTreeDictionary<Metachunk, FreeList<Metachunk> >;
|
||||
template class TreeChunk<Metachunk, FreeList<Metachunk> >;
|
||||
|
||||
|
||||
#if INCLUDE_ALL_GCS
|
||||
// Explicitly instantiate these types for FreeChunk.
|
||||
template class TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >;
|
||||
template class BinaryTreeDictionary<FreeChunk, AdaptiveFreeList<FreeChunk> >;
|
||||
template class TreeChunk<FreeChunk, AdaptiveFreeList<FreeChunk> >;
|
||||
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
#endif // SHARE_VM_MEMORY_BINARYTREEDICTIONARY_INLINE_HPP
|
||||
@ -25,10 +25,6 @@
|
||||
#ifndef SHARE_VM_MEMORY_FREELIST_HPP
|
||||
#define SHARE_VM_MEMORY_FREELIST_HPP
|
||||
|
||||
#include "gc/cms/allocationStats.hpp"
|
||||
|
||||
class CompactibleFreeListSpace;
|
||||
|
||||
// A class for maintaining a free list of Chunk's. The FreeList
|
||||
// maintains a the structure of the list (head, tail, etc.) plus
|
||||
// statistics for allocations from the list. The links between items
|
||||
|
||||
@ -22,7 +22,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#ifndef SHARE_MEMORY_FREELIST_INLINE_HPP
|
||||
#define SHARE_MEMORY_FREELIST_INLINE_HPP
|
||||
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "memory/freeList.hpp"
|
||||
#include "memory/metachunk.hpp"
|
||||
@ -30,9 +32,6 @@
|
||||
#include "runtime/mutex.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#if INCLUDE_ALL_GCS
|
||||
#include "gc/cms/freeChunk.hpp"
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
|
||||
// Free list. A FreeList is used to access a linked list of chunks
|
||||
// of space in the heap. The head and tail are maintained so that
|
||||
@ -329,8 +328,4 @@ void FreeList<Chunk_t>::print_on(outputStream* st, const char* c) const {
|
||||
}
|
||||
}
|
||||
|
||||
template class FreeList<Metablock>;
|
||||
template class FreeList<Metachunk>;
|
||||
#if INCLUDE_ALL_GCS
|
||||
template class FreeList<FreeChunk>;
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
#endif // SHARE_MEMORY_FREELIST_INLINE_HPP
|
||||
@ -28,9 +28,9 @@
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/binaryTreeDictionary.hpp"
|
||||
#include "memory/binaryTreeDictionary.inline.hpp"
|
||||
#include "memory/filemap.hpp"
|
||||
#include "memory/freeList.hpp"
|
||||
#include "memory/freeList.inline.hpp"
|
||||
#include "memory/metachunk.hpp"
|
||||
#include "memory/metaspace.hpp"
|
||||
#include "memory/metaspaceGCThresholdUpdater.hpp"
|
||||
@ -5342,4 +5342,3 @@ extern void test_metaspace_retrieve_chunk_geometry(Metaspace::MetadataType mdTyp
|
||||
out->medium_chunk_word_size = ClassMediumChunk;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user