提交 c290220e 编写于 作者: Y ysr

6631166: CMS: better heuristics when combatting fragmentation

Summary: Autonomic per-worker free block cache sizing, tunable coalition policies, fixes to per-size block statistics, retuned gain and bandwidth of some feedback loop filters to allow quicker reactivity to abrupt changes in ambient demand, and other heuristics to reduce fragmentation of the CMS old gen. Also tightened some assertions, including those related to locking.
Reviewed-by: jmasa
上级 7f92f7a2
...@@ -62,12 +62,13 @@ TreeList* TreeList::as_TreeList(TreeChunk* tc) { ...@@ -62,12 +62,13 @@ TreeList* TreeList::as_TreeList(TreeChunk* tc) {
tl->link_head(tc); tl->link_head(tc);
tl->link_tail(tc); tl->link_tail(tc);
tl->set_count(1); tl->set_count(1);
tl->init_statistics(); tl->init_statistics(true /* split_birth */);
tl->setParent(NULL); tl->setParent(NULL);
tl->setLeft(NULL); tl->setLeft(NULL);
tl->setRight(NULL); tl->setRight(NULL);
return tl; return tl;
} }
TreeList* TreeList::as_TreeList(HeapWord* addr, size_t size) { TreeList* TreeList::as_TreeList(HeapWord* addr, size_t size) {
TreeChunk* tc = (TreeChunk*) addr; TreeChunk* tc = (TreeChunk*) addr;
assert(size >= sizeof(TreeChunk), "Chunk is too small for a TreeChunk"); assert(size >= sizeof(TreeChunk), "Chunk is too small for a TreeChunk");
...@@ -267,6 +268,31 @@ TreeChunk* TreeList::first_available() { ...@@ -267,6 +268,31 @@ TreeChunk* TreeList::first_available() {
return retTC; return retTC;
} }
// Returns the block with the largest heap address amongst
// those in the list for this size; potentially slow and expensive,
// use with caution!
TreeChunk* TreeList::largest_address() {
guarantee(head() != NULL, "The head of the list cannot be NULL");
FreeChunk* fc = head()->next();
TreeChunk* retTC;
if (fc == NULL) {
retTC = head_as_TreeChunk();
} else {
// walk down the list and return the one with the highest
// heap address among chunks of this size.
FreeChunk* last = fc;
while (fc->next() != NULL) {
if ((HeapWord*)last < (HeapWord*)fc) {
last = fc;
}
fc = fc->next();
}
retTC = TreeChunk::as_TreeChunk(last);
}
assert(retTC->list() == this, "Wrong type of chunk.");
return retTC;
}
BinaryTreeDictionary::BinaryTreeDictionary(MemRegion mr, bool splay): BinaryTreeDictionary::BinaryTreeDictionary(MemRegion mr, bool splay):
_splay(splay) _splay(splay)
{ {
...@@ -379,7 +405,7 @@ BinaryTreeDictionary::getChunkFromTree(size_t size, Dither dither, bool splay) ...@@ -379,7 +405,7 @@ BinaryTreeDictionary::getChunkFromTree(size_t size, Dither dither, bool splay)
break; break;
} }
// The evm code reset the hint of the candidate as // The evm code reset the hint of the candidate as
// at an interrim point. Why? Seems like this leaves // at an interim point. Why? Seems like this leaves
// the hint pointing to a list that didn't work. // the hint pointing to a list that didn't work.
// curTL->set_hint(hintTL->size()); // curTL->set_hint(hintTL->size());
} }
...@@ -436,7 +462,7 @@ FreeChunk* BinaryTreeDictionary::findLargestDict() const { ...@@ -436,7 +462,7 @@ FreeChunk* BinaryTreeDictionary::findLargestDict() const {
TreeList *curTL = root(); TreeList *curTL = root();
if (curTL != NULL) { if (curTL != NULL) {
while(curTL->right() != NULL) curTL = curTL->right(); while(curTL->right() != NULL) curTL = curTL->right();
return curTL->first_available(); return curTL->largest_address();
} else { } else {
return NULL; return NULL;
} }
...@@ -664,7 +690,7 @@ void BinaryTreeDictionary::insertChunkInTree(FreeChunk* fc) { ...@@ -664,7 +690,7 @@ void BinaryTreeDictionary::insertChunkInTree(FreeChunk* fc) {
} }
} }
TreeChunk* tc = TreeChunk::as_TreeChunk(fc); TreeChunk* tc = TreeChunk::as_TreeChunk(fc);
// This chunk is being returned to the binary try. It's embedded // This chunk is being returned to the binary tree. Its embedded
// TreeList should be unused at this point. // TreeList should be unused at this point.
tc->initialize(); tc->initialize();
if (curTL != NULL) { // exact match if (curTL != NULL) { // exact match
...@@ -807,6 +833,8 @@ void BinaryTreeDictionary::dictCensusUpdate(size_t size, bool split, bool birth) ...@@ -807,6 +833,8 @@ void BinaryTreeDictionary::dictCensusUpdate(size_t size, bool split, bool birth)
} }
bool BinaryTreeDictionary::coalDictOverPopulated(size_t size) { bool BinaryTreeDictionary::coalDictOverPopulated(size_t size) {
if (FLSAlwaysCoalesceLarge) return true;
TreeList* list_of_size = findList(size); TreeList* list_of_size = findList(size);
// None of requested size implies overpopulated. // None of requested size implies overpopulated.
return list_of_size == NULL || list_of_size->coalDesired() <= 0 || return list_of_size == NULL || list_of_size->coalDesired() <= 0 ||
...@@ -854,17 +882,20 @@ class BeginSweepClosure : public AscendTreeCensusClosure { ...@@ -854,17 +882,20 @@ class BeginSweepClosure : public AscendTreeCensusClosure {
double _percentage; double _percentage;
float _inter_sweep_current; float _inter_sweep_current;
float _inter_sweep_estimate; float _inter_sweep_estimate;
float _intra_sweep_estimate;
public: public:
BeginSweepClosure(double p, float inter_sweep_current, BeginSweepClosure(double p, float inter_sweep_current,
float inter_sweep_estimate) : float inter_sweep_estimate,
float intra_sweep_estimate) :
_percentage(p), _percentage(p),
_inter_sweep_current(inter_sweep_current), _inter_sweep_current(inter_sweep_current),
_inter_sweep_estimate(inter_sweep_estimate) { } _inter_sweep_estimate(inter_sweep_estimate),
_intra_sweep_estimate(intra_sweep_estimate) { }
void do_list(FreeList* fl) { void do_list(FreeList* fl) {
double coalSurplusPercent = _percentage; double coalSurplusPercent = _percentage;
fl->compute_desired(_inter_sweep_current, _inter_sweep_estimate); fl->compute_desired(_inter_sweep_current, _inter_sweep_estimate, _intra_sweep_estimate);
fl->set_coalDesired((ssize_t)((double)fl->desired() * coalSurplusPercent)); fl->set_coalDesired((ssize_t)((double)fl->desired() * coalSurplusPercent));
fl->set_beforeSweep(fl->count()); fl->set_beforeSweep(fl->count());
fl->set_bfrSurp(fl->surplus()); fl->set_bfrSurp(fl->surplus());
...@@ -939,9 +970,10 @@ FreeChunk* BinaryTreeDictionary::find_chunk_ends_at(HeapWord* target) const { ...@@ -939,9 +970,10 @@ FreeChunk* BinaryTreeDictionary::find_chunk_ends_at(HeapWord* target) const {
} }
void BinaryTreeDictionary::beginSweepDictCensus(double coalSurplusPercent, void BinaryTreeDictionary::beginSweepDictCensus(double coalSurplusPercent,
float inter_sweep_current, float inter_sweep_estimate) { float inter_sweep_current, float inter_sweep_estimate, float intra_sweep_estimate) {
BeginSweepClosure bsc(coalSurplusPercent, inter_sweep_current, BeginSweepClosure bsc(coalSurplusPercent, inter_sweep_current,
inter_sweep_estimate); inter_sweep_estimate,
intra_sweep_estimate);
bsc.do_tree(root()); bsc.do_tree(root());
} }
...@@ -1077,13 +1109,13 @@ void BinaryTreeDictionary::reportStatistics() const { ...@@ -1077,13 +1109,13 @@ void BinaryTreeDictionary::reportStatistics() const {
// Print census information - counts, births, deaths, etc. // Print census information - counts, births, deaths, etc.
// for each list in the tree. Also print some summary // for each list in the tree. Also print some summary
// information. // information.
class printTreeCensusClosure : public AscendTreeCensusClosure { class PrintTreeCensusClosure : public AscendTreeCensusClosure {
int _print_line; int _print_line;
size_t _totalFree; size_t _totalFree;
FreeList _total; FreeList _total;
public: public:
printTreeCensusClosure() { PrintTreeCensusClosure() {
_print_line = 0; _print_line = 0;
_totalFree = 0; _totalFree = 0;
} }
...@@ -1113,7 +1145,7 @@ void BinaryTreeDictionary::printDictCensus(void) const { ...@@ -1113,7 +1145,7 @@ void BinaryTreeDictionary::printDictCensus(void) const {
gclog_or_tty->print("\nBinaryTree\n"); gclog_or_tty->print("\nBinaryTree\n");
FreeList::print_labels_on(gclog_or_tty, "size"); FreeList::print_labels_on(gclog_or_tty, "size");
printTreeCensusClosure ptc; PrintTreeCensusClosure ptc;
ptc.do_tree(root()); ptc.do_tree(root());
FreeList* total = ptc.total(); FreeList* total = ptc.total();
...@@ -1130,6 +1162,38 @@ void BinaryTreeDictionary::printDictCensus(void) const { ...@@ -1130,6 +1162,38 @@ void BinaryTreeDictionary::printDictCensus(void) const {
/(total->desired() != 0 ? (double)total->desired() : 1.0)); /(total->desired() != 0 ? (double)total->desired() : 1.0));
} }
class PrintFreeListsClosure : public AscendTreeCensusClosure {
outputStream* _st;
int _print_line;
public:
PrintFreeListsClosure(outputStream* st) {
_st = st;
_print_line = 0;
}
void do_list(FreeList* fl) {
if (++_print_line >= 40) {
FreeList::print_labels_on(_st, "size");
_print_line = 0;
}
fl->print_on(gclog_or_tty);
size_t sz = fl->size();
for (FreeChunk* fc = fl->head(); fc != NULL;
fc = fc->next()) {
_st->print_cr("\t[" PTR_FORMAT "," PTR_FORMAT ") %s",
fc, (HeapWord*)fc + sz,
fc->cantCoalesce() ? "\t CC" : "");
}
}
};
void BinaryTreeDictionary::print_free_lists(outputStream* st) const {
FreeList::print_labels_on(st, "size");
PrintFreeListsClosure pflc(st);
pflc.do_tree(root());
}
// Verify the following tree invariants: // Verify the following tree invariants:
// . _root has no parent // . _root has no parent
// . parent and child point to each other // . parent and child point to each other
......
...@@ -42,9 +42,6 @@ class TreeList: public FreeList { ...@@ -42,9 +42,6 @@ class TreeList: public FreeList {
friend class AscendTreeCensusClosure; friend class AscendTreeCensusClosure;
friend class DescendTreeCensusClosure; friend class DescendTreeCensusClosure;
friend class DescendTreeSearchClosure; friend class DescendTreeSearchClosure;
TreeList* _parent;
TreeList* _left;
TreeList* _right;
protected: protected:
TreeList* parent() const { return _parent; } TreeList* parent() const { return _parent; }
...@@ -82,6 +79,11 @@ class TreeList: public FreeList { ...@@ -82,6 +79,11 @@ class TreeList: public FreeList {
// to a TreeChunk. // to a TreeChunk.
TreeChunk* first_available(); TreeChunk* first_available();
// Returns the block with the largest heap address amongst
// those in the list for this size; potentially slow and expensive,
// use with caution!
TreeChunk* largest_address();
// removeChunkReplaceIfNeeded() removes the given "tc" from the TreeList. // removeChunkReplaceIfNeeded() removes the given "tc" from the TreeList.
// If "tc" is the first chunk in the list, it is also the // If "tc" is the first chunk in the list, it is also the
// TreeList that is the node in the tree. removeChunkReplaceIfNeeded() // TreeList that is the node in the tree. removeChunkReplaceIfNeeded()
...@@ -254,8 +256,9 @@ class BinaryTreeDictionary: public FreeBlockDictionary { ...@@ -254,8 +256,9 @@ class BinaryTreeDictionary: public FreeBlockDictionary {
// Methods called at the beginning of a sweep to prepare the // Methods called at the beginning of a sweep to prepare the
// statistics for the sweep. // statistics for the sweep.
void beginSweepDictCensus(double coalSurplusPercent, void beginSweepDictCensus(double coalSurplusPercent,
float sweep_current, float inter_sweep_current,
float sweep_estimate); float inter_sweep_estimate,
float intra_sweep_estimate);
// Methods called after the end of a sweep to modify the // Methods called after the end of a sweep to modify the
// statistics for the sweep. // statistics for the sweep.
void endSweepDictCensus(double splitSurplusPercent); void endSweepDictCensus(double splitSurplusPercent);
...@@ -269,6 +272,7 @@ class BinaryTreeDictionary: public FreeBlockDictionary { ...@@ -269,6 +272,7 @@ class BinaryTreeDictionary: public FreeBlockDictionary {
// Print the statistcis for all the lists in the tree. Also may // Print the statistcis for all the lists in the tree. Also may
// print out summaries. // print out summaries.
void printDictCensus(void) const; void printDictCensus(void) const;
void print_free_lists(outputStream* st) const;
// For debugging. Returns the sum of the _returnedBytes for // For debugging. Returns the sum of the _returnedBytes for
// all lists in the tree. // all lists in the tree.
......
...@@ -32,7 +32,9 @@ ...@@ -32,7 +32,9 @@
// threads. The second argument is in support of an extra locking // threads. The second argument is in support of an extra locking
// check for CFL spaces' free list locks. // check for CFL spaces' free list locks.
#ifndef PRODUCT #ifndef PRODUCT
void CMSLockVerifier::assert_locked(const Mutex* lock, const Mutex* p_lock) { void CMSLockVerifier::assert_locked(const Mutex* lock,
const Mutex* p_lock1,
const Mutex* p_lock2) {
if (!Universe::is_fully_initialized()) { if (!Universe::is_fully_initialized()) {
return; return;
} }
...@@ -40,7 +42,7 @@ void CMSLockVerifier::assert_locked(const Mutex* lock, const Mutex* p_lock) { ...@@ -40,7 +42,7 @@ void CMSLockVerifier::assert_locked(const Mutex* lock, const Mutex* p_lock) {
Thread* myThread = Thread::current(); Thread* myThread = Thread::current();
if (lock == NULL) { // a "lock-free" structure, e.g. MUT, protected by CMS token if (lock == NULL) { // a "lock-free" structure, e.g. MUT, protected by CMS token
assert(p_lock == NULL, "Unexpected state"); assert(p_lock1 == NULL && p_lock2 == NULL, "Unexpected caller error");
if (myThread->is_ConcurrentGC_thread()) { if (myThread->is_ConcurrentGC_thread()) {
// This test might have to change in the future, if there can be // This test might have to change in the future, if there can be
// multiple peer CMS threads. But for now, if we're testing the CMS // multiple peer CMS threads. But for now, if we're testing the CMS
...@@ -60,9 +62,6 @@ void CMSLockVerifier::assert_locked(const Mutex* lock, const Mutex* p_lock) { ...@@ -60,9 +62,6 @@ void CMSLockVerifier::assert_locked(const Mutex* lock, const Mutex* p_lock) {
return; return;
} }
if (ParallelGCThreads == 0) {
assert_lock_strong(lock);
} else {
if (myThread->is_VM_thread() if (myThread->is_VM_thread()
|| myThread->is_ConcurrentGC_thread() || myThread->is_ConcurrentGC_thread()
|| myThread->is_Java_thread()) { || myThread->is_Java_thread()) {
...@@ -73,11 +72,11 @@ void CMSLockVerifier::assert_locked(const Mutex* lock, const Mutex* p_lock) { ...@@ -73,11 +72,11 @@ void CMSLockVerifier::assert_locked(const Mutex* lock, const Mutex* p_lock) {
// threads are holding "sub-locks" of freeListLock(). We check only // threads are holding "sub-locks" of freeListLock(). We check only
// the parDictionaryAllocLock because the others are too numerous. // the parDictionaryAllocLock because the others are too numerous.
// This spl case code is somewhat ugly and any improvements // This spl case code is somewhat ugly and any improvements
// are welcome XXX FIX ME!! // are welcome.
if (p_lock != NULL) { assert(p_lock1 == NULL || !p_lock1->is_locked() || p_lock1->owned_by_self(),
assert(!p_lock->is_locked() || p_lock->owned_by_self(), "Possible race between this and parallel GC threads");
assert(p_lock2 == NULL || !p_lock2->is_locked() || p_lock2->owned_by_self(),
"Possible race between this and parallel GC threads"); "Possible race between this and parallel GC threads");
}
} else if (myThread->is_GC_task_thread()) { } else if (myThread->is_GC_task_thread()) {
// Make sure that the VM or CMS thread holds lock on our behalf // Make sure that the VM or CMS thread holds lock on our behalf
// XXX If there were a concept of a gang_master for a (set of) // XXX If there were a concept of a gang_master for a (set of)
...@@ -86,10 +85,16 @@ void CMSLockVerifier::assert_locked(const Mutex* lock, const Mutex* p_lock) { ...@@ -86,10 +85,16 @@ void CMSLockVerifier::assert_locked(const Mutex* lock, const Mutex* p_lock) {
assert(lock->owner() == VMThread::vm_thread() || assert(lock->owner() == VMThread::vm_thread() ||
lock->owner() == ConcurrentMarkSweepThread::cmst(), lock->owner() == ConcurrentMarkSweepThread::cmst(),
"Should be locked by VM thread or CMS thread on my behalf"); "Should be locked by VM thread or CMS thread on my behalf");
if (p_lock1 != NULL) {
assert_lock_strong(p_lock1);
}
if (p_lock2 != NULL) {
assert_lock_strong(p_lock2);
}
} else { } else {
// Make sure we didn't miss some obscure corner case // Make sure we didn't miss some other thread type calling into here;
// perhaps as a result of future VM evolution.
ShouldNotReachHere(); ShouldNotReachHere();
} }
}
} }
#endif #endif
...@@ -29,8 +29,11 @@ ...@@ -29,8 +29,11 @@
// the parallel threads. // the parallel threads.
class CMSLockVerifier: AllStatic { class CMSLockVerifier: AllStatic {
public: public:
static void assert_locked(const Mutex* lock, const Mutex* p_lock) static void assert_locked(const Mutex* lock, const Mutex* p_lock1, const Mutex* p_lock2)
PRODUCT_RETURN; PRODUCT_RETURN;
static void assert_locked(const Mutex* lock, const Mutex* p_lock) {
assert_locked(lock, p_lock, NULL);
}
static void assert_locked(const Mutex* lock) { static void assert_locked(const Mutex* lock) {
assert_locked(lock, NULL); assert_locked(lock, NULL);
} }
......
...@@ -25,8 +25,6 @@ ...@@ -25,8 +25,6 @@
// Classes in support of keeping track of promotions into a non-Contiguous // Classes in support of keeping track of promotions into a non-Contiguous
// space, in this case a CompactibleFreeListSpace. // space, in this case a CompactibleFreeListSpace.
#define CFLS_LAB_REFILL_STATS 0
// Forward declarations // Forward declarations
class CompactibleFreeListSpace; class CompactibleFreeListSpace;
class BlkClosure; class BlkClosure;
...@@ -89,6 +87,9 @@ class SpoolBlock: public FreeChunk { ...@@ -89,6 +87,9 @@ class SpoolBlock: public FreeChunk {
displacedHdr = (markOop*)&displacedHdr; displacedHdr = (markOop*)&displacedHdr;
nextSpoolBlock = NULL; nextSpoolBlock = NULL;
} }
void print_on(outputStream* st) const;
void print() const { print_on(gclog_or_tty); }
}; };
class PromotionInfo VALUE_OBJ_CLASS_SPEC { class PromotionInfo VALUE_OBJ_CLASS_SPEC {
...@@ -121,7 +122,7 @@ class PromotionInfo VALUE_OBJ_CLASS_SPEC { ...@@ -121,7 +122,7 @@ class PromotionInfo VALUE_OBJ_CLASS_SPEC {
return _promoHead == NULL; return _promoHead == NULL;
} }
void startTrackingPromotions(); void startTrackingPromotions();
void stopTrackingPromotions(); void stopTrackingPromotions(uint worker_id = 0);
bool tracking() const { return _tracking; } bool tracking() const { return _tracking; }
void track(PromotedObject* trackOop); // keep track of a promoted oop void track(PromotedObject* trackOop); // keep track of a promoted oop
// The following variant must be used when trackOop is not fully // The following variant must be used when trackOop is not fully
...@@ -161,6 +162,9 @@ class PromotionInfo VALUE_OBJ_CLASS_SPEC { ...@@ -161,6 +162,9 @@ class PromotionInfo VALUE_OBJ_CLASS_SPEC {
_nextIndex = 0; _nextIndex = 0;
} }
void print_on(outputStream* st) const;
void print_statistics(uint worker_id) const;
}; };
class LinearAllocBlock VALUE_OBJ_CLASS_SPEC { class LinearAllocBlock VALUE_OBJ_CLASS_SPEC {
...@@ -243,6 +247,7 @@ class CompactibleFreeListSpace: public CompactibleSpace { ...@@ -243,6 +247,7 @@ class CompactibleFreeListSpace: public CompactibleSpace {
mutable Mutex _freelistLock; mutable Mutex _freelistLock;
// locking verifier convenience function // locking verifier convenience function
void assert_locked() const PRODUCT_RETURN; void assert_locked() const PRODUCT_RETURN;
void assert_locked(const Mutex* lock) const PRODUCT_RETURN;
// Linear allocation blocks // Linear allocation blocks
LinearAllocBlock _smallLinearAllocBlock; LinearAllocBlock _smallLinearAllocBlock;
...@@ -281,13 +286,6 @@ class CompactibleFreeListSpace: public CompactibleSpace { ...@@ -281,13 +286,6 @@ class CompactibleFreeListSpace: public CompactibleSpace {
// Locks protecting the exact lists during par promotion allocation. // Locks protecting the exact lists during par promotion allocation.
Mutex* _indexedFreeListParLocks[IndexSetSize]; Mutex* _indexedFreeListParLocks[IndexSetSize];
#if CFLS_LAB_REFILL_STATS
// Some statistics.
jint _par_get_chunk_from_small;
jint _par_get_chunk_from_large;
#endif
// Attempt to obtain up to "n" blocks of the size "word_sz" (which is // Attempt to obtain up to "n" blocks of the size "word_sz" (which is
// required to be smaller than "IndexSetSize".) If successful, // required to be smaller than "IndexSetSize".) If successful,
// adds them to "fl", which is required to be an empty free list. // adds them to "fl", which is required to be an empty free list.
...@@ -320,7 +318,7 @@ class CompactibleFreeListSpace: public CompactibleSpace { ...@@ -320,7 +318,7 @@ class CompactibleFreeListSpace: public CompactibleSpace {
// Helper function for getChunkFromIndexedFreeList. // Helper function for getChunkFromIndexedFreeList.
// Replenish the indexed free list for this "size". Do not take from an // Replenish the indexed free list for this "size". Do not take from an
// underpopulated size. // underpopulated size.
FreeChunk* getChunkFromIndexedFreeListHelper(size_t size); FreeChunk* getChunkFromIndexedFreeListHelper(size_t size, bool replenish = true);
// Get a chunk from the indexed free list. If the indexed free list // Get a chunk from the indexed free list. If the indexed free list
// does not have a free chunk, try to replenish the indexed free list // does not have a free chunk, try to replenish the indexed free list
...@@ -430,10 +428,6 @@ class CompactibleFreeListSpace: public CompactibleSpace { ...@@ -430,10 +428,6 @@ class CompactibleFreeListSpace: public CompactibleSpace {
void initialize_sequential_subtasks_for_marking(int n_threads, void initialize_sequential_subtasks_for_marking(int n_threads,
HeapWord* low = NULL); HeapWord* low = NULL);
#if CFLS_LAB_REFILL_STATS
void print_par_alloc_stats();
#endif
// Space enquiries // Space enquiries
size_t used() const; size_t used() const;
size_t free() const; size_t free() const;
...@@ -617,6 +611,12 @@ class CompactibleFreeListSpace: public CompactibleSpace { ...@@ -617,6 +611,12 @@ class CompactibleFreeListSpace: public CompactibleSpace {
// Do some basic checks on the the free lists. // Do some basic checks on the the free lists.
void checkFreeListConsistency() const PRODUCT_RETURN; void checkFreeListConsistency() const PRODUCT_RETURN;
// Printing support
void dump_at_safepoint_with_locks(CMSCollector* c, outputStream* st);
void print_indexed_free_lists(outputStream* st) const;
void print_dictionary_free_lists(outputStream* st) const;
void print_promo_info_blocks(outputStream* st) const;
NOT_PRODUCT ( NOT_PRODUCT (
void initializeIndexedFreeListArrayReturnedBytes(); void initializeIndexedFreeListArrayReturnedBytes();
size_t sumIndexedFreeListArrayReturnedBytes(); size_t sumIndexedFreeListArrayReturnedBytes();
...@@ -638,8 +638,9 @@ class CompactibleFreeListSpace: public CompactibleSpace { ...@@ -638,8 +638,9 @@ class CompactibleFreeListSpace: public CompactibleSpace {
// Statistics functions // Statistics functions
// Initialize census for lists before the sweep. // Initialize census for lists before the sweep.
void beginSweepFLCensus(float sweep_current, void beginSweepFLCensus(float inter_sweep_current,
float sweep_estimate); float inter_sweep_estimate,
float intra_sweep_estimate);
// Set the surplus for each of the free lists. // Set the surplus for each of the free lists.
void setFLSurplus(); void setFLSurplus();
// Set the hint for each of the free lists. // Set the hint for each of the free lists.
...@@ -730,16 +731,17 @@ class CFLS_LAB : public CHeapObj { ...@@ -730,16 +731,17 @@ class CFLS_LAB : public CHeapObj {
FreeList _indexedFreeList[CompactibleFreeListSpace::IndexSetSize]; FreeList _indexedFreeList[CompactibleFreeListSpace::IndexSetSize];
// Initialized from a command-line arg. // Initialized from a command-line arg.
size_t _blocks_to_claim;
#if CFLS_LAB_REFILL_STATS // Allocation statistics in support of dynamic adjustment of
// Some statistics. // #blocks to claim per get_from_global_pool() call below.
int _refills; static AdaptiveWeightedAverage
int _blocksTaken; _blocks_to_claim [CompactibleFreeListSpace::IndexSetSize];
static int _tot_refills; static size_t _global_num_blocks [CompactibleFreeListSpace::IndexSetSize];
static int _tot_blocksTaken; static int _global_num_workers[CompactibleFreeListSpace::IndexSetSize];
static int _next_threshold; size_t _num_blocks [CompactibleFreeListSpace::IndexSetSize];
#endif
// Internal work method
void get_from_global_pool(size_t word_sz, FreeList* fl);
public: public:
CFLS_LAB(CompactibleFreeListSpace* cfls); CFLS_LAB(CompactibleFreeListSpace* cfls);
...@@ -748,7 +750,12 @@ public: ...@@ -748,7 +750,12 @@ public:
HeapWord* alloc(size_t word_sz); HeapWord* alloc(size_t word_sz);
// Return any unused portions of the buffer to the global pool. // Return any unused portions of the buffer to the global pool.
void retire(); void retire(int tid);
// Dynamic OldPLABSize sizing
static void compute_desired_plab_size();
// When the settings are modified from default static initialization
static void modify_initialization(size_t n, unsigned wt);
}; };
size_t PromotionInfo::refillSize() const { size_t PromotionInfo::refillSize() const {
......
...@@ -253,7 +253,6 @@ void ConcurrentMarkSweepGeneration::init_initiating_occupancy(intx io, intx tr) ...@@ -253,7 +253,6 @@ void ConcurrentMarkSweepGeneration::init_initiating_occupancy(intx io, intx tr)
} }
} }
void ConcurrentMarkSweepGeneration::ref_processor_init() { void ConcurrentMarkSweepGeneration::ref_processor_init() {
assert(collector() != NULL, "no collector"); assert(collector() != NULL, "no collector");
collector()->ref_processor_init(); collector()->ref_processor_init();
...@@ -341,6 +340,14 @@ CMSStats::CMSStats(ConcurrentMarkSweepGeneration* cms_gen, unsigned int alpha): ...@@ -341,6 +340,14 @@ CMSStats::CMSStats(ConcurrentMarkSweepGeneration* cms_gen, unsigned int alpha):
_icms_duty_cycle = CMSIncrementalDutyCycle; _icms_duty_cycle = CMSIncrementalDutyCycle;
} }
double CMSStats::cms_free_adjustment_factor(size_t free) const {
// TBD: CR 6909490
return 1.0;
}
void CMSStats::adjust_cms_free_adjustment_factor(bool fail, size_t free) {
}
// If promotion failure handling is on use // If promotion failure handling is on use
// the padded average size of the promotion for each // the padded average size of the promotion for each
// young generation collection. // young generation collection.
...@@ -361,7 +368,11 @@ double CMSStats::time_until_cms_gen_full() const { ...@@ -361,7 +368,11 @@ double CMSStats::time_until_cms_gen_full() const {
// Adjust by the safety factor. // Adjust by the safety factor.
double cms_free_dbl = (double)cms_free; double cms_free_dbl = (double)cms_free;
cms_free_dbl = cms_free_dbl * (100.0 - CMSIncrementalSafetyFactor) / 100.0; double cms_adjustment = (100.0 - CMSIncrementalSafetyFactor)/100.0;
// Apply a further correction factor which tries to adjust
// for recent occurance of concurrent mode failures.
cms_adjustment = cms_adjustment * cms_free_adjustment_factor(cms_free);
cms_free_dbl = cms_free_dbl * cms_adjustment;
if (PrintGCDetails && Verbose) { if (PrintGCDetails && Verbose) {
gclog_or_tty->print_cr("CMSStats::time_until_cms_gen_full: cms_free " gclog_or_tty->print_cr("CMSStats::time_until_cms_gen_full: cms_free "
...@@ -395,6 +406,8 @@ double CMSStats::time_until_cms_start() const { ...@@ -395,6 +406,8 @@ double CMSStats::time_until_cms_start() const {
// late. // late.
double work = cms_duration() + gc0_period(); double work = cms_duration() + gc0_period();
double deadline = time_until_cms_gen_full(); double deadline = time_until_cms_gen_full();
// If a concurrent mode failure occurred recently, we want to be
// more conservative and halve our expected time_until_cms_gen_full()
if (work > deadline) { if (work > deadline) {
if (Verbose && PrintGCDetails) { if (Verbose && PrintGCDetails) {
gclog_or_tty->print( gclog_or_tty->print(
...@@ -556,7 +569,8 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen, ...@@ -556,7 +569,8 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
_should_unload_classes(false), _should_unload_classes(false),
_concurrent_cycles_since_last_unload(0), _concurrent_cycles_since_last_unload(0),
_roots_scanning_options(0), _roots_scanning_options(0),
_sweep_estimate(CMS_SweepWeight, CMS_SweepPadding) _inter_sweep_estimate(CMS_SweepWeight, CMS_SweepPadding),
_intra_sweep_estimate(CMS_SweepWeight, CMS_SweepPadding)
{ {
if (ExplicitGCInvokesConcurrentAndUnloadsClasses) { if (ExplicitGCInvokesConcurrentAndUnloadsClasses) {
ExplicitGCInvokesConcurrent = true; ExplicitGCInvokesConcurrent = true;
...@@ -773,7 +787,7 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen, ...@@ -773,7 +787,7 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
NOT_PRODUCT(_overflow_counter = CMSMarkStackOverflowInterval;) NOT_PRODUCT(_overflow_counter = CMSMarkStackOverflowInterval;)
_gc_counters = new CollectorCounters("CMS", 1); _gc_counters = new CollectorCounters("CMS", 1);
_completed_initialization = true; _completed_initialization = true;
_sweep_timer.start(); // start of time _inter_sweep_timer.start(); // start of time
} }
const char* ConcurrentMarkSweepGeneration::name() const { const char* ConcurrentMarkSweepGeneration::name() const {
...@@ -900,6 +914,14 @@ bool ConcurrentMarkSweepGeneration::promotion_attempt_is_safe( ...@@ -900,6 +914,14 @@ bool ConcurrentMarkSweepGeneration::promotion_attempt_is_safe(
return result; return result;
} }
// At a promotion failure dump information on block layout in heap
// (cms old generation).
void ConcurrentMarkSweepGeneration::promotion_failure_occurred() {
if (CMSDumpAtPromotionFailure) {
cmsSpace()->dump_at_safepoint_with_locks(collector(), gclog_or_tty);
}
}
CompactibleSpace* CompactibleSpace*
ConcurrentMarkSweepGeneration::first_compaction_space() const { ConcurrentMarkSweepGeneration::first_compaction_space() const {
return _cmsSpace; return _cmsSpace;
...@@ -1368,12 +1390,7 @@ void ...@@ -1368,12 +1390,7 @@ void
ConcurrentMarkSweepGeneration:: ConcurrentMarkSweepGeneration::
par_promote_alloc_done(int thread_num) { par_promote_alloc_done(int thread_num) {
CMSParGCThreadState* ps = _par_gc_thread_states[thread_num]; CMSParGCThreadState* ps = _par_gc_thread_states[thread_num];
ps->lab.retire(); ps->lab.retire(thread_num);
#if CFLS_LAB_REFILL_STATS
if (thread_num == 0) {
_cmsSpace->print_par_alloc_stats();
}
#endif
} }
void void
...@@ -1974,11 +1991,14 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) { ...@@ -1974,11 +1991,14 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) {
// We must adjust the allocation statistics being maintained // We must adjust the allocation statistics being maintained
// in the free list space. We do so by reading and clearing // in the free list space. We do so by reading and clearing
// the sweep timer and updating the block flux rate estimates below. // the sweep timer and updating the block flux rate estimates below.
assert(_sweep_timer.is_active(), "We should never see the timer inactive"); assert(!_intra_sweep_timer.is_active(), "_intra_sweep_timer should be inactive");
_sweep_timer.stop(); if (_inter_sweep_timer.is_active()) {
// Note that we do not use this sample to update the _sweep_estimate. _inter_sweep_timer.stop();
_cmsGen->cmsSpace()->beginSweepFLCensus((float)(_sweep_timer.seconds()), // Note that we do not use this sample to update the _inter_sweep_estimate.
_sweep_estimate.padded_average()); _cmsGen->cmsSpace()->beginSweepFLCensus((float)(_inter_sweep_timer.seconds()),
_inter_sweep_estimate.padded_average(),
_intra_sweep_estimate.padded_average());
}
GenMarkSweep::invoke_at_safepoint(_cmsGen->level(), GenMarkSweep::invoke_at_safepoint(_cmsGen->level(),
ref_processor(), clear_all_soft_refs); ref_processor(), clear_all_soft_refs);
...@@ -2015,10 +2035,10 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) { ...@@ -2015,10 +2035,10 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) {
} }
// Adjust the per-size allocation stats for the next epoch. // Adjust the per-size allocation stats for the next epoch.
_cmsGen->cmsSpace()->endSweepFLCensus(sweepCount() /* fake */); _cmsGen->cmsSpace()->endSweepFLCensus(sweep_count() /* fake */);
// Restart the "sweep timer" for next epoch. // Restart the "inter sweep timer" for the next epoch.
_sweep_timer.reset(); _inter_sweep_timer.reset();
_sweep_timer.start(); _inter_sweep_timer.start();
// Sample collection pause time and reset for collection interval. // Sample collection pause time and reset for collection interval.
if (UseAdaptiveSizePolicy) { if (UseAdaptiveSizePolicy) {
...@@ -2676,7 +2696,7 @@ void ConcurrentMarkSweepGeneration::gc_epilogue(bool full) { ...@@ -2676,7 +2696,7 @@ void ConcurrentMarkSweepGeneration::gc_epilogue(bool full) {
// Also reset promotion tracking in par gc thread states. // Also reset promotion tracking in par gc thread states.
if (ParallelGCThreads > 0) { if (ParallelGCThreads > 0) {
for (uint i = 0; i < ParallelGCThreads; i++) { for (uint i = 0; i < ParallelGCThreads; i++) {
_par_gc_thread_states[i]->promo.stopTrackingPromotions(); _par_gc_thread_states[i]->promo.stopTrackingPromotions(i);
} }
} }
} }
...@@ -2771,7 +2791,7 @@ class VerifyMarkedClosure: public BitMapClosure { ...@@ -2771,7 +2791,7 @@ class VerifyMarkedClosure: public BitMapClosure {
bool do_bit(size_t offset) { bool do_bit(size_t offset) {
HeapWord* addr = _marks->offsetToHeapWord(offset); HeapWord* addr = _marks->offsetToHeapWord(offset);
if (!_marks->isMarked(addr)) { if (!_marks->isMarked(addr)) {
oop(addr)->print(); oop(addr)->print_on(gclog_or_tty);
gclog_or_tty->print_cr(" ("INTPTR_FORMAT" should have been marked)", addr); gclog_or_tty->print_cr(" ("INTPTR_FORMAT" should have been marked)", addr);
_failed = true; _failed = true;
} }
...@@ -2820,7 +2840,7 @@ bool CMSCollector::verify_after_remark() { ...@@ -2820,7 +2840,7 @@ bool CMSCollector::verify_after_remark() {
// Clear any marks from a previous round // Clear any marks from a previous round
verification_mark_bm()->clear_all(); verification_mark_bm()->clear_all();
assert(verification_mark_stack()->isEmpty(), "markStack should be empty"); assert(verification_mark_stack()->isEmpty(), "markStack should be empty");
assert(overflow_list_is_empty(), "overflow list should be empty"); verify_work_stacks_empty();
GenCollectedHeap* gch = GenCollectedHeap::heap(); GenCollectedHeap* gch = GenCollectedHeap::heap();
gch->ensure_parsability(false); // fill TLABs, but no need to retire them gch->ensure_parsability(false); // fill TLABs, but no need to retire them
...@@ -2893,8 +2913,8 @@ void CMSCollector::verify_after_remark_work_1() { ...@@ -2893,8 +2913,8 @@ void CMSCollector::verify_after_remark_work_1() {
verification_mark_bm()->iterate(&vcl); verification_mark_bm()->iterate(&vcl);
if (vcl.failed()) { if (vcl.failed()) {
gclog_or_tty->print("Verification failed"); gclog_or_tty->print("Verification failed");
Universe::heap()->print(); Universe::heap()->print_on(gclog_or_tty);
fatal(" ... aborting"); fatal("CMS: failed marking verification after remark");
} }
} }
...@@ -3314,7 +3334,7 @@ bool ConcurrentMarkSweepGeneration::grow_by(size_t bytes) { ...@@ -3314,7 +3334,7 @@ bool ConcurrentMarkSweepGeneration::grow_by(size_t bytes) {
Universe::heap()->barrier_set()->resize_covered_region(mr); Universe::heap()->barrier_set()->resize_covered_region(mr);
// Hmmmm... why doesn't CFLS::set_end verify locking? // Hmmmm... why doesn't CFLS::set_end verify locking?
// This is quite ugly; FIX ME XXX // This is quite ugly; FIX ME XXX
_cmsSpace->assert_locked(); _cmsSpace->assert_locked(freelistLock());
_cmsSpace->set_end((HeapWord*)_virtual_space.high()); _cmsSpace->set_end((HeapWord*)_virtual_space.high());
// update the space and generation capacity counters // update the space and generation capacity counters
...@@ -5868,9 +5888,9 @@ void CMSCollector::sweep(bool asynch) { ...@@ -5868,9 +5888,9 @@ void CMSCollector::sweep(bool asynch) {
check_correct_thread_executing(); check_correct_thread_executing();
verify_work_stacks_empty(); verify_work_stacks_empty();
verify_overflow_empty(); verify_overflow_empty();
incrementSweepCount(); increment_sweep_count();
_sweep_timer.stop(); _inter_sweep_timer.stop();
_sweep_estimate.sample(_sweep_timer.seconds()); _inter_sweep_estimate.sample(_inter_sweep_timer.seconds());
size_policy()->avg_cms_free_at_sweep()->sample(_cmsGen->free()); size_policy()->avg_cms_free_at_sweep()->sample(_cmsGen->free());
// PermGen verification support: If perm gen sweeping is disabled in // PermGen verification support: If perm gen sweeping is disabled in
...@@ -5893,6 +5913,9 @@ void CMSCollector::sweep(bool asynch) { ...@@ -5893,6 +5913,9 @@ void CMSCollector::sweep(bool asynch) {
} }
} }
assert(!_intra_sweep_timer.is_active(), "Should not be active");
_intra_sweep_timer.reset();
_intra_sweep_timer.start();
if (asynch) { if (asynch) {
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
CMSPhaseAccounting pa(this, "sweep", !PrintGCDetails); CMSPhaseAccounting pa(this, "sweep", !PrintGCDetails);
...@@ -5937,8 +5960,11 @@ void CMSCollector::sweep(bool asynch) { ...@@ -5937,8 +5960,11 @@ void CMSCollector::sweep(bool asynch) {
verify_work_stacks_empty(); verify_work_stacks_empty();
verify_overflow_empty(); verify_overflow_empty();
_sweep_timer.reset(); _intra_sweep_timer.stop();
_sweep_timer.start(); _intra_sweep_estimate.sample(_intra_sweep_timer.seconds());
_inter_sweep_timer.reset();
_inter_sweep_timer.start();
update_time_of_last_gc(os::javaTimeMillis()); update_time_of_last_gc(os::javaTimeMillis());
...@@ -5981,11 +6007,11 @@ void CMSCollector::sweep(bool asynch) { ...@@ -5981,11 +6007,11 @@ void CMSCollector::sweep(bool asynch) {
// FIX ME!!! Looks like this belongs in CFLSpace, with // FIX ME!!! Looks like this belongs in CFLSpace, with
// CMSGen merely delegating to it. // CMSGen merely delegating to it.
void ConcurrentMarkSweepGeneration::setNearLargestChunk() { void ConcurrentMarkSweepGeneration::setNearLargestChunk() {
double nearLargestPercent = 0.999; double nearLargestPercent = FLSLargestBlockCoalesceProximity;
HeapWord* minAddr = _cmsSpace->bottom(); HeapWord* minAddr = _cmsSpace->bottom();
HeapWord* largestAddr = HeapWord* largestAddr =
(HeapWord*) _cmsSpace->dictionary()->findLargestDict(); (HeapWord*) _cmsSpace->dictionary()->findLargestDict();
if (largestAddr == 0) { if (largestAddr == NULL) {
// The dictionary appears to be empty. In this case // The dictionary appears to be empty. In this case
// try to coalesce at the end of the heap. // try to coalesce at the end of the heap.
largestAddr = _cmsSpace->end(); largestAddr = _cmsSpace->end();
...@@ -5993,6 +6019,13 @@ void ConcurrentMarkSweepGeneration::setNearLargestChunk() { ...@@ -5993,6 +6019,13 @@ void ConcurrentMarkSweepGeneration::setNearLargestChunk() {
size_t largestOffset = pointer_delta(largestAddr, minAddr); size_t largestOffset = pointer_delta(largestAddr, minAddr);
size_t nearLargestOffset = size_t nearLargestOffset =
(size_t)((double)largestOffset * nearLargestPercent) - MinChunkSize; (size_t)((double)largestOffset * nearLargestPercent) - MinChunkSize;
if (PrintFLSStatistics != 0) {
gclog_or_tty->print_cr(
"CMS: Large Block: " PTR_FORMAT ";"
" Proximity: " PTR_FORMAT " -> " PTR_FORMAT,
largestAddr,
_cmsSpace->nearLargestChunk(), minAddr + nearLargestOffset);
}
_cmsSpace->set_nearLargestChunk(minAddr + nearLargestOffset); _cmsSpace->set_nearLargestChunk(minAddr + nearLargestOffset);
} }
...@@ -6072,9 +6105,11 @@ void CMSCollector::sweepWork(ConcurrentMarkSweepGeneration* gen, ...@@ -6072,9 +6105,11 @@ void CMSCollector::sweepWork(ConcurrentMarkSweepGeneration* gen,
assert_lock_strong(gen->freelistLock()); assert_lock_strong(gen->freelistLock());
assert_lock_strong(bitMapLock()); assert_lock_strong(bitMapLock());
assert(!_sweep_timer.is_active(), "Was switched off in an outer context"); assert(!_inter_sweep_timer.is_active(), "Was switched off in an outer context");
gen->cmsSpace()->beginSweepFLCensus((float)(_sweep_timer.seconds()), assert(_intra_sweep_timer.is_active(), "Was switched on in an outer context");
_sweep_estimate.padded_average()); gen->cmsSpace()->beginSweepFLCensus((float)(_inter_sweep_timer.seconds()),
_inter_sweep_estimate.padded_average(),
_intra_sweep_estimate.padded_average());
gen->setNearLargestChunk(); gen->setNearLargestChunk();
{ {
...@@ -6087,7 +6122,7 @@ void CMSCollector::sweepWork(ConcurrentMarkSweepGeneration* gen, ...@@ -6087,7 +6122,7 @@ void CMSCollector::sweepWork(ConcurrentMarkSweepGeneration* gen,
// end-of-sweep-census below will be off by a little bit. // end-of-sweep-census below will be off by a little bit.
} }
gen->cmsSpace()->sweep_completed(); gen->cmsSpace()->sweep_completed();
gen->cmsSpace()->endSweepFLCensus(sweepCount()); gen->cmsSpace()->endSweepFLCensus(sweep_count());
if (should_unload_classes()) { // unloaded classes this cycle, if (should_unload_classes()) { // unloaded classes this cycle,
_concurrent_cycles_since_last_unload = 0; // ... reset count _concurrent_cycles_since_last_unload = 0; // ... reset count
} else { // did not unload classes, } else { // did not unload classes,
......
...@@ -355,6 +355,11 @@ class CMSStats VALUE_OBJ_CLASS_SPEC { ...@@ -355,6 +355,11 @@ class CMSStats VALUE_OBJ_CLASS_SPEC {
unsigned int new_duty_cycle); unsigned int new_duty_cycle);
unsigned int icms_update_duty_cycle_impl(); unsigned int icms_update_duty_cycle_impl();
// In support of adjusting of cms trigger ratios based on history
// of concurrent mode failure.
double cms_free_adjustment_factor(size_t free) const;
void adjust_cms_free_adjustment_factor(bool fail, size_t free);
public: public:
CMSStats(ConcurrentMarkSweepGeneration* cms_gen, CMSStats(ConcurrentMarkSweepGeneration* cms_gen,
unsigned int alpha = CMSExpAvgFactor); unsigned int alpha = CMSExpAvgFactor);
...@@ -570,8 +575,11 @@ class CMSCollector: public CHeapObj { ...@@ -570,8 +575,11 @@ class CMSCollector: public CHeapObj {
// appropriately. // appropriately.
void check_gc_time_limit(); void check_gc_time_limit();
// XXX Move these to CMSStats ??? FIX ME !!! // XXX Move these to CMSStats ??? FIX ME !!!
elapsedTimer _sweep_timer; elapsedTimer _inter_sweep_timer; // time between sweeps
AdaptivePaddedAverage _sweep_estimate; elapsedTimer _intra_sweep_timer; // time _in_ sweeps
// padded decaying average estimates of the above
AdaptivePaddedAverage _inter_sweep_estimate;
AdaptivePaddedAverage _intra_sweep_estimate;
protected: protected:
ConcurrentMarkSweepGeneration* _cmsGen; // old gen (CMS) ConcurrentMarkSweepGeneration* _cmsGen; // old gen (CMS)
...@@ -625,6 +633,7 @@ class CMSCollector: public CHeapObj { ...@@ -625,6 +633,7 @@ class CMSCollector: public CHeapObj {
// . _collectorState <= Idling == post-sweep && pre-mark // . _collectorState <= Idling == post-sweep && pre-mark
// . _collectorState in (Idling, Sweeping) == {initial,final}marking || // . _collectorState in (Idling, Sweeping) == {initial,final}marking ||
// precleaning || abortablePrecleanb // precleaning || abortablePrecleanb
public:
enum CollectorState { enum CollectorState {
Resizing = 0, Resizing = 0,
Resetting = 1, Resetting = 1,
...@@ -636,6 +645,7 @@ class CMSCollector: public CHeapObj { ...@@ -636,6 +645,7 @@ class CMSCollector: public CHeapObj {
FinalMarking = 7, FinalMarking = 7,
Sweeping = 8 Sweeping = 8
}; };
protected:
static CollectorState _collectorState; static CollectorState _collectorState;
// State related to prologue/epilogue invocation for my generations // State related to prologue/epilogue invocation for my generations
...@@ -655,7 +665,7 @@ class CMSCollector: public CHeapObj { ...@@ -655,7 +665,7 @@ class CMSCollector: public CHeapObj {
int _numYields; int _numYields;
size_t _numDirtyCards; size_t _numDirtyCards;
uint _sweepCount; size_t _sweep_count;
// number of full gc's since the last concurrent gc. // number of full gc's since the last concurrent gc.
uint _full_gcs_since_conc_gc; uint _full_gcs_since_conc_gc;
...@@ -905,7 +915,7 @@ class CMSCollector: public CHeapObj { ...@@ -905,7 +915,7 @@ class CMSCollector: public CHeapObj {
// Check that the currently executing thread is the expected // Check that the currently executing thread is the expected
// one (foreground collector or background collector). // one (foreground collector or background collector).
void check_correct_thread_executing() PRODUCT_RETURN; static void check_correct_thread_executing() PRODUCT_RETURN;
// XXXPERM void print_statistics() PRODUCT_RETURN; // XXXPERM void print_statistics() PRODUCT_RETURN;
bool is_cms_reachable(HeapWord* addr); bool is_cms_reachable(HeapWord* addr);
...@@ -930,8 +940,8 @@ class CMSCollector: public CHeapObj { ...@@ -930,8 +940,8 @@ class CMSCollector: public CHeapObj {
static void set_foregroundGCShouldWait(bool v) { _foregroundGCShouldWait = v; } static void set_foregroundGCShouldWait(bool v) { _foregroundGCShouldWait = v; }
static bool foregroundGCIsActive() { return _foregroundGCIsActive; } static bool foregroundGCIsActive() { return _foregroundGCIsActive; }
static void set_foregroundGCIsActive(bool v) { _foregroundGCIsActive = v; } static void set_foregroundGCIsActive(bool v) { _foregroundGCIsActive = v; }
uint sweepCount() const { return _sweepCount; } size_t sweep_count() const { return _sweep_count; }
void incrementSweepCount() { _sweepCount++; } void increment_sweep_count() { _sweep_count++; }
// Timers/stats for gc scheduling and incremental mode pacing. // Timers/stats for gc scheduling and incremental mode pacing.
CMSStats& stats() { return _stats; } CMSStats& stats() { return _stats; }
...@@ -1165,6 +1175,11 @@ class ConcurrentMarkSweepGeneration: public CardGeneration { ...@@ -1165,6 +1175,11 @@ class ConcurrentMarkSweepGeneration: public CardGeneration {
virtual bool promotion_attempt_is_safe(size_t promotion_in_bytes, virtual bool promotion_attempt_is_safe(size_t promotion_in_bytes,
bool younger_handles_promotion_failure) const; bool younger_handles_promotion_failure) const;
// Inform this (non-young) generation that a promotion failure was
// encountered during a collection of a younger generation that
// promotes into this generation.
virtual void promotion_failure_occurred();
bool should_collect(bool full, size_t size, bool tlab); bool should_collect(bool full, size_t size, bool tlab);
virtual bool should_concurrent_collect() const; virtual bool should_concurrent_collect() const;
virtual bool is_too_full() const; virtual bool is_too_full() const;
......
...@@ -55,7 +55,8 @@ class FreeBlockDictionary: public CHeapObj { ...@@ -55,7 +55,8 @@ class FreeBlockDictionary: public CHeapObj {
virtual void dictCensusUpdate(size_t size, bool split, bool birth) = 0; virtual void dictCensusUpdate(size_t size, bool split, bool birth) = 0;
virtual bool coalDictOverPopulated(size_t size) = 0; virtual bool coalDictOverPopulated(size_t size) = 0;
virtual void beginSweepDictCensus(double coalSurplusPercent, virtual void beginSweepDictCensus(double coalSurplusPercent,
float sweep_current, float sweep_ewstimate) = 0; float inter_sweep_current, float inter_sweep_estimate,
float intra__sweep_current) = 0;
virtual void endSweepDictCensus(double splitSurplusPercent) = 0; virtual void endSweepDictCensus(double splitSurplusPercent) = 0;
virtual FreeChunk* findLargestDict() const = 0; virtual FreeChunk* findLargestDict() const = 0;
// verify that the given chunk is in the dictionary. // verify that the given chunk is in the dictionary.
...@@ -79,6 +80,7 @@ class FreeBlockDictionary: public CHeapObj { ...@@ -79,6 +80,7 @@ class FreeBlockDictionary: public CHeapObj {
} }
virtual void printDictCensus() const = 0; virtual void printDictCensus() const = 0;
virtual void print_free_lists(outputStream* st) const = 0;
virtual void verify() const = 0; virtual void verify() const = 0;
......
...@@ -67,3 +67,8 @@ void FreeChunk::verifyList() const { ...@@ -67,3 +67,8 @@ void FreeChunk::verifyList() const {
} }
} }
#endif #endif
void FreeChunk::print_on(outputStream* st) {
st->print_cr("Next: " PTR_FORMAT " Prev: " PTR_FORMAT " %s",
next(), prev(), cantCoalesce() ? "[can't coalesce]" : "");
}
...@@ -129,6 +129,8 @@ class FreeChunk VALUE_OBJ_CLASS_SPEC { ...@@ -129,6 +129,8 @@ class FreeChunk VALUE_OBJ_CLASS_SPEC {
void verifyList() const PRODUCT_RETURN; void verifyList() const PRODUCT_RETURN;
void mangleAllocated(size_t size) PRODUCT_RETURN; void mangleAllocated(size_t size) PRODUCT_RETURN;
void mangleFreed(size_t size) PRODUCT_RETURN; void mangleFreed(size_t size) PRODUCT_RETURN;
void print_on(outputStream* st);
}; };
// Alignment helpers etc. // Alignment helpers etc.
......
...@@ -81,8 +81,8 @@ void FreeList::reset(size_t hint) { ...@@ -81,8 +81,8 @@ void FreeList::reset(size_t hint) {
set_hint(hint); set_hint(hint);
} }
void FreeList::init_statistics() { void FreeList::init_statistics(bool split_birth) {
_allocation_stats.initialize(); _allocation_stats.initialize(split_birth);
} }
FreeChunk* FreeList::getChunkAtHead() { FreeChunk* FreeList::getChunkAtHead() {
...@@ -292,14 +292,31 @@ bool FreeList::verifyChunkInFreeLists(FreeChunk* fc) const { ...@@ -292,14 +292,31 @@ bool FreeList::verifyChunkInFreeLists(FreeChunk* fc) const {
} }
#ifndef PRODUCT #ifndef PRODUCT
void FreeList::verify_stats() const {
// The +1 of the LH comparand is to allow some "looseness" in
// checking: we usually call this interface when adding a block
// and we'll subsequently update the stats; we cannot update the
// stats beforehand because in the case of the large-block BT
// dictionary for example, this might be the first block and
// in that case there would be no place that we could record
// the stats (which are kept in the block itself).
assert(_allocation_stats.prevSweep() + _allocation_stats.splitBirths() + 1 // Total Stock + 1
>= _allocation_stats.splitDeaths() + (ssize_t)count(), "Conservation Principle");
}
void FreeList::assert_proper_lock_protection_work() const { void FreeList::assert_proper_lock_protection_work() const {
#ifdef ASSERT assert(_protecting_lock != NULL, "Don't call this directly");
if (_protecting_lock != NULL && assert(ParallelGCThreads > 0, "Don't call this directly");
SharedHeap::heap()->n_par_threads() > 0) { Thread* thr = Thread::current();
// Should become an assert. if (thr->is_VM_thread() || thr->is_ConcurrentGC_thread()) {
guarantee(_protecting_lock->owned_by_self(), "FreeList RACE DETECTED"); // assert that we are holding the freelist lock
} else if (thr->is_GC_task_thread()) {
assert(_protecting_lock->owned_by_self(), "FreeList RACE DETECTED");
} else if (thr->is_Java_thread()) {
assert(!SafepointSynchronize::is_at_safepoint(), "Should not be executing");
} else {
ShouldNotReachHere(); // unaccounted thread type?
} }
#endif
} }
#endif #endif
......
...@@ -35,18 +35,26 @@ class CompactibleFreeListSpace; ...@@ -35,18 +35,26 @@ class CompactibleFreeListSpace;
// for that implementation. // for that implementation.
class Mutex; class Mutex;
class TreeList;
class FreeList VALUE_OBJ_CLASS_SPEC { class FreeList VALUE_OBJ_CLASS_SPEC {
friend class CompactibleFreeListSpace; friend class CompactibleFreeListSpace;
friend class VMStructs; friend class VMStructs;
friend class printTreeCensusClosure; friend class PrintTreeCensusClosure;
FreeChunk* _head; // List of free chunks
protected:
TreeList* _parent;
TreeList* _left;
TreeList* _right;
private:
FreeChunk* _head; // Head of list of free chunks
FreeChunk* _tail; // Tail of list of free chunks FreeChunk* _tail; // Tail of list of free chunks
size_t _size; // Size in Heap words of each chunks size_t _size; // Size in Heap words of each chunk
ssize_t _count; // Number of entries in list ssize_t _count; // Number of entries in list
size_t _hint; // next larger size list with a positive surplus size_t _hint; // next larger size list with a positive surplus
AllocationStats _allocation_stats; // statistics for smart allocation AllocationStats _allocation_stats; // allocation-related statistics
#ifdef ASSERT #ifdef ASSERT
Mutex* _protecting_lock; Mutex* _protecting_lock;
...@@ -63,9 +71,12 @@ class FreeList VALUE_OBJ_CLASS_SPEC { ...@@ -63,9 +71,12 @@ class FreeList VALUE_OBJ_CLASS_SPEC {
// Initialize the allocation statistics. // Initialize the allocation statistics.
protected: protected:
void init_statistics(); void init_statistics(bool split_birth = false);
void set_count(ssize_t v) { _count = v;} void set_count(ssize_t v) { _count = v;}
void increment_count() { _count++; } void increment_count() {
_count++;
}
void decrement_count() { void decrement_count() {
_count--; _count--;
assert(_count >= 0, "Count should not be negative"); assert(_count >= 0, "Count should not be negative");
...@@ -167,11 +178,13 @@ class FreeList VALUE_OBJ_CLASS_SPEC { ...@@ -167,11 +178,13 @@ class FreeList VALUE_OBJ_CLASS_SPEC {
_allocation_stats.set_desired(v); _allocation_stats.set_desired(v);
} }
void compute_desired(float inter_sweep_current, void compute_desired(float inter_sweep_current,
float inter_sweep_estimate) { float inter_sweep_estimate,
float intra_sweep_estimate) {
assert_proper_lock_protection(); assert_proper_lock_protection();
_allocation_stats.compute_desired(_count, _allocation_stats.compute_desired(_count,
inter_sweep_current, inter_sweep_current,
inter_sweep_estimate); inter_sweep_estimate,
intra_sweep_estimate);
} }
ssize_t coalDesired() const { ssize_t coalDesired() const {
return _allocation_stats.coalDesired(); return _allocation_stats.coalDesired();
...@@ -306,6 +319,9 @@ class FreeList VALUE_OBJ_CLASS_SPEC { ...@@ -306,6 +319,9 @@ class FreeList VALUE_OBJ_CLASS_SPEC {
// found. Return NULL if "fc" is not found. // found. Return NULL if "fc" is not found.
bool verifyChunkInFreeLists(FreeChunk* fc) const; bool verifyChunkInFreeLists(FreeChunk* fc) const;
// Stats verification
void verify_stats() const PRODUCT_RETURN;
// Printing support // Printing support
static void print_labels_on(outputStream* st, const char* c); static void print_labels_on(outputStream* st, const char* c);
void print_on(outputStream* st, const char* c = NULL) const; void print_on(outputStream* st, const char* c = NULL) const;
......
...@@ -221,6 +221,7 @@ freeList.cpp freeList.hpp ...@@ -221,6 +221,7 @@ freeList.cpp freeList.hpp
freeList.cpp globals.hpp freeList.cpp globals.hpp
freeList.cpp mutex.hpp freeList.cpp mutex.hpp
freeList.cpp sharedHeap.hpp freeList.cpp sharedHeap.hpp
freeList.cpp vmThread.hpp
freeList.hpp allocationStats.hpp freeList.hpp allocationStats.hpp
......
...@@ -71,6 +71,7 @@ gcUtil.cpp gcUtil.hpp ...@@ -71,6 +71,7 @@ gcUtil.cpp gcUtil.hpp
gcUtil.hpp allocation.hpp gcUtil.hpp allocation.hpp
gcUtil.hpp debug.hpp gcUtil.hpp debug.hpp
gcUtil.hpp globalDefinitions.hpp gcUtil.hpp globalDefinitions.hpp
gcUtil.hpp ostream.hpp
gcUtil.hpp timer.hpp gcUtil.hpp timer.hpp
generationCounters.cpp generationCounters.hpp generationCounters.cpp generationCounters.hpp
......
...@@ -50,6 +50,7 @@ ParScanThreadState::ParScanThreadState(Space* to_space_, ...@@ -50,6 +50,7 @@ ParScanThreadState::ParScanThreadState(Space* to_space_,
work_queue_set_, &term_), work_queue_set_, &term_),
_is_alive_closure(gen_), _scan_weak_ref_closure(gen_, this), _is_alive_closure(gen_), _scan_weak_ref_closure(gen_, this),
_keep_alive_closure(&_scan_weak_ref_closure), _keep_alive_closure(&_scan_weak_ref_closure),
_promotion_failure_size(0),
_pushes(0), _pops(0), _steals(0), _steal_attempts(0), _term_attempts(0), _pushes(0), _pops(0), _steals(0), _steal_attempts(0), _term_attempts(0),
_strong_roots_time(0.0), _term_time(0.0) _strong_roots_time(0.0), _term_time(0.0)
{ {
...@@ -249,6 +250,16 @@ void ParScanThreadState::undo_alloc_in_to_space(HeapWord* obj, ...@@ -249,6 +250,16 @@ void ParScanThreadState::undo_alloc_in_to_space(HeapWord* obj,
} }
} }
void ParScanThreadState::print_and_clear_promotion_failure_size() {
if (_promotion_failure_size != 0) {
if (PrintPromotionFailure) {
gclog_or_tty->print(" (%d: promotion failure size = " SIZE_FORMAT ") ",
_thread_num, _promotion_failure_size);
}
_promotion_failure_size = 0;
}
}
class ParScanThreadStateSet: private ResourceArray { class ParScanThreadStateSet: private ResourceArray {
public: public:
// Initializes states for the specified number of threads; // Initializes states for the specified number of threads;
...@@ -260,11 +271,11 @@ public: ...@@ -260,11 +271,11 @@ public:
GrowableArray<oop>** overflow_stacks_, GrowableArray<oop>** overflow_stacks_,
size_t desired_plab_sz, size_t desired_plab_sz,
ParallelTaskTerminator& term); ParallelTaskTerminator& term);
inline ParScanThreadState& thread_sate(int i); inline ParScanThreadState& thread_state(int i);
int pushes() { return _pushes; } int pushes() { return _pushes; }
int pops() { return _pops; } int pops() { return _pops; }
int steals() { return _steals; } int steals() { return _steals; }
void reset(); void reset(bool promotion_failed);
void flush(); void flush();
private: private:
ParallelTaskTerminator& _term; ParallelTaskTerminator& _term;
...@@ -295,22 +306,31 @@ ParScanThreadStateSet::ParScanThreadStateSet( ...@@ -295,22 +306,31 @@ ParScanThreadStateSet::ParScanThreadStateSet(
} }
} }
inline ParScanThreadState& ParScanThreadStateSet::thread_sate(int i) inline ParScanThreadState& ParScanThreadStateSet::thread_state(int i)
{ {
assert(i >= 0 && i < length(), "sanity check!"); assert(i >= 0 && i < length(), "sanity check!");
return ((ParScanThreadState*)_data)[i]; return ((ParScanThreadState*)_data)[i];
} }
void ParScanThreadStateSet::reset() void ParScanThreadStateSet::reset(bool promotion_failed)
{ {
_term.reset_for_reuse(); _term.reset_for_reuse();
if (promotion_failed) {
for (int i = 0; i < length(); ++i) {
thread_state(i).print_and_clear_promotion_failure_size();
}
}
} }
void ParScanThreadStateSet::flush() void ParScanThreadStateSet::flush()
{ {
// Work in this loop should be kept as lightweight as
// possible since this might otherwise become a bottleneck
// to scaling. Should we add heavy-weight work into this
// loop, consider parallelizing the loop into the worker threads.
for (int i = 0; i < length(); ++i) { for (int i = 0; i < length(); ++i) {
ParScanThreadState& par_scan_state = thread_sate(i); ParScanThreadState& par_scan_state = thread_state(i);
// Flush stats related to To-space PLAB activity and // Flush stats related to To-space PLAB activity and
// retire the last buffer. // retire the last buffer.
...@@ -362,6 +382,14 @@ void ParScanThreadStateSet::flush() ...@@ -362,6 +382,14 @@ void ParScanThreadStateSet::flush()
} }
} }
} }
if (UseConcMarkSweepGC && ParallelGCThreads > 0) {
// We need to call this even when ResizeOldPLAB is disabled
// so as to avoid breaking some asserts. While we may be able
// to avoid this by reorganizing the code a bit, I am loathe
// to do that unless we find cases where ergo leads to bad
// performance.
CFLS_LAB::compute_desired_plab_size();
}
} }
ParScanClosure::ParScanClosure(ParNewGeneration* g, ParScanClosure::ParScanClosure(ParNewGeneration* g,
...@@ -475,7 +503,7 @@ void ParNewGenTask::work(int i) { ...@@ -475,7 +503,7 @@ void ParNewGenTask::work(int i) {
Generation* old_gen = gch->next_gen(_gen); Generation* old_gen = gch->next_gen(_gen);
ParScanThreadState& par_scan_state = _state_set->thread_sate(i); ParScanThreadState& par_scan_state = _state_set->thread_state(i);
par_scan_state.set_young_old_boundary(_young_old_boundary); par_scan_state.set_young_old_boundary(_young_old_boundary);
par_scan_state.start_strong_roots(); par_scan_state.start_strong_roots();
...@@ -659,7 +687,7 @@ void ParNewRefProcTaskProxy::work(int i) ...@@ -659,7 +687,7 @@ void ParNewRefProcTaskProxy::work(int i)
{ {
ResourceMark rm; ResourceMark rm;
HandleMark hm; HandleMark hm;
ParScanThreadState& par_scan_state = _state_set.thread_sate(i); ParScanThreadState& par_scan_state = _state_set.thread_state(i);
par_scan_state.set_young_old_boundary(_young_old_boundary); par_scan_state.set_young_old_boundary(_young_old_boundary);
_task.work(i, par_scan_state.is_alive_closure(), _task.work(i, par_scan_state.is_alive_closure(),
par_scan_state.keep_alive_closure(), par_scan_state.keep_alive_closure(),
...@@ -693,7 +721,7 @@ void ParNewRefProcTaskExecutor::execute(ProcessTask& task) ...@@ -693,7 +721,7 @@ void ParNewRefProcTaskExecutor::execute(ProcessTask& task)
ParNewRefProcTaskProxy rp_task(task, _generation, *_generation.next_gen(), ParNewRefProcTaskProxy rp_task(task, _generation, *_generation.next_gen(),
_generation.reserved().end(), _state_set); _generation.reserved().end(), _state_set);
workers->run_task(&rp_task); workers->run_task(&rp_task);
_state_set.reset(); _state_set.reset(_generation.promotion_failed());
} }
void ParNewRefProcTaskExecutor::execute(EnqueueTask& task) void ParNewRefProcTaskExecutor::execute(EnqueueTask& task)
...@@ -813,7 +841,7 @@ void ParNewGeneration::collect(bool full, ...@@ -813,7 +841,7 @@ void ParNewGeneration::collect(bool full,
GenCollectedHeap::StrongRootsScope srs(gch); GenCollectedHeap::StrongRootsScope srs(gch);
tsk.work(0); tsk.work(0);
} }
thread_state_set.reset(); thread_state_set.reset(promotion_failed());
if (PAR_STATS_ENABLED && ParallelGCVerbose) { if (PAR_STATS_ENABLED && ParallelGCVerbose) {
gclog_or_tty->print("Thread totals:\n" gclog_or_tty->print("Thread totals:\n"
...@@ -882,6 +910,8 @@ void ParNewGeneration::collect(bool full, ...@@ -882,6 +910,8 @@ void ParNewGeneration::collect(bool full,
swap_spaces(); // Make life simpler for CMS || rescan; see 6483690. swap_spaces(); // Make life simpler for CMS || rescan; see 6483690.
from()->set_next_compaction_space(to()); from()->set_next_compaction_space(to());
gch->set_incremental_collection_will_fail(); gch->set_incremental_collection_will_fail();
// Inform the next generation that a promotion failure occurred.
_next_gen->promotion_failure_occurred();
// Reset the PromotionFailureALot counters. // Reset the PromotionFailureALot counters.
NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();) NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();)
...@@ -1029,6 +1059,8 @@ oop ParNewGeneration::copy_to_survivor_space_avoiding_promotion_undo( ...@@ -1029,6 +1059,8 @@ oop ParNewGeneration::copy_to_survivor_space_avoiding_promotion_undo(
new_obj = old; new_obj = old;
preserve_mark_if_necessary(old, m); preserve_mark_if_necessary(old, m);
// Log the size of the maiden promotion failure
par_scan_state->log_promotion_failure(sz);
} }
old->forward_to(new_obj); old->forward_to(new_obj);
...@@ -1150,6 +1182,8 @@ oop ParNewGeneration::copy_to_survivor_space_with_undo( ...@@ -1150,6 +1182,8 @@ oop ParNewGeneration::copy_to_survivor_space_with_undo(
failed_to_promote = true; failed_to_promote = true;
preserve_mark_if_necessary(old, m); preserve_mark_if_necessary(old, m);
// Log the size of the maiden promotion failure
par_scan_state->log_promotion_failure(sz);
} }
} else { } else {
// Is in to-space; do copying ourselves. // Is in to-space; do copying ourselves.
......
...@@ -97,6 +97,9 @@ class ParScanThreadState { ...@@ -97,6 +97,9 @@ class ParScanThreadState {
int _pushes, _pops, _steals, _steal_attempts, _term_attempts; int _pushes, _pops, _steals, _steal_attempts, _term_attempts;
int _overflow_pushes, _overflow_refills, _overflow_refill_objs; int _overflow_pushes, _overflow_refills, _overflow_refill_objs;
// Stats for promotion failure
size_t _promotion_failure_size;
// Timing numbers. // Timing numbers.
double _start; double _start;
double _start_strong_roots; double _start_strong_roots;
...@@ -169,6 +172,15 @@ class ParScanThreadState { ...@@ -169,6 +172,15 @@ class ParScanThreadState {
// Undo the most recent allocation ("obj", of "word_sz"). // Undo the most recent allocation ("obj", of "word_sz").
void undo_alloc_in_to_space(HeapWord* obj, size_t word_sz); void undo_alloc_in_to_space(HeapWord* obj, size_t word_sz);
// Promotion failure stats
size_t promotion_failure_size() { return promotion_failure_size(); }
void log_promotion_failure(size_t sz) {
if (_promotion_failure_size == 0) {
_promotion_failure_size = sz;
}
}
void print_and_clear_promotion_failure_size();
int pushes() { return _pushes; } int pushes() { return _pushes; }
int pops() { return _pops; } int pops() { return _pops; }
int steals() { return _steals; } int steals() { return _steals; }
......
...@@ -31,7 +31,7 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC { ...@@ -31,7 +31,7 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC {
// beginning of this sweep: // beginning of this sweep:
// Count(end_last_sweep) - Count(start_this_sweep) // Count(end_last_sweep) - Count(start_this_sweep)
// + splitBirths(between) - splitDeaths(between) // + splitBirths(between) - splitDeaths(between)
// The above number divided by the time since the start [END???] of the // The above number divided by the time since the end of the
// previous sweep gives us a time rate of demand for blocks // previous sweep gives us a time rate of demand for blocks
// of this size. We compute a padded average of this rate as // of this size. We compute a padded average of this rate as
// our current estimate for the time rate of demand for blocks // our current estimate for the time rate of demand for blocks
...@@ -41,7 +41,7 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC { ...@@ -41,7 +41,7 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC {
// estimates. // estimates.
AdaptivePaddedAverage _demand_rate_estimate; AdaptivePaddedAverage _demand_rate_estimate;
ssize_t _desired; // Estimate computed as described above ssize_t _desired; // Demand stimate computed as described above
ssize_t _coalDesired; // desired +/- small-percent for tuning coalescing ssize_t _coalDesired; // desired +/- small-percent for tuning coalescing
ssize_t _surplus; // count - (desired +/- small-percent), ssize_t _surplus; // count - (desired +/- small-percent),
...@@ -55,7 +55,7 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC { ...@@ -55,7 +55,7 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC {
ssize_t _splitDeaths; // loss from splitting ssize_t _splitDeaths; // loss from splitting
size_t _returnedBytes; // number of bytes returned to list. size_t _returnedBytes; // number of bytes returned to list.
public: public:
void initialize() { void initialize(bool split_birth = false) {
AdaptivePaddedAverage* dummy = AdaptivePaddedAverage* dummy =
new (&_demand_rate_estimate) AdaptivePaddedAverage(CMS_FLSWeight, new (&_demand_rate_estimate) AdaptivePaddedAverage(CMS_FLSWeight,
CMS_FLSPadding); CMS_FLSPadding);
...@@ -67,7 +67,7 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC { ...@@ -67,7 +67,7 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC {
_beforeSweep = 0; _beforeSweep = 0;
_coalBirths = 0; _coalBirths = 0;
_coalDeaths = 0; _coalDeaths = 0;
_splitBirths = 0; _splitBirths = split_birth? 1 : 0;
_splitDeaths = 0; _splitDeaths = 0;
_returnedBytes = 0; _returnedBytes = 0;
} }
...@@ -75,10 +75,12 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC { ...@@ -75,10 +75,12 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC {
AllocationStats() { AllocationStats() {
initialize(); initialize();
} }
// The rate estimate is in blocks per second. // The rate estimate is in blocks per second.
void compute_desired(size_t count, void compute_desired(size_t count,
float inter_sweep_current, float inter_sweep_current,
float inter_sweep_estimate) { float inter_sweep_estimate,
float intra_sweep_estimate) {
// If the latest inter-sweep time is below our granularity // If the latest inter-sweep time is below our granularity
// of measurement, we may call in here with // of measurement, we may call in here with
// inter_sweep_current == 0. However, even for suitably small // inter_sweep_current == 0. However, even for suitably small
...@@ -88,12 +90,31 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC { ...@@ -88,12 +90,31 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC {
// vulnerable to noisy glitches. In such cases, we // vulnerable to noisy glitches. In such cases, we
// ignore the current sample and use currently available // ignore the current sample and use currently available
// historical estimates. // historical estimates.
// XXX NEEDS TO BE FIXED
// assert(prevSweep() + splitBirths() >= splitDeaths() + (ssize_t)count, "Conservation Principle");
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// "Total Stock" "Not used at this block size"
if (inter_sweep_current > _threshold) { if (inter_sweep_current > _threshold) {
ssize_t demand = prevSweep() - count + splitBirths() - splitDeaths(); ssize_t demand = prevSweep() - (ssize_t)count + splitBirths() - splitDeaths();
// XXX NEEDS TO BE FIXED
// assert(demand >= 0, "Demand should be non-negative");
// Defensive: adjust for imprecision in event counting
if (demand < 0) {
demand = 0;
}
float old_rate = _demand_rate_estimate.padded_average();
float rate = ((float)demand)/inter_sweep_current; float rate = ((float)demand)/inter_sweep_current;
_demand_rate_estimate.sample(rate); _demand_rate_estimate.sample(rate);
_desired = (ssize_t)(_demand_rate_estimate.padded_average() float new_rate = _demand_rate_estimate.padded_average();
*inter_sweep_estimate); ssize_t old_desired = _desired;
_desired = (ssize_t)(new_rate * (inter_sweep_estimate
+ CMSExtrapolateSweep
? intra_sweep_estimate
: 0.0));
if (PrintFLSStatistics > 1) {
gclog_or_tty->print_cr("demand: %d, old_rate: %f, current_rate: %f, new_rate: %f, old_desired: %d, new_desired: %d",
demand, old_rate, rate, new_rate, old_desired, _desired);
}
} }
} }
......
...@@ -52,11 +52,35 @@ void AdaptiveWeightedAverage::sample(float new_sample) { ...@@ -52,11 +52,35 @@ void AdaptiveWeightedAverage::sample(float new_sample) {
_last_sample = new_sample; _last_sample = new_sample;
} }
void AdaptiveWeightedAverage::print() const {
print_on(tty);
}
void AdaptiveWeightedAverage::print_on(outputStream* st) const {
guarantee(false, "NYI");
}
void AdaptivePaddedAverage::print() const {
print_on(tty);
}
void AdaptivePaddedAverage::print_on(outputStream* st) const {
guarantee(false, "NYI");
}
void AdaptivePaddedNoZeroDevAverage::print() const {
print_on(tty);
}
void AdaptivePaddedNoZeroDevAverage::print_on(outputStream* st) const {
guarantee(false, "NYI");
}
void AdaptivePaddedAverage::sample(float new_sample) { void AdaptivePaddedAverage::sample(float new_sample) {
// Compute our parent classes sample information // Compute new adaptive weighted average based on new sample.
AdaptiveWeightedAverage::sample(new_sample); AdaptiveWeightedAverage::sample(new_sample);
// Now compute the deviation and the new padded sample // Now update the deviation and the padded average.
float new_avg = average(); float new_avg = average();
float new_dev = compute_adaptive_average(fabsd(new_sample - new_avg), float new_dev = compute_adaptive_average(fabsd(new_sample - new_avg),
deviation()); deviation());
......
...@@ -54,8 +54,8 @@ class AdaptiveWeightedAverage : public CHeapObj { ...@@ -54,8 +54,8 @@ class AdaptiveWeightedAverage : public CHeapObj {
public: public:
// Input weight must be between 0 and 100 // Input weight must be between 0 and 100
AdaptiveWeightedAverage(unsigned weight) : AdaptiveWeightedAverage(unsigned weight, float avg = 0.0) :
_average(0.0), _sample_count(0), _weight(weight), _last_sample(0.0) { _average(avg), _sample_count(0), _weight(weight), _last_sample(0.0) {
} }
void clear() { void clear() {
...@@ -64,6 +64,13 @@ class AdaptiveWeightedAverage : public CHeapObj { ...@@ -64,6 +64,13 @@ class AdaptiveWeightedAverage : public CHeapObj {
_last_sample = 0; _last_sample = 0;
} }
// Useful for modifying static structures after startup.
void modify(size_t avg, unsigned wt, bool force = false) {
assert(force, "Are you sure you want to call this?");
_average = (float)avg;
_weight = wt;
}
// Accessors // Accessors
float average() const { return _average; } float average() const { return _average; }
unsigned weight() const { return _weight; } unsigned weight() const { return _weight; }
...@@ -83,6 +90,10 @@ class AdaptiveWeightedAverage : public CHeapObj { ...@@ -83,6 +90,10 @@ class AdaptiveWeightedAverage : public CHeapObj {
// Convert to float and back to avoid integer overflow. // Convert to float and back to avoid integer overflow.
return (size_t)exp_avg((float)avg, (float)sample, weight); return (size_t)exp_avg((float)avg, (float)sample, weight);
} }
// Printing
void print_on(outputStream* st) const;
void print() const;
}; };
...@@ -129,6 +140,10 @@ class AdaptivePaddedAverage : public AdaptiveWeightedAverage { ...@@ -129,6 +140,10 @@ class AdaptivePaddedAverage : public AdaptiveWeightedAverage {
// Override // Override
void sample(float new_sample); void sample(float new_sample);
// Printing
void print_on(outputStream* st) const;
void print() const;
}; };
// A weighted average that includes a deviation from the average, // A weighted average that includes a deviation from the average,
...@@ -146,7 +161,12 @@ public: ...@@ -146,7 +161,12 @@ public:
AdaptivePaddedAverage(weight, padding) {} AdaptivePaddedAverage(weight, padding) {}
// Override // Override
void sample(float new_sample); void sample(float new_sample);
// Printing
void print_on(outputStream* st) const;
void print() const;
}; };
// Use a least squares fit to a set of data to generate a linear // Use a least squares fit to a set of data to generate a linear
// equation. // equation.
// y = intercept + slope * x // y = intercept + slope * x
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
// have any questions. // have any questions.
// //
arguments.cpp compactibleFreeListSpace.hpp
assembler_<arch>.cpp g1SATBCardTableModRefBS.hpp assembler_<arch>.cpp g1SATBCardTableModRefBS.hpp
assembler_<arch>.cpp g1CollectedHeap.inline.hpp assembler_<arch>.cpp g1CollectedHeap.inline.hpp
assembler_<arch>.cpp heapRegion.hpp assembler_<arch>.cpp heapRegion.hpp
......
...@@ -609,7 +609,7 @@ void DefNewGeneration::collect(bool full, ...@@ -609,7 +609,7 @@ void DefNewGeneration::collect(bool full,
remove_forwarding_pointers(); remove_forwarding_pointers();
if (PrintGCDetails) { if (PrintGCDetails) {
gclog_or_tty->print(" (promotion failed)"); gclog_or_tty->print(" (promotion failed) ");
} }
// Add to-space to the list of space to compact // Add to-space to the list of space to compact
// when a promotion failure has occurred. In that // when a promotion failure has occurred. In that
...@@ -620,6 +620,9 @@ void DefNewGeneration::collect(bool full, ...@@ -620,6 +620,9 @@ void DefNewGeneration::collect(bool full,
from()->set_next_compaction_space(to()); from()->set_next_compaction_space(to());
gch->set_incremental_collection_will_fail(); gch->set_incremental_collection_will_fail();
// Inform the next generation that a promotion failure occurred.
_next_gen->promotion_failure_occurred();
// Reset the PromotionFailureALot counters. // Reset the PromotionFailureALot counters.
NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();) NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();)
} }
...@@ -679,6 +682,11 @@ void DefNewGeneration::preserve_mark_if_necessary(oop obj, markOop m) { ...@@ -679,6 +682,11 @@ void DefNewGeneration::preserve_mark_if_necessary(oop obj, markOop m) {
void DefNewGeneration::handle_promotion_failure(oop old) { void DefNewGeneration::handle_promotion_failure(oop old) {
preserve_mark_if_necessary(old, old->mark()); preserve_mark_if_necessary(old, old->mark());
if (!_promotion_failed && PrintPromotionFailure) {
gclog_or_tty->print(" (promotion failure size = " SIZE_FORMAT ") ",
old->size());
}
// forward to self // forward to self
old->forward_to(old); old->forward_to(old);
_promotion_failed = true; _promotion_failed = true;
......
...@@ -181,6 +181,12 @@ class Generation: public CHeapObj { ...@@ -181,6 +181,12 @@ class Generation: public CHeapObj {
virtual bool promotion_attempt_is_safe(size_t promotion_in_bytes, virtual bool promotion_attempt_is_safe(size_t promotion_in_bytes,
bool younger_handles_promotion_failure) const; bool younger_handles_promotion_failure) const;
// For a non-young generation, this interface can be used to inform a
// generation that a promotion attempt into that generation failed.
// Typically used to enable diagnostic output for post-mortem analysis,
// but other uses of the interface are not ruled out.
virtual void promotion_failure_occurred() { /* does nothing */ }
// Return an estimate of the maximum allocation that could be performed // Return an estimate of the maximum allocation that could be performed
// in the generation without triggering any collection or expansion // in the generation without triggering any collection or expansion
// activity. It is "unsafe" because no locks are taken; the result // activity. It is "unsafe" because no locks are taken; the result
......
...@@ -948,6 +948,7 @@ static void no_shared_spaces() { ...@@ -948,6 +948,7 @@ static void no_shared_spaces() {
} }
} }
#ifndef KERNEL
// If the user has chosen ParallelGCThreads > 0, we set UseParNewGC // If the user has chosen ParallelGCThreads > 0, we set UseParNewGC
// if it's not explictly set or unset. If the user has chosen // if it's not explictly set or unset. If the user has chosen
// UseParNewGC and not explicitly set ParallelGCThreads we // UseParNewGC and not explicitly set ParallelGCThreads we
...@@ -1177,8 +1178,7 @@ void Arguments::set_cms_and_parnew_gc_flags() { ...@@ -1177,8 +1178,7 @@ void Arguments::set_cms_and_parnew_gc_flags() {
// the value (either from the command line or ergonomics) of // the value (either from the command line or ergonomics) of
// OldPLABSize. Following OldPLABSize is an ergonomics decision. // OldPLABSize. Following OldPLABSize is an ergonomics decision.
FLAG_SET_ERGO(uintx, CMSParPromoteBlocksToClaim, OldPLABSize); FLAG_SET_ERGO(uintx, CMSParPromoteBlocksToClaim, OldPLABSize);
} } else {
else {
// OldPLABSize and CMSParPromoteBlocksToClaim are both set. // OldPLABSize and CMSParPromoteBlocksToClaim are both set.
// CMSParPromoteBlocksToClaim is a collector-specific flag, so // CMSParPromoteBlocksToClaim is a collector-specific flag, so
// we'll let it to take precedence. // we'll let it to take precedence.
...@@ -1188,7 +1188,23 @@ void Arguments::set_cms_and_parnew_gc_flags() { ...@@ -1188,7 +1188,23 @@ void Arguments::set_cms_and_parnew_gc_flags() {
" CMSParPromoteBlocksToClaim will take precedence.\n"); " CMSParPromoteBlocksToClaim will take precedence.\n");
} }
} }
if (!FLAG_IS_DEFAULT(ResizeOldPLAB) && !ResizeOldPLAB) {
// OldPLAB sizing manually turned off: Use a larger default setting,
// unless it was manually specified. This is because a too-low value
// will slow down scavenges.
if (FLAG_IS_DEFAULT(CMSParPromoteBlocksToClaim)) {
FLAG_SET_ERGO(uintx, CMSParPromoteBlocksToClaim, 50); // default value before 6631166
}
}
// Overwrite OldPLABSize which is the variable we will internally use everywhere.
FLAG_SET_ERGO(uintx, OldPLABSize, CMSParPromoteBlocksToClaim);
// If either of the static initialization defaults have changed, note this
// modification.
if (!FLAG_IS_DEFAULT(CMSParPromoteBlocksToClaim) || !FLAG_IS_DEFAULT(OldPLABWeight)) {
CFLS_LAB::modify_initialization(OldPLABSize, OldPLABWeight);
}
} }
#endif // KERNEL
inline uintx max_heap_for_compressed_oops() { inline uintx max_heap_for_compressed_oops() {
LP64_ONLY(return oopDesc::OopEncodingHeapMax - MaxPermSize - os::vm_page_size()); LP64_ONLY(return oopDesc::OopEncodingHeapMax - MaxPermSize - os::vm_page_size());
...@@ -2370,22 +2386,25 @@ SOLARIS_ONLY( ...@@ -2370,22 +2386,25 @@ SOLARIS_ONLY(
"ExtendedDTraceProbes flag is only applicable on Solaris\n"); "ExtendedDTraceProbes flag is only applicable on Solaris\n");
return JNI_EINVAL; return JNI_EINVAL;
#endif // ndef SOLARIS #endif // ndef SOLARIS
} else
#ifdef ASSERT #ifdef ASSERT
if (match_option(option, "-XX:+FullGCALot", &tail)) { } else if (match_option(option, "-XX:+FullGCALot", &tail)) {
FLAG_SET_CMDLINE(bool, FullGCALot, true); FLAG_SET_CMDLINE(bool, FullGCALot, true);
// disable scavenge before parallel mark-compact // disable scavenge before parallel mark-compact
FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false); FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false);
} else
#endif #endif
if (match_option(option, "-XX:ParCMSPromoteBlocksToClaim=", &tail)) { } else if (match_option(option, "-XX:CMSParPromoteBlocksToClaim=", &tail)) {
julong cms_blocks_to_claim = (julong)atol(tail); julong cms_blocks_to_claim = (julong)atol(tail);
FLAG_SET_CMDLINE(uintx, CMSParPromoteBlocksToClaim, cms_blocks_to_claim); FLAG_SET_CMDLINE(uintx, CMSParPromoteBlocksToClaim, cms_blocks_to_claim);
jio_fprintf(defaultStream::error_stream(), jio_fprintf(defaultStream::error_stream(),
"Please use -XX:CMSParPromoteBlocksToClaim in place of " "Please use -XX:OldPLABSize in place of "
"-XX:CMSParPromoteBlocksToClaim in the future\n");
} else if (match_option(option, "-XX:ParCMSPromoteBlocksToClaim=", &tail)) {
julong cms_blocks_to_claim = (julong)atol(tail);
FLAG_SET_CMDLINE(uintx, CMSParPromoteBlocksToClaim, cms_blocks_to_claim);
jio_fprintf(defaultStream::error_stream(),
"Please use -XX:OldPLABSize in place of "
"-XX:ParCMSPromoteBlocksToClaim in the future\n"); "-XX:ParCMSPromoteBlocksToClaim in the future\n");
} else } else if (match_option(option, "-XX:ParallelGCOldGenAllocBufferSize=", &tail)) {
if (match_option(option, "-XX:ParallelGCOldGenAllocBufferSize=", &tail)) {
julong old_plab_size = 0; julong old_plab_size = 0;
ArgsRange errcode = parse_memory_size(tail, &old_plab_size, 1); ArgsRange errcode = parse_memory_size(tail, &old_plab_size, 1);
if (errcode != arg_in_range) { if (errcode != arg_in_range) {
...@@ -2398,8 +2417,7 @@ SOLARIS_ONLY( ...@@ -2398,8 +2417,7 @@ SOLARIS_ONLY(
jio_fprintf(defaultStream::error_stream(), jio_fprintf(defaultStream::error_stream(),
"Please use -XX:OldPLABSize in place of " "Please use -XX:OldPLABSize in place of "
"-XX:ParallelGCOldGenAllocBufferSize in the future\n"); "-XX:ParallelGCOldGenAllocBufferSize in the future\n");
} else } else if (match_option(option, "-XX:ParallelGCToSpaceAllocBufferSize=", &tail)) {
if (match_option(option, "-XX:ParallelGCToSpaceAllocBufferSize=", &tail)) {
julong young_plab_size = 0; julong young_plab_size = 0;
ArgsRange errcode = parse_memory_size(tail, &young_plab_size, 1); ArgsRange errcode = parse_memory_size(tail, &young_plab_size, 1);
if (errcode != arg_in_range) { if (errcode != arg_in_range) {
...@@ -2412,8 +2430,7 @@ SOLARIS_ONLY( ...@@ -2412,8 +2430,7 @@ SOLARIS_ONLY(
jio_fprintf(defaultStream::error_stream(), jio_fprintf(defaultStream::error_stream(),
"Please use -XX:YoungPLABSize in place of " "Please use -XX:YoungPLABSize in place of "
"-XX:ParallelGCToSpaceAllocBufferSize in the future\n"); "-XX:ParallelGCToSpaceAllocBufferSize in the future\n");
} else } else if (match_option(option, "-XX:", &tail)) { // -XX:xxxx
if (match_option(option, "-XX:", &tail)) { // -XX:xxxx
// Skip -XX:Flags= since that case has already been handled // Skip -XX:Flags= since that case has already been handled
if (strncmp(tail, "Flags=", strlen("Flags=")) != 0) { if (strncmp(tail, "Flags=", strlen("Flags=")) != 0) {
if (!process_argument(tail, args->ignoreUnrecognized, origin)) { if (!process_argument(tail, args->ignoreUnrecognized, origin)) {
...@@ -2727,6 +2744,7 @@ jint Arguments::parse(const JavaVMInitArgs* args) { ...@@ -2727,6 +2744,7 @@ jint Arguments::parse(const JavaVMInitArgs* args) {
return JNI_EINVAL; return JNI_EINVAL;
} }
#ifndef KERNEL
if (UseConcMarkSweepGC) { if (UseConcMarkSweepGC) {
// Set flags for CMS and ParNew. Check UseConcMarkSweep first // Set flags for CMS and ParNew. Check UseConcMarkSweep first
// to ensure that when both UseConcMarkSweepGC and UseParNewGC // to ensure that when both UseConcMarkSweepGC and UseParNewGC
...@@ -2744,6 +2762,7 @@ jint Arguments::parse(const JavaVMInitArgs* args) { ...@@ -2744,6 +2762,7 @@ jint Arguments::parse(const JavaVMInitArgs* args) {
set_g1_gc_flags(); set_g1_gc_flags();
} }
} }
#endif // KERNEL
#ifdef SERIALGC #ifdef SERIALGC
assert(verify_serial_gc_flags(), "SerialGC unset"); assert(verify_serial_gc_flags(), "SerialGC unset");
......
...@@ -1355,10 +1355,46 @@ class CommandLineFlags { ...@@ -1355,10 +1355,46 @@ class CommandLineFlags {
product(uintx, ParGCDesiredObjsFromOverflowList, 20, \ product(uintx, ParGCDesiredObjsFromOverflowList, 20, \
"The desired number of objects to claim from the overflow list") \ "The desired number of objects to claim from the overflow list") \
\ \
product(uintx, CMSParPromoteBlocksToClaim, 50, \ product(uintx, CMSParPromoteBlocksToClaim, 16, \
"Number of blocks to attempt to claim when refilling CMS LAB for "\ "Number of blocks to attempt to claim when refilling CMS LAB for "\
"parallel GC.") \ "parallel GC.") \
\ \
product(uintx, OldPLABWeight, 50, \
"Percentage (0-100) used to weight the current sample when" \
"computing exponentially decaying average for resizing CMSParPromoteBlocksToClaim.") \
\
product(bool, ResizeOldPLAB, true, \
"Dynamically resize (old gen) promotion labs") \
\
product(bool, PrintOldPLAB, false, \
"Print (old gen) promotion labs sizing decisions") \
\
product(uintx, CMSOldPLABMin, 16, \
"Min size of CMS gen promotion lab caches per worker per blksize")\
\
product(uintx, CMSOldPLABMax, 1024, \
"Max size of CMS gen promotion lab caches per worker per blksize")\
\
product(uintx, CMSOldPLABNumRefills, 4, \
"Nominal number of refills of CMS gen promotion lab cache" \
" per worker per block size") \
\
product(bool, CMSOldPLABResizeQuicker, false, \
"Whether to react on-the-fly during a scavenge to a sudden" \
" change in block demand rate") \
\
product(uintx, CMSOldPLABToleranceFactor, 4, \
"The tolerance of the phase-change detector for on-the-fly" \
" PLAB resizing during a scavenge") \
\
product(uintx, CMSOldPLABReactivityFactor, 2, \
"The gain in the feedback loop for on-the-fly PLAB resizing" \
" during a scavenge") \
\
product(uintx, CMSOldPLABReactivityCeiling, 10, \
"The clamping of the gain in the feedback loop for on-the-fly" \
" PLAB resizing during a scavenge") \
\
product(bool, AlwaysPreTouch, false, \ product(bool, AlwaysPreTouch, false, \
"It forces all freshly committed pages to be pre-touched.") \ "It forces all freshly committed pages to be pre-touched.") \
\ \
...@@ -1400,27 +1436,54 @@ class CommandLineFlags { ...@@ -1400,27 +1436,54 @@ class CommandLineFlags {
"Percentage (0-100) by which the CMS incremental mode duty cycle" \ "Percentage (0-100) by which the CMS incremental mode duty cycle" \
" is shifted to the right within the period between young GCs") \ " is shifted to the right within the period between young GCs") \
\ \
product(uintx, CMSExpAvgFactor, 25, \ product(uintx, CMSExpAvgFactor, 50, \
"Percentage (0-100) used to weight the current sample when " \ "Percentage (0-100) used to weight the current sample when" \
"computing exponential averages for CMS statistics") \ "computing exponential averages for CMS statistics.") \
\ \
product(uintx, CMS_FLSWeight, 50, \ product(uintx, CMS_FLSWeight, 75, \
"Percentage (0-100) used to weight the current sample when " \ "Percentage (0-100) used to weight the current sample when" \
"computing exponentially decating averages for CMS FLS statistics") \ "computing exponentially decating averages for CMS FLS statistics.") \
\ \
product(uintx, CMS_FLSPadding, 2, \ product(uintx, CMS_FLSPadding, 1, \
"The multiple of deviation from mean to use for buffering " \ "The multiple of deviation from mean to use for buffering" \
"against volatility in free list demand.") \ "against volatility in free list demand.") \
\ \
product(uintx, FLSCoalescePolicy, 2, \ product(uintx, FLSCoalescePolicy, 2, \
"CMS: Aggression level for coalescing, increasing from 0 to 4") \ "CMS: Aggression level for coalescing, increasing from 0 to 4") \
\ \
product(uintx, CMS_SweepWeight, 50, \ product(bool, FLSAlwaysCoalesceLarge, false, \
"CMS: Larger free blocks are always available for coalescing") \
\
product(double, FLSLargestBlockCoalesceProximity, 0.99, \
"CMS: the smaller the percentage the greater the coalition force")\
\
product(double, CMSSmallCoalSurplusPercent, 1.05, \
"CMS: the factor by which to inflate estimated demand of small" \
" block sizes to prevent coalescing with an adjoining block") \
\
product(double, CMSLargeCoalSurplusPercent, 0.95, \
"CMS: the factor by which to inflate estimated demand of large" \
" block sizes to prevent coalescing with an adjoining block") \
\
product(double, CMSSmallSplitSurplusPercent, 1.10, \
"CMS: the factor by which to inflate estimated demand of small" \
" block sizes to prevent splitting to supply demand for smaller" \
" blocks") \
\
product(double, CMSLargeSplitSurplusPercent, 1.00, \
"CMS: the factor by which to inflate estimated demand of large" \
" block sizes to prevent splitting to supply demand for smaller" \
" blocks") \
\
product(bool, CMSExtrapolateSweep, false, \
"CMS: cushion for block demand during sweep") \
\
product(uintx, CMS_SweepWeight, 75, \
"Percentage (0-100) used to weight the current sample when " \ "Percentage (0-100) used to weight the current sample when " \
"computing exponentially decaying average for inter-sweep " \ "computing exponentially decaying average for inter-sweep " \
"duration") \ "duration") \
\ \
product(uintx, CMS_SweepPadding, 2, \ product(uintx, CMS_SweepPadding, 1, \
"The multiple of deviation from mean to use for buffering " \ "The multiple of deviation from mean to use for buffering " \
"against volatility in inter-sweep duration.") \ "against volatility in inter-sweep duration.") \
\ \
...@@ -1459,6 +1522,13 @@ class CommandLineFlags { ...@@ -1459,6 +1522,13 @@ class CommandLineFlags {
product(uintx, CMSIndexedFreeListReplenish, 4, \ product(uintx, CMSIndexedFreeListReplenish, 4, \
"Replenish and indexed free list with this number of chunks") \ "Replenish and indexed free list with this number of chunks") \
\ \
product(bool, CMSReplenishIntermediate, true, \
"Replenish all intermediate free-list caches") \
\
product(bool, CMSSplitIndexedFreeListBlocks, true, \
"When satisfying batched demand, splot blocks from the " \
"IndexedFreeList whose size is a multiple of requested size") \
\
product(bool, CMSLoopWarn, false, \ product(bool, CMSLoopWarn, false, \
"Warn in case of excessive CMS looping") \ "Warn in case of excessive CMS looping") \
\ \
...@@ -1593,6 +1663,18 @@ class CommandLineFlags { ...@@ -1593,6 +1663,18 @@ class CommandLineFlags {
"Bitmap operations should process at most this many bits" \ "Bitmap operations should process at most this many bits" \
"between yields") \ "between yields") \
\ \
product(bool, CMSDumpAtPromotionFailure, false, \
"Dump useful information about the state of the CMS old " \
" generation upon a promotion failure.") \
\
product(bool, CMSPrintChunksInDump, false, \
"In a dump enabled by CMSDumpAtPromotionFailure, include " \
" more detailed information about the free chunks.") \
\
product(bool, CMSPrintObjectsInDump, false, \
"In a dump enabled by CMSDumpAtPromotionFailure, include " \
" more detailed information about the allocated objects.") \
\
diagnostic(bool, FLSVerifyAllHeapReferences, false, \ diagnostic(bool, FLSVerifyAllHeapReferences, false, \
"Verify that all refs across the FLS boundary " \ "Verify that all refs across the FLS boundary " \
" are to valid objects") \ " are to valid objects") \
...@@ -1677,6 +1759,10 @@ class CommandLineFlags { ...@@ -1677,6 +1759,10 @@ class CommandLineFlags {
"The youngest generation collection does not require " \ "The youngest generation collection does not require " \
"a guarantee of full promotion of all live objects.") \ "a guarantee of full promotion of all live objects.") \
\ \
product(bool, PrintPromotionFailure, false, \
"Print additional diagnostic information following " \
" promotion failure") \
\
notproduct(bool, PromotionFailureALot, false, \ notproduct(bool, PromotionFailureALot, false, \
"Use promotion failure handling on every youngest generation " \ "Use promotion failure handling on every youngest generation " \
"collection") \ "collection") \
......
...@@ -128,7 +128,7 @@ void ClassLoadingService::notify_class_unloaded(instanceKlass* k) { ...@@ -128,7 +128,7 @@ void ClassLoadingService::notify_class_unloaded(instanceKlass* k) {
if (TraceClassUnloading) { if (TraceClassUnloading) {
ResourceMark rm; ResourceMark rm;
tty->print_cr("[Unloading class %s]", k->external_name()); gclog_or_tty->print_cr("[Unloading class %s]", k->external_name());
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册