7050392: G1: Introduce flag to generate a log of the G1 ergonomic decisions
It introduces ergonomic decision logging in G1 for the following heuristics: heap sizing, collection set construction, concurrent cycle initiation, and partially-young GC start/end. The code has a bit of refactoring in a few places to make the decision logging possible. It also replaces alternative ad-hoc logging that we have under different parameters and switches (G1_DEBUG, G1PolicyVerbose). Reviewed-by: johnc, ysr
This commit is contained in:
parent
a9cd50a1c8
commit
24eb07061e
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -26,6 +26,7 @@
|
|||||||
#include "gc_implementation/g1/collectionSetChooser.hpp"
|
#include "gc_implementation/g1/collectionSetChooser.hpp"
|
||||||
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
|
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
|
||||||
#include "gc_implementation/g1/g1CollectorPolicy.hpp"
|
#include "gc_implementation/g1/g1CollectorPolicy.hpp"
|
||||||
|
#include "gc_implementation/g1/g1ErgoVerbose.hpp"
|
||||||
#include "memory/space.inline.hpp"
|
#include "memory/space.inline.hpp"
|
||||||
|
|
||||||
CSetChooserCache::CSetChooserCache() {
|
CSetChooserCache::CSetChooserCache() {
|
||||||
@ -358,6 +359,9 @@ CollectionSetChooser::getNextMarkedRegion(double time_remaining,
|
|||||||
if (_cache.is_empty()) {
|
if (_cache.is_empty()) {
|
||||||
assert(_curMarkedIndex == _numMarkedRegions,
|
assert(_curMarkedIndex == _numMarkedRegions,
|
||||||
"if cache is empty, list should also be empty");
|
"if cache is empty, list should also be empty");
|
||||||
|
ergo_verbose0(ErgoCSetConstruction,
|
||||||
|
"stop adding old regions to CSet",
|
||||||
|
ergo_format_reason("cache is empty"));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,10 +372,23 @@ CollectionSetChooser::getNextMarkedRegion(double time_remaining,
|
|||||||
if (g1p->adaptive_young_list_length()) {
|
if (g1p->adaptive_young_list_length()) {
|
||||||
if (time_remaining - predicted_time < 0.0) {
|
if (time_remaining - predicted_time < 0.0) {
|
||||||
g1h->check_if_region_is_too_expensive(predicted_time);
|
g1h->check_if_region_is_too_expensive(predicted_time);
|
||||||
|
ergo_verbose2(ErgoCSetConstruction,
|
||||||
|
"stop adding old regions to CSet",
|
||||||
|
ergo_format_reason("predicted old region time higher than remaining time")
|
||||||
|
ergo_format_ms("predicted old region time")
|
||||||
|
ergo_format_ms("remaining time"),
|
||||||
|
predicted_time, time_remaining);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (predicted_time > 2.0 * avg_prediction) {
|
double threshold = 2.0 * avg_prediction;
|
||||||
|
if (predicted_time > threshold) {
|
||||||
|
ergo_verbose2(ErgoCSetConstruction,
|
||||||
|
"stop adding old regions to CSet",
|
||||||
|
ergo_format_reason("predicted old region time higher than threshold")
|
||||||
|
ergo_format_ms("predicted old region time")
|
||||||
|
ergo_format_ms("threshold"),
|
||||||
|
predicted_time, threshold);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "gc_implementation/g1/concurrentMarkThread.inline.hpp"
|
#include "gc_implementation/g1/concurrentMarkThread.inline.hpp"
|
||||||
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
|
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
|
||||||
#include "gc_implementation/g1/g1CollectorPolicy.hpp"
|
#include "gc_implementation/g1/g1CollectorPolicy.hpp"
|
||||||
|
#include "gc_implementation/g1/g1ErgoVerbose.hpp"
|
||||||
#include "gc_implementation/g1/g1OopClosures.inline.hpp"
|
#include "gc_implementation/g1/g1OopClosures.inline.hpp"
|
||||||
#include "gc_implementation/g1/g1RemSet.hpp"
|
#include "gc_implementation/g1/g1RemSet.hpp"
|
||||||
#include "gc_implementation/g1/heapRegionRemSet.hpp"
|
#include "gc_implementation/g1/heapRegionRemSet.hpp"
|
||||||
@ -1727,18 +1728,21 @@ void ConcurrentMark::cleanup() {
|
|||||||
|
|
||||||
size_t known_garbage_bytes =
|
size_t known_garbage_bytes =
|
||||||
g1_par_count_task.used_bytes() - g1_par_count_task.live_bytes();
|
g1_par_count_task.used_bytes() - g1_par_count_task.live_bytes();
|
||||||
#if 0
|
|
||||||
gclog_or_tty->print_cr("used %1.2lf, live %1.2lf, garbage %1.2lf",
|
|
||||||
(double) g1_par_count_task.used_bytes() / (double) (1024 * 1024),
|
|
||||||
(double) g1_par_count_task.live_bytes() / (double) (1024 * 1024),
|
|
||||||
(double) known_garbage_bytes / (double) (1024 * 1024));
|
|
||||||
#endif // 0
|
|
||||||
g1p->set_known_garbage_bytes(known_garbage_bytes);
|
g1p->set_known_garbage_bytes(known_garbage_bytes);
|
||||||
|
|
||||||
size_t start_used_bytes = g1h->used();
|
size_t start_used_bytes = g1h->used();
|
||||||
_at_least_one_mark_complete = true;
|
_at_least_one_mark_complete = true;
|
||||||
g1h->set_marking_complete();
|
g1h->set_marking_complete();
|
||||||
|
|
||||||
|
ergo_verbose4(ErgoConcCycles,
|
||||||
|
"finish cleanup",
|
||||||
|
ergo_format_byte("occupancy")
|
||||||
|
ergo_format_byte("capacity")
|
||||||
|
ergo_format_byte_perc("known garbage"),
|
||||||
|
start_used_bytes, g1h->capacity(),
|
||||||
|
known_garbage_bytes,
|
||||||
|
((double) known_garbage_bytes / (double) g1h->capacity()) * 100.0);
|
||||||
|
|
||||||
double count_end = os::elapsedTime();
|
double count_end = os::elapsedTime();
|
||||||
double this_final_counting_time = (count_end - start);
|
double this_final_counting_time = (count_end - start);
|
||||||
if (G1PrintParCleanupStats) {
|
if (G1PrintParCleanupStats) {
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "gc_implementation/g1/g1AllocRegion.inline.hpp"
|
#include "gc_implementation/g1/g1AllocRegion.inline.hpp"
|
||||||
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
|
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
|
||||||
#include "gc_implementation/g1/g1CollectorPolicy.hpp"
|
#include "gc_implementation/g1/g1CollectorPolicy.hpp"
|
||||||
|
#include "gc_implementation/g1/g1ErgoVerbose.hpp"
|
||||||
#include "gc_implementation/g1/g1MarkSweep.hpp"
|
#include "gc_implementation/g1/g1MarkSweep.hpp"
|
||||||
#include "gc_implementation/g1/g1OopClosures.inline.hpp"
|
#include "gc_implementation/g1/g1OopClosures.inline.hpp"
|
||||||
#include "gc_implementation/g1/g1RemSet.inline.hpp"
|
#include "gc_implementation/g1/g1RemSet.inline.hpp"
|
||||||
@ -577,6 +578,11 @@ HeapRegion* G1CollectedHeap::new_region(size_t word_size, bool do_expand) {
|
|||||||
res = new_region_try_secondary_free_list();
|
res = new_region_try_secondary_free_list();
|
||||||
}
|
}
|
||||||
if (res == NULL && do_expand) {
|
if (res == NULL && do_expand) {
|
||||||
|
ergo_verbose1(ErgoHeapSizing,
|
||||||
|
"attempt heap expansion",
|
||||||
|
ergo_format_reason("region allocation request failed")
|
||||||
|
ergo_format_byte("allocation request"),
|
||||||
|
word_size * HeapWordSize);
|
||||||
if (expand(word_size * HeapWordSize)) {
|
if (expand(word_size * HeapWordSize)) {
|
||||||
// Even though the heap was expanded, it might not have reached
|
// Even though the heap was expanded, it might not have reached
|
||||||
// the desired size. So, we cannot assume that the allocation
|
// the desired size. So, we cannot assume that the allocation
|
||||||
@ -790,6 +796,11 @@ HeapWord* G1CollectedHeap::humongous_obj_allocate(size_t word_size) {
|
|||||||
// room available.
|
// room available.
|
||||||
assert(num_regions > fs, "earlier allocation should have succeeded");
|
assert(num_regions > fs, "earlier allocation should have succeeded");
|
||||||
|
|
||||||
|
ergo_verbose1(ErgoHeapSizing,
|
||||||
|
"attempt heap expansion",
|
||||||
|
ergo_format_reason("humongous allocation request failed")
|
||||||
|
ergo_format_byte("allocation request"),
|
||||||
|
word_size * HeapWordSize);
|
||||||
if (expand((num_regions - fs) * HeapRegion::GrainBytes)) {
|
if (expand((num_regions - fs) * HeapRegion::GrainBytes)) {
|
||||||
// Even though the heap was expanded, it might not have
|
// Even though the heap was expanded, it might not have
|
||||||
// reached the desired size. So, we cannot assume that the
|
// reached the desired size. So, we cannot assume that the
|
||||||
@ -906,6 +917,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size,
|
|||||||
|
|
||||||
if (GC_locker::is_active_and_needs_gc()) {
|
if (GC_locker::is_active_and_needs_gc()) {
|
||||||
if (g1_policy()->can_expand_young_list()) {
|
if (g1_policy()->can_expand_young_list()) {
|
||||||
|
// No need for an ergo verbose message here,
|
||||||
|
// can_expand_young_list() does this when it returns true.
|
||||||
result = _mutator_alloc_region.attempt_allocation_force(word_size,
|
result = _mutator_alloc_region.attempt_allocation_force(word_size,
|
||||||
false /* bot_updates */);
|
false /* bot_updates */);
|
||||||
if (result != NULL) {
|
if (result != NULL) {
|
||||||
@ -1477,63 +1490,34 @@ resize_if_necessary_after_full_collection(size_t word_size) {
|
|||||||
// we'll try to make the capacity smaller than it, not greater).
|
// we'll try to make the capacity smaller than it, not greater).
|
||||||
maximum_desired_capacity = MAX2(maximum_desired_capacity, min_heap_size);
|
maximum_desired_capacity = MAX2(maximum_desired_capacity, min_heap_size);
|
||||||
|
|
||||||
if (PrintGC && Verbose) {
|
|
||||||
const double free_percentage =
|
|
||||||
(double) free_after_gc / (double) capacity_after_gc;
|
|
||||||
gclog_or_tty->print_cr("Computing new size after full GC ");
|
|
||||||
gclog_or_tty->print_cr(" "
|
|
||||||
" minimum_free_percentage: %6.2f",
|
|
||||||
minimum_free_percentage);
|
|
||||||
gclog_or_tty->print_cr(" "
|
|
||||||
" maximum_free_percentage: %6.2f",
|
|
||||||
maximum_free_percentage);
|
|
||||||
gclog_or_tty->print_cr(" "
|
|
||||||
" capacity: %6.1fK"
|
|
||||||
" minimum_desired_capacity: %6.1fK"
|
|
||||||
" maximum_desired_capacity: %6.1fK",
|
|
||||||
(double) capacity_after_gc / (double) K,
|
|
||||||
(double) minimum_desired_capacity / (double) K,
|
|
||||||
(double) maximum_desired_capacity / (double) K);
|
|
||||||
gclog_or_tty->print_cr(" "
|
|
||||||
" free_after_gc: %6.1fK"
|
|
||||||
" used_after_gc: %6.1fK",
|
|
||||||
(double) free_after_gc / (double) K,
|
|
||||||
(double) used_after_gc / (double) K);
|
|
||||||
gclog_or_tty->print_cr(" "
|
|
||||||
" free_percentage: %6.2f",
|
|
||||||
free_percentage);
|
|
||||||
}
|
|
||||||
if (capacity_after_gc < minimum_desired_capacity) {
|
if (capacity_after_gc < minimum_desired_capacity) {
|
||||||
// Don't expand unless it's significant
|
// Don't expand unless it's significant
|
||||||
size_t expand_bytes = minimum_desired_capacity - capacity_after_gc;
|
size_t expand_bytes = minimum_desired_capacity - capacity_after_gc;
|
||||||
if (expand(expand_bytes)) {
|
ergo_verbose4(ErgoHeapSizing,
|
||||||
if (PrintGC && Verbose) {
|
"attempt heap expansion",
|
||||||
gclog_or_tty->print_cr(" "
|
ergo_format_reason("capacity lower than "
|
||||||
" expanding:"
|
"min desired capacity after Full GC")
|
||||||
" max_heap_size: %6.1fK"
|
ergo_format_byte("capacity")
|
||||||
" minimum_desired_capacity: %6.1fK"
|
ergo_format_byte("occupancy")
|
||||||
" expand_bytes: %6.1fK",
|
ergo_format_byte_perc("min desired capacity"),
|
||||||
(double) max_heap_size / (double) K,
|
capacity_after_gc, used_after_gc,
|
||||||
(double) minimum_desired_capacity / (double) K,
|
minimum_desired_capacity, (double) MinHeapFreeRatio);
|
||||||
(double) expand_bytes / (double) K);
|
expand(expand_bytes);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No expansion, now see if we want to shrink
|
// No expansion, now see if we want to shrink
|
||||||
} else if (capacity_after_gc > maximum_desired_capacity) {
|
} else if (capacity_after_gc > maximum_desired_capacity) {
|
||||||
// Capacity too large, compute shrinking size
|
// Capacity too large, compute shrinking size
|
||||||
size_t shrink_bytes = capacity_after_gc - maximum_desired_capacity;
|
size_t shrink_bytes = capacity_after_gc - maximum_desired_capacity;
|
||||||
|
ergo_verbose4(ErgoHeapSizing,
|
||||||
|
"attempt heap shrinking",
|
||||||
|
ergo_format_reason("capacity higher than "
|
||||||
|
"max desired capacity after Full GC")
|
||||||
|
ergo_format_byte("capacity")
|
||||||
|
ergo_format_byte("occupancy")
|
||||||
|
ergo_format_byte_perc("max desired capacity"),
|
||||||
|
capacity_after_gc, used_after_gc,
|
||||||
|
maximum_desired_capacity, (double) MaxHeapFreeRatio);
|
||||||
shrink(shrink_bytes);
|
shrink(shrink_bytes);
|
||||||
if (PrintGC && Verbose) {
|
|
||||||
gclog_or_tty->print_cr(" "
|
|
||||||
" shrinking:"
|
|
||||||
" min_heap_size: %6.1fK"
|
|
||||||
" maximum_desired_capacity: %6.1fK"
|
|
||||||
" shrink_bytes: %6.1fK",
|
|
||||||
(double) min_heap_size / (double) K,
|
|
||||||
(double) maximum_desired_capacity / (double) K,
|
|
||||||
(double) shrink_bytes / (double) K);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1619,6 +1603,11 @@ HeapWord* G1CollectedHeap::expand_and_allocate(size_t word_size) {
|
|||||||
verify_region_sets_optional();
|
verify_region_sets_optional();
|
||||||
|
|
||||||
size_t expand_bytes = MAX2(word_size * HeapWordSize, MinHeapDeltaBytes);
|
size_t expand_bytes = MAX2(word_size * HeapWordSize, MinHeapDeltaBytes);
|
||||||
|
ergo_verbose1(ErgoHeapSizing,
|
||||||
|
"attempt heap expansion",
|
||||||
|
ergo_format_reason("allocation request failed")
|
||||||
|
ergo_format_byte("allocation request"),
|
||||||
|
word_size * HeapWordSize);
|
||||||
if (expand(expand_bytes)) {
|
if (expand(expand_bytes)) {
|
||||||
_hrs.verify_optional();
|
_hrs.verify_optional();
|
||||||
verify_region_sets_optional();
|
verify_region_sets_optional();
|
||||||
@ -1646,11 +1635,11 @@ bool G1CollectedHeap::expand(size_t expand_bytes) {
|
|||||||
size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes);
|
size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes);
|
||||||
aligned_expand_bytes = align_size_up(aligned_expand_bytes,
|
aligned_expand_bytes = align_size_up(aligned_expand_bytes,
|
||||||
HeapRegion::GrainBytes);
|
HeapRegion::GrainBytes);
|
||||||
|
ergo_verbose2(ErgoHeapSizing,
|
||||||
if (Verbose && PrintGC) {
|
"expand the heap",
|
||||||
gclog_or_tty->print("Expanding garbage-first heap from %ldK by %ldK",
|
ergo_format_byte("requested expansion amount")
|
||||||
old_mem_size/K, aligned_expand_bytes/K);
|
ergo_format_byte("attempted expansion amount"),
|
||||||
}
|
expand_bytes, aligned_expand_bytes);
|
||||||
|
|
||||||
// First commit the memory.
|
// First commit the memory.
|
||||||
HeapWord* old_end = (HeapWord*) _g1_storage.high();
|
HeapWord* old_end = (HeapWord*) _g1_storage.high();
|
||||||
@ -1694,6 +1683,9 @@ bool G1CollectedHeap::expand(size_t expand_bytes) {
|
|||||||
assert(curr == mr.end(), "post-condition");
|
assert(curr == mr.end(), "post-condition");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
ergo_verbose0(ErgoHeapSizing,
|
||||||
|
"did not expand the heap",
|
||||||
|
ergo_format_reason("heap expansion operation failed"));
|
||||||
// The expansion of the virtual storage space was unsuccessful.
|
// The expansion of the virtual storage space was unsuccessful.
|
||||||
// Let's see if it was because we ran out of swap.
|
// Let's see if it was because we ran out of swap.
|
||||||
if (G1ExitOnExpansionFailure &&
|
if (G1ExitOnExpansionFailure &&
|
||||||
@ -1702,13 +1694,6 @@ bool G1CollectedHeap::expand(size_t expand_bytes) {
|
|||||||
vm_exit_out_of_memory(aligned_expand_bytes, "G1 heap expansion");
|
vm_exit_out_of_memory(aligned_expand_bytes, "G1 heap expansion");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Verbose && PrintGC) {
|
|
||||||
size_t new_mem_size = _g1_storage.committed_size();
|
|
||||||
gclog_or_tty->print_cr("...%s, expanded to %ldK",
|
|
||||||
(successful ? "Successful" : "Failed"),
|
|
||||||
new_mem_size/K);
|
|
||||||
}
|
|
||||||
return successful;
|
return successful;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1722,6 +1707,13 @@ void G1CollectedHeap::shrink_helper(size_t shrink_bytes) {
|
|||||||
MemRegion mr = _hrs.shrink_by(aligned_shrink_bytes, &num_regions_deleted);
|
MemRegion mr = _hrs.shrink_by(aligned_shrink_bytes, &num_regions_deleted);
|
||||||
HeapWord* old_end = (HeapWord*) _g1_storage.high();
|
HeapWord* old_end = (HeapWord*) _g1_storage.high();
|
||||||
assert(mr.end() == old_end, "post-condition");
|
assert(mr.end() == old_end, "post-condition");
|
||||||
|
|
||||||
|
ergo_verbose3(ErgoHeapSizing,
|
||||||
|
"shrink the heap",
|
||||||
|
ergo_format_byte("requested shrinking amount")
|
||||||
|
ergo_format_byte("aligned shrinking amount")
|
||||||
|
ergo_format_byte("attempted shrinking amount"),
|
||||||
|
shrink_bytes, aligned_shrink_bytes, mr.byte_size());
|
||||||
if (mr.byte_size() > 0) {
|
if (mr.byte_size() > 0) {
|
||||||
if (_hr_printer.is_active()) {
|
if (_hr_printer.is_active()) {
|
||||||
HeapWord* curr = mr.end();
|
HeapWord* curr = mr.end();
|
||||||
@ -1740,13 +1732,10 @@ void G1CollectedHeap::shrink_helper(size_t shrink_bytes) {
|
|||||||
_expansion_regions += num_regions_deleted;
|
_expansion_regions += num_regions_deleted;
|
||||||
update_committed_space(old_end, new_end);
|
update_committed_space(old_end, new_end);
|
||||||
HeapRegionRemSet::shrink_heap(n_regions());
|
HeapRegionRemSet::shrink_heap(n_regions());
|
||||||
|
} else {
|
||||||
if (Verbose && PrintGC) {
|
ergo_verbose0(ErgoHeapSizing,
|
||||||
size_t new_mem_size = _g1_storage.committed_size();
|
"did not shrink the heap",
|
||||||
gclog_or_tty->print_cr("Shrinking garbage-first heap from %ldK by %ldK to %ldK",
|
ergo_format_reason("heap shrinking operation failed"));
|
||||||
old_mem_size/K, aligned_shrink_bytes/K,
|
|
||||||
new_mem_size/K);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3579,6 +3568,8 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
|
|||||||
size_t expand_bytes = g1_policy()->expansion_amount();
|
size_t expand_bytes = g1_policy()->expansion_amount();
|
||||||
if (expand_bytes > 0) {
|
if (expand_bytes > 0) {
|
||||||
size_t bytes_before = capacity();
|
size_t bytes_before = capacity();
|
||||||
|
// No need for an ergo verbose message here,
|
||||||
|
// expansion_amount() does this when it returns a value > 0.
|
||||||
if (!expand(expand_bytes)) {
|
if (!expand(expand_bytes)) {
|
||||||
// We failed to expand the heap so let's verify that
|
// We failed to expand the heap so let's verify that
|
||||||
// committed/uncommitted amount match the backing store
|
// committed/uncommitted amount match the backing store
|
||||||
@ -3732,13 +3723,6 @@ public:
|
|||||||
bool do_object_b(oop p) {
|
bool do_object_b(oop p) {
|
||||||
// It is reachable if it is outside the collection set, or is inside
|
// It is reachable if it is outside the collection set, or is inside
|
||||||
// and forwarded.
|
// and forwarded.
|
||||||
|
|
||||||
#ifdef G1_DEBUG
|
|
||||||
gclog_or_tty->print_cr("is alive "PTR_FORMAT" in CS %d forwarded %d overall %d",
|
|
||||||
(void*) p, _g1->obj_in_cs(p), p->is_forwarded(),
|
|
||||||
!_g1->obj_in_cs(p) || p->is_forwarded());
|
|
||||||
#endif // G1_DEBUG
|
|
||||||
|
|
||||||
return !_g1->obj_in_cs(p) || p->is_forwarded();
|
return !_g1->obj_in_cs(p) || p->is_forwarded();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -3750,20 +3734,9 @@ public:
|
|||||||
void do_oop(narrowOop* p) { guarantee(false, "Not needed"); }
|
void do_oop(narrowOop* p) { guarantee(false, "Not needed"); }
|
||||||
void do_oop( oop* p) {
|
void do_oop( oop* p) {
|
||||||
oop obj = *p;
|
oop obj = *p;
|
||||||
#ifdef G1_DEBUG
|
|
||||||
if (PrintGC && Verbose) {
|
|
||||||
gclog_or_tty->print_cr("keep alive *"PTR_FORMAT" = "PTR_FORMAT" "PTR_FORMAT,
|
|
||||||
p, (void*) obj, (void*) *p);
|
|
||||||
}
|
|
||||||
#endif // G1_DEBUG
|
|
||||||
|
|
||||||
if (_g1->obj_in_cs(obj)) {
|
if (_g1->obj_in_cs(obj)) {
|
||||||
assert( obj->is_forwarded(), "invariant" );
|
assert( obj->is_forwarded(), "invariant" );
|
||||||
*p = obj->forwardee();
|
*p = obj->forwardee();
|
||||||
#ifdef G1_DEBUG
|
|
||||||
gclog_or_tty->print_cr(" in CSet: moved "PTR_FORMAT" -> "PTR_FORMAT,
|
|
||||||
(void*) obj, (void*) *p);
|
|
||||||
#endif // G1_DEBUG
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "gc_implementation/g1/concurrentMarkThread.inline.hpp"
|
#include "gc_implementation/g1/concurrentMarkThread.inline.hpp"
|
||||||
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
|
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
|
||||||
#include "gc_implementation/g1/g1CollectorPolicy.hpp"
|
#include "gc_implementation/g1/g1CollectorPolicy.hpp"
|
||||||
|
#include "gc_implementation/g1/g1ErgoVerbose.hpp"
|
||||||
#include "gc_implementation/g1/heapRegionRemSet.hpp"
|
#include "gc_implementation/g1/heapRegionRemSet.hpp"
|
||||||
#include "gc_implementation/shared/gcPolicyCounters.hpp"
|
#include "gc_implementation/shared/gcPolicyCounters.hpp"
|
||||||
#include "runtime/arguments.hpp"
|
#include "runtime/arguments.hpp"
|
||||||
@ -271,15 +272,26 @@ G1CollectorPolicy::G1CollectorPolicy() :
|
|||||||
_recorded_survivor_tail(NULL),
|
_recorded_survivor_tail(NULL),
|
||||||
_survivors_age_table(true),
|
_survivors_age_table(true),
|
||||||
|
|
||||||
_gc_overhead_perc(0.0)
|
_gc_overhead_perc(0.0) {
|
||||||
|
|
||||||
{
|
|
||||||
// Set up the region size and associated fields. Given that the
|
// Set up the region size and associated fields. Given that the
|
||||||
// policy is created before the heap, we have to set this up here,
|
// policy is created before the heap, we have to set this up here,
|
||||||
// so it's done as soon as possible.
|
// so it's done as soon as possible.
|
||||||
HeapRegion::setup_heap_region_size(Arguments::min_heap_size());
|
HeapRegion::setup_heap_region_size(Arguments::min_heap_size());
|
||||||
HeapRegionRemSet::setup_remset_size();
|
HeapRegionRemSet::setup_remset_size();
|
||||||
|
|
||||||
|
G1ErgoVerbose::initialize();
|
||||||
|
if (PrintAdaptiveSizePolicy) {
|
||||||
|
// Currently, we only use a single switch for all the heuristics.
|
||||||
|
G1ErgoVerbose::set_enabled(true);
|
||||||
|
// Given that we don't currently have a verboseness level
|
||||||
|
// parameter, we'll hardcode this to high. This can be easily
|
||||||
|
// changed in the future.
|
||||||
|
G1ErgoVerbose::set_level(ErgoHigh);
|
||||||
|
} else {
|
||||||
|
G1ErgoVerbose::set_enabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
// Verify PLAB sizes
|
// Verify PLAB sizes
|
||||||
const uint region_size = HeapRegion::GrainWords;
|
const uint region_size = HeapRegion::GrainWords;
|
||||||
if (YoungPLABSize > region_size || OldPLABSize > region_size) {
|
if (YoungPLABSize > region_size || OldPLABSize > region_size) {
|
||||||
@ -959,11 +971,9 @@ void
|
|||||||
G1CollectorPolicy::
|
G1CollectorPolicy::
|
||||||
record_concurrent_mark_cleanup_end_work1(size_t freed_bytes,
|
record_concurrent_mark_cleanup_end_work1(size_t freed_bytes,
|
||||||
size_t max_live_bytes) {
|
size_t max_live_bytes) {
|
||||||
if (_n_marks < 2) _n_marks++;
|
if (_n_marks < 2) {
|
||||||
if (G1PolicyVerbose > 0)
|
_n_marks++;
|
||||||
gclog_or_tty->print_cr("At end of marking, max_live is " SIZE_FORMAT " MB "
|
}
|
||||||
" (of " SIZE_FORMAT " MB heap).",
|
|
||||||
max_live_bytes/M, _g1->capacity()/M);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The important thing about this is that it includes "os::elapsedTime".
|
// The important thing about this is that it includes "os::elapsedTime".
|
||||||
@ -977,14 +987,6 @@ void G1CollectorPolicy::record_concurrent_mark_cleanup_end_work2() {
|
|||||||
_mmu_tracker->add_pause(_mark_cleanup_start_sec, end_time_sec, true);
|
_mmu_tracker->add_pause(_mark_cleanup_start_sec, end_time_sec, true);
|
||||||
|
|
||||||
_num_markings++;
|
_num_markings++;
|
||||||
|
|
||||||
// We did a marking, so reset the "since_last_mark" variables.
|
|
||||||
double considerConcMarkCost = 1.0;
|
|
||||||
// If there are available processors, concurrent activity is free...
|
|
||||||
if (Threads::number_of_non_daemon_threads() * 2 <
|
|
||||||
os::active_processor_count()) {
|
|
||||||
considerConcMarkCost = 0.0;
|
|
||||||
}
|
|
||||||
_n_pauses_at_mark_end = _n_pauses;
|
_n_pauses_at_mark_end = _n_pauses;
|
||||||
_n_marks_since_last_pause++;
|
_n_marks_since_last_pause++;
|
||||||
}
|
}
|
||||||
@ -1148,20 +1150,37 @@ void G1CollectorPolicy::record_collection_pause_end() {
|
|||||||
if (last_pause_included_initial_mark)
|
if (last_pause_included_initial_mark)
|
||||||
record_concurrent_mark_init_end(0.0);
|
record_concurrent_mark_init_end(0.0);
|
||||||
|
|
||||||
size_t min_used_targ =
|
size_t marking_initiating_used_threshold =
|
||||||
(_g1->capacity() / 100) * InitiatingHeapOccupancyPercent;
|
(_g1->capacity() / 100) * InitiatingHeapOccupancyPercent;
|
||||||
|
|
||||||
|
|
||||||
if (!_g1->mark_in_progress() && !_last_full_young_gc) {
|
if (!_g1->mark_in_progress() && !_last_full_young_gc) {
|
||||||
assert(!last_pause_included_initial_mark, "invariant");
|
assert(!last_pause_included_initial_mark, "invariant");
|
||||||
if (cur_used_bytes > min_used_targ &&
|
if (cur_used_bytes > marking_initiating_used_threshold) {
|
||||||
cur_used_bytes > _prev_collection_pause_used_at_end_bytes) {
|
if (cur_used_bytes > _prev_collection_pause_used_at_end_bytes) {
|
||||||
assert(!during_initial_mark_pause(), "we should not see this here");
|
assert(!during_initial_mark_pause(), "we should not see this here");
|
||||||
|
|
||||||
|
ergo_verbose3(ErgoConcCycles,
|
||||||
|
"request concurrent cycle initiation",
|
||||||
|
ergo_format_reason("occupancy higher than threshold")
|
||||||
|
ergo_format_byte("occupancy")
|
||||||
|
ergo_format_byte_perc("threshold"),
|
||||||
|
cur_used_bytes,
|
||||||
|
marking_initiating_used_threshold,
|
||||||
|
(double) InitiatingHeapOccupancyPercent);
|
||||||
|
|
||||||
// Note: this might have already been set, if during the last
|
// Note: this might have already been set, if during the last
|
||||||
// pause we decided to start a cycle but at the beginning of
|
// pause we decided to start a cycle but at the beginning of
|
||||||
// this pause we decided to postpone it. That's OK.
|
// this pause we decided to postpone it. That's OK.
|
||||||
set_initiate_conc_mark_if_possible();
|
set_initiate_conc_mark_if_possible();
|
||||||
|
} else {
|
||||||
|
ergo_verbose2(ErgoConcCycles,
|
||||||
|
"do not request concurrent cycle initiation",
|
||||||
|
ergo_format_reason("occupancy lower than previous occupancy")
|
||||||
|
ergo_format_byte("occupancy")
|
||||||
|
ergo_format_byte("previous occupancy"),
|
||||||
|
cur_used_bytes,
|
||||||
|
_prev_collection_pause_used_at_end_bytes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1437,16 +1456,45 @@ void G1CollectorPolicy::record_collection_pause_end() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_last_full_young_gc) {
|
if (_last_full_young_gc) {
|
||||||
|
ergo_verbose2(ErgoPartiallyYoungGCs,
|
||||||
|
"start partially-young GCs",
|
||||||
|
ergo_format_byte_perc("known garbage"),
|
||||||
|
_known_garbage_bytes, _known_garbage_ratio * 100.0);
|
||||||
set_full_young_gcs(false);
|
set_full_young_gcs(false);
|
||||||
_last_full_young_gc = false;
|
_last_full_young_gc = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !_last_young_gc_full ) {
|
if ( !_last_young_gc_full ) {
|
||||||
if ( _should_revert_to_full_young_gcs ||
|
if (_should_revert_to_full_young_gcs) {
|
||||||
_known_garbage_ratio < 0.05 ||
|
ergo_verbose2(ErgoPartiallyYoungGCs,
|
||||||
(adaptive_young_list_length() &&
|
"end partially-young GCs",
|
||||||
(get_gc_eff_factor() * cur_efficiency < predict_young_gc_eff())) ) {
|
ergo_format_reason("partially-young GCs end requested")
|
||||||
set_full_young_gcs(true);
|
ergo_format_byte_perc("known garbage"),
|
||||||
|
_known_garbage_bytes, _known_garbage_ratio * 100.0);
|
||||||
|
set_full_young_gcs(true);
|
||||||
|
} else if (_known_garbage_ratio < 0.05) {
|
||||||
|
ergo_verbose3(ErgoPartiallyYoungGCs,
|
||||||
|
"end partially-young GCs",
|
||||||
|
ergo_format_reason("known garbage percent lower than threshold")
|
||||||
|
ergo_format_byte_perc("known garbage")
|
||||||
|
ergo_format_perc("threshold"),
|
||||||
|
_known_garbage_bytes, _known_garbage_ratio * 100.0,
|
||||||
|
0.05 * 100.0);
|
||||||
|
set_full_young_gcs(true);
|
||||||
|
} else if (adaptive_young_list_length() &&
|
||||||
|
(get_gc_eff_factor() * cur_efficiency < predict_young_gc_eff())) {
|
||||||
|
ergo_verbose5(ErgoPartiallyYoungGCs,
|
||||||
|
"end partially-young GCs",
|
||||||
|
ergo_format_reason("current GC efficiency lower than "
|
||||||
|
"predicted fully-young GC efficiency")
|
||||||
|
ergo_format_double("GC efficiency factor")
|
||||||
|
ergo_format_double("current GC efficiency")
|
||||||
|
ergo_format_double("predicted fully-young GC efficiency")
|
||||||
|
ergo_format_byte_perc("known garbage"),
|
||||||
|
get_gc_eff_factor(), cur_efficiency,
|
||||||
|
predict_young_gc_eff(),
|
||||||
|
_known_garbage_bytes, _known_garbage_ratio * 100.0);
|
||||||
|
set_full_young_gcs(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_should_revert_to_full_young_gcs = false;
|
_should_revert_to_full_young_gcs = false;
|
||||||
@ -1877,6 +1925,12 @@ void G1CollectorPolicy::check_if_region_is_too_expensive(double
|
|||||||
// I don't think we need to do this when in young GC mode since
|
// I don't think we need to do this when in young GC mode since
|
||||||
// marking will be initiated next time we hit the soft limit anyway...
|
// marking will be initiated next time we hit the soft limit anyway...
|
||||||
if (predicted_time_ms > _expensive_region_limit_ms) {
|
if (predicted_time_ms > _expensive_region_limit_ms) {
|
||||||
|
ergo_verbose2(ErgoPartiallyYoungGCs,
|
||||||
|
"request partially-young GCs end",
|
||||||
|
ergo_format_reason("predicted region time higher than threshold")
|
||||||
|
ergo_format_ms("predicted region time")
|
||||||
|
ergo_format_ms("threshold"),
|
||||||
|
predicted_time_ms, _expensive_region_limit_ms);
|
||||||
// no point in doing another partial one
|
// no point in doing another partial one
|
||||||
_should_revert_to_full_young_gcs = true;
|
_should_revert_to_full_young_gcs = true;
|
||||||
}
|
}
|
||||||
@ -1986,7 +2040,9 @@ G1CollectorPolicy::conservative_avg_survival_fraction_work(double avg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t G1CollectorPolicy::expansion_amount() {
|
size_t G1CollectorPolicy::expansion_amount() {
|
||||||
if ((recent_avg_pause_time_ratio() * 100.0) > _gc_overhead_perc) {
|
double recent_gc_overhead = recent_avg_pause_time_ratio() * 100.0;
|
||||||
|
double threshold = _gc_overhead_perc;
|
||||||
|
if (recent_gc_overhead > threshold) {
|
||||||
// We will double the existing space, or take
|
// We will double the existing space, or take
|
||||||
// G1ExpandByPercentOfAvailable % of the available expansion
|
// G1ExpandByPercentOfAvailable % of the available expansion
|
||||||
// space, whichever is smaller, bounded below by a minimum
|
// space, whichever is smaller, bounded below by a minimum
|
||||||
@ -2001,20 +2057,19 @@ size_t G1CollectorPolicy::expansion_amount() {
|
|||||||
expand_bytes = MIN2(expand_bytes_via_pct, committed_bytes);
|
expand_bytes = MIN2(expand_bytes_via_pct, committed_bytes);
|
||||||
expand_bytes = MAX2(expand_bytes, min_expand_bytes);
|
expand_bytes = MAX2(expand_bytes, min_expand_bytes);
|
||||||
expand_bytes = MIN2(expand_bytes, uncommitted_bytes);
|
expand_bytes = MIN2(expand_bytes, uncommitted_bytes);
|
||||||
if (G1PolicyVerbose > 1) {
|
|
||||||
gclog_or_tty->print("Decided to expand: ratio = %5.2f, "
|
ergo_verbose5(ErgoHeapSizing,
|
||||||
"committed = %d%s, uncommited = %d%s, via pct = %d%s.\n"
|
"attempt heap expansion",
|
||||||
" Answer = %d.\n",
|
ergo_format_reason("recent GC overhead higher than "
|
||||||
recent_avg_pause_time_ratio(),
|
"threshold after GC")
|
||||||
byte_size_in_proper_unit(committed_bytes),
|
ergo_format_perc("recent GC overhead")
|
||||||
proper_unit_for_byte_size(committed_bytes),
|
ergo_format_perc("threshold")
|
||||||
byte_size_in_proper_unit(uncommitted_bytes),
|
ergo_format_byte("uncommitted")
|
||||||
proper_unit_for_byte_size(uncommitted_bytes),
|
ergo_format_byte_perc("calculated expansion amount"),
|
||||||
byte_size_in_proper_unit(expand_bytes_via_pct),
|
recent_gc_overhead, threshold,
|
||||||
proper_unit_for_byte_size(expand_bytes_via_pct),
|
uncommitted_bytes,
|
||||||
byte_size_in_proper_unit(expand_bytes),
|
expand_bytes_via_pct, (double) G1ExpandByPercentOfAvailable);
|
||||||
proper_unit_for_byte_size(expand_bytes));
|
|
||||||
}
|
|
||||||
return expand_bytes;
|
return expand_bytes;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
@ -2237,8 +2292,7 @@ void G1CollectorPolicy::print_yg_surv_rate_info() const {
|
|||||||
#endif // PRODUCT
|
#endif // PRODUCT
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void G1CollectorPolicy::update_region_num(bool young) {
|
||||||
G1CollectorPolicy::update_region_num(bool young) {
|
|
||||||
if (young) {
|
if (young) {
|
||||||
++_region_num_young;
|
++_region_num_young;
|
||||||
} else {
|
} else {
|
||||||
@ -2315,13 +2369,23 @@ bool G1CollectorPolicy_BestRegionsFirst::assertMarkedBytesDataOK() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool
|
bool G1CollectorPolicy::force_initial_mark_if_outside_cycle(
|
||||||
G1CollectorPolicy::force_initial_mark_if_outside_cycle() {
|
GCCause::Cause gc_cause) {
|
||||||
bool during_cycle = _g1->concurrent_mark()->cmThread()->during_cycle();
|
bool during_cycle = _g1->concurrent_mark()->cmThread()->during_cycle();
|
||||||
if (!during_cycle) {
|
if (!during_cycle) {
|
||||||
|
ergo_verbose1(ErgoConcCycles,
|
||||||
|
"request concurrent cycle initiation",
|
||||||
|
ergo_format_reason("requested by GC cause")
|
||||||
|
ergo_format_str("GC cause"),
|
||||||
|
GCCause::to_string(gc_cause));
|
||||||
set_initiate_conc_mark_if_possible();
|
set_initiate_conc_mark_if_possible();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
ergo_verbose1(ErgoConcCycles,
|
||||||
|
"do not request concurrent cycle initiation",
|
||||||
|
ergo_format_reason("concurrent cycle already in progress")
|
||||||
|
ergo_format_str("GC cause"),
|
||||||
|
GCCause::to_string(gc_cause));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2353,6 +2417,10 @@ G1CollectorPolicy::decide_on_conc_mark_initiation() {
|
|||||||
// And we can now clear initiate_conc_mark_if_possible() as
|
// And we can now clear initiate_conc_mark_if_possible() as
|
||||||
// we've already acted on it.
|
// we've already acted on it.
|
||||||
clear_initiate_conc_mark_if_possible();
|
clear_initiate_conc_mark_if_possible();
|
||||||
|
|
||||||
|
ergo_verbose0(ErgoConcCycles,
|
||||||
|
"initiate concurrent cycle",
|
||||||
|
ergo_format_reason("concurrent cycle initiation requested"));
|
||||||
} else {
|
} else {
|
||||||
// The concurrent marking thread is still finishing up the
|
// The concurrent marking thread is still finishing up the
|
||||||
// previous cycle. If we start one right now the two cycles
|
// previous cycle. If we start one right now the two cycles
|
||||||
@ -2366,6 +2434,9 @@ G1CollectorPolicy::decide_on_conc_mark_initiation() {
|
|||||||
// and, if it's in a yield point, it's waiting for us to
|
// and, if it's in a yield point, it's waiting for us to
|
||||||
// finish. So, at this point we will not start a cycle and we'll
|
// finish. So, at this point we will not start a cycle and we'll
|
||||||
// let the concurrent marking thread complete the last one.
|
// let the concurrent marking thread complete the last one.
|
||||||
|
ergo_verbose0(ErgoConcCycles,
|
||||||
|
"do not initiate concurrent cycle",
|
||||||
|
ergo_format_reason("concurrent cycle already in progress"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2756,6 +2827,8 @@ G1CollectorPolicy_BestRegionsFirst::choose_collection_set(
|
|||||||
// Set this here - in case we're not doing young collections.
|
// Set this here - in case we're not doing young collections.
|
||||||
double non_young_start_time_sec = os::elapsedTime();
|
double non_young_start_time_sec = os::elapsedTime();
|
||||||
|
|
||||||
|
YoungList* young_list = _g1->young_list();
|
||||||
|
|
||||||
start_recording_regions();
|
start_recording_regions();
|
||||||
|
|
||||||
guarantee(target_pause_time_ms > 0.0,
|
guarantee(target_pause_time_ms > 0.0,
|
||||||
@ -2768,61 +2841,62 @@ G1CollectorPolicy_BestRegionsFirst::choose_collection_set(
|
|||||||
|
|
||||||
double time_remaining_ms = target_pause_time_ms - base_time_ms;
|
double time_remaining_ms = target_pause_time_ms - base_time_ms;
|
||||||
|
|
||||||
|
ergo_verbose3(ErgoCSetConstruction | ErgoHigh,
|
||||||
|
"start choosing CSet",
|
||||||
|
ergo_format_ms("predicted base time")
|
||||||
|
ergo_format_ms("remaining time")
|
||||||
|
ergo_format_ms("target pause time"),
|
||||||
|
base_time_ms, time_remaining_ms, target_pause_time_ms);
|
||||||
|
|
||||||
// the 10% and 50% values are arbitrary...
|
// the 10% and 50% values are arbitrary...
|
||||||
if (time_remaining_ms < 0.10 * target_pause_time_ms) {
|
double threshold = 0.10 * target_pause_time_ms;
|
||||||
|
if (time_remaining_ms < threshold) {
|
||||||
|
double prev_time_remaining_ms = time_remaining_ms;
|
||||||
time_remaining_ms = 0.50 * target_pause_time_ms;
|
time_remaining_ms = 0.50 * target_pause_time_ms;
|
||||||
_within_target = false;
|
_within_target = false;
|
||||||
|
ergo_verbose3(ErgoCSetConstruction,
|
||||||
|
"adjust remaining time",
|
||||||
|
ergo_format_reason("remaining time lower than threshold")
|
||||||
|
ergo_format_ms("remaining time")
|
||||||
|
ergo_format_ms("threshold")
|
||||||
|
ergo_format_ms("adjusted remaining time"),
|
||||||
|
prev_time_remaining_ms, threshold, time_remaining_ms);
|
||||||
} else {
|
} else {
|
||||||
_within_target = true;
|
_within_target = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We figure out the number of bytes available for future to-space.
|
size_t expansion_bytes = _g1->expansion_regions() * HeapRegion::GrainBytes;
|
||||||
// For new regions without marking information, we must assume the
|
|
||||||
// worst-case of complete survival. If we have marking information for a
|
|
||||||
// region, we can bound the amount of live data. We can add a number of
|
|
||||||
// such regions, as long as the sum of the live data bounds does not
|
|
||||||
// exceed the available evacuation space.
|
|
||||||
size_t max_live_bytes = _g1->free_regions() * HeapRegion::GrainBytes;
|
|
||||||
|
|
||||||
size_t expansion_bytes =
|
|
||||||
_g1->expansion_regions() * HeapRegion::GrainBytes;
|
|
||||||
|
|
||||||
_collection_set_bytes_used_before = 0;
|
|
||||||
_collection_set_size = 0;
|
|
||||||
|
|
||||||
// Adjust for expansion and slop.
|
|
||||||
max_live_bytes = max_live_bytes + expansion_bytes;
|
|
||||||
|
|
||||||
HeapRegion* hr;
|
HeapRegion* hr;
|
||||||
double young_start_time_sec = os::elapsedTime();
|
double young_start_time_sec = os::elapsedTime();
|
||||||
|
|
||||||
if (G1PolicyVerbose > 0) {
|
_collection_set_bytes_used_before = 0;
|
||||||
gclog_or_tty->print_cr("Adding %d young regions to the CSet",
|
_collection_set_size = 0;
|
||||||
_g1->young_list()->length());
|
|
||||||
}
|
|
||||||
|
|
||||||
_young_cset_length = 0;
|
_young_cset_length = 0;
|
||||||
_last_young_gc_full = full_young_gcs() ? true : false;
|
_last_young_gc_full = full_young_gcs() ? true : false;
|
||||||
|
|
||||||
if (_last_young_gc_full)
|
if (_last_young_gc_full) {
|
||||||
++_full_young_pause_num;
|
++_full_young_pause_num;
|
||||||
else
|
} else {
|
||||||
++_partial_young_pause_num;
|
++_partial_young_pause_num;
|
||||||
|
}
|
||||||
|
|
||||||
// The young list is laid with the survivor regions from the previous
|
// The young list is laid with the survivor regions from the previous
|
||||||
// pause are appended to the RHS of the young list, i.e.
|
// pause are appended to the RHS of the young list, i.e.
|
||||||
// [Newly Young Regions ++ Survivors from last pause].
|
// [Newly Young Regions ++ Survivors from last pause].
|
||||||
|
|
||||||
hr = _g1->young_list()->first_survivor_region();
|
size_t survivor_region_num = young_list->survivor_length();
|
||||||
|
size_t eden_region_num = young_list->length() - survivor_region_num;
|
||||||
|
size_t old_region_num = 0;
|
||||||
|
hr = young_list->first_survivor_region();
|
||||||
while (hr != NULL) {
|
while (hr != NULL) {
|
||||||
assert(hr->is_survivor(), "badly formed young list");
|
assert(hr->is_survivor(), "badly formed young list");
|
||||||
hr->set_young();
|
hr->set_young();
|
||||||
hr = hr->get_next_young_region();
|
hr = hr->get_next_young_region();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the fields that point to the survivor list - they are
|
// Clear the fields that point to the survivor list - they are all young now.
|
||||||
// all young now.
|
young_list->clear_survivors();
|
||||||
_g1->young_list()->clear_survivors();
|
|
||||||
|
|
||||||
if (_g1->mark_in_progress())
|
if (_g1->mark_in_progress())
|
||||||
_g1->concurrent_mark()->register_collection_set_finger(_inc_cset_max_finger);
|
_g1->concurrent_mark()->register_collection_set_finger(_inc_cset_max_finger);
|
||||||
@ -2831,14 +2905,17 @@ G1CollectorPolicy_BestRegionsFirst::choose_collection_set(
|
|||||||
_collection_set = _inc_cset_head;
|
_collection_set = _inc_cset_head;
|
||||||
_collection_set_size = _inc_cset_size;
|
_collection_set_size = _inc_cset_size;
|
||||||
_collection_set_bytes_used_before = _inc_cset_bytes_used_before;
|
_collection_set_bytes_used_before = _inc_cset_bytes_used_before;
|
||||||
|
|
||||||
// For young regions in the collection set, we assume the worst
|
|
||||||
// case of complete survival
|
|
||||||
max_live_bytes -= _inc_cset_size * HeapRegion::GrainBytes;
|
|
||||||
|
|
||||||
time_remaining_ms -= _inc_cset_predicted_elapsed_time_ms;
|
time_remaining_ms -= _inc_cset_predicted_elapsed_time_ms;
|
||||||
predicted_pause_time_ms += _inc_cset_predicted_elapsed_time_ms;
|
predicted_pause_time_ms += _inc_cset_predicted_elapsed_time_ms;
|
||||||
|
|
||||||
|
ergo_verbose3(ErgoCSetConstruction | ErgoHigh,
|
||||||
|
"add young regions to CSet",
|
||||||
|
ergo_format_region("eden")
|
||||||
|
ergo_format_region("survivors")
|
||||||
|
ergo_format_ms("predicted young region time"),
|
||||||
|
eden_region_num, survivor_region_num,
|
||||||
|
_inc_cset_predicted_elapsed_time_ms);
|
||||||
|
|
||||||
// The number of recorded young regions is the incremental
|
// The number of recorded young regions is the incremental
|
||||||
// collection set's current size
|
// collection set's current size
|
||||||
set_recorded_young_regions(_inc_cset_size);
|
set_recorded_young_regions(_inc_cset_size);
|
||||||
@ -2848,14 +2925,7 @@ G1CollectorPolicy_BestRegionsFirst::choose_collection_set(
|
|||||||
set_predicted_bytes_to_copy(_inc_cset_predicted_bytes_to_copy);
|
set_predicted_bytes_to_copy(_inc_cset_predicted_bytes_to_copy);
|
||||||
#endif // PREDICTIONS_VERBOSE
|
#endif // PREDICTIONS_VERBOSE
|
||||||
|
|
||||||
if (G1PolicyVerbose > 0) {
|
assert(_inc_cset_size == young_list->length(), "Invariant");
|
||||||
gclog_or_tty->print_cr(" Added " PTR_FORMAT " Young Regions to CS.",
|
|
||||||
_inc_cset_size);
|
|
||||||
gclog_or_tty->print_cr(" (" SIZE_FORMAT " KB left in heap.)",
|
|
||||||
max_live_bytes/K);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(_inc_cset_size == _g1->young_list()->length(), "Invariant");
|
|
||||||
|
|
||||||
double young_end_time_sec = os::elapsedTime();
|
double young_end_time_sec = os::elapsedTime();
|
||||||
_recorded_young_cset_choice_time_ms =
|
_recorded_young_cset_choice_time_ms =
|
||||||
@ -2869,6 +2939,8 @@ G1CollectorPolicy_BestRegionsFirst::choose_collection_set(
|
|||||||
NumberSeq seq;
|
NumberSeq seq;
|
||||||
double avg_prediction = 100000000000000000.0; // something very large
|
double avg_prediction = 100000000000000000.0; // something very large
|
||||||
|
|
||||||
|
size_t prev_collection_set_size = _collection_set_size;
|
||||||
|
double prev_predicted_pause_time_ms = predicted_pause_time_ms;
|
||||||
do {
|
do {
|
||||||
hr = _collectionSetChooser->getNextMarkedRegion(time_remaining_ms,
|
hr = _collectionSetChooser->getNextMarkedRegion(time_remaining_ms,
|
||||||
avg_prediction);
|
avg_prediction);
|
||||||
@ -2878,23 +2950,58 @@ G1CollectorPolicy_BestRegionsFirst::choose_collection_set(
|
|||||||
predicted_pause_time_ms += predicted_time_ms;
|
predicted_pause_time_ms += predicted_time_ms;
|
||||||
add_to_collection_set(hr);
|
add_to_collection_set(hr);
|
||||||
record_non_young_cset_region(hr);
|
record_non_young_cset_region(hr);
|
||||||
max_live_bytes -= MIN2(hr->max_live_bytes(), max_live_bytes);
|
|
||||||
if (G1PolicyVerbose > 0) {
|
|
||||||
gclog_or_tty->print_cr(" (" SIZE_FORMAT " KB left in heap.)",
|
|
||||||
max_live_bytes/K);
|
|
||||||
}
|
|
||||||
seq.add(predicted_time_ms);
|
seq.add(predicted_time_ms);
|
||||||
avg_prediction = seq.avg() + seq.sd();
|
avg_prediction = seq.avg() + seq.sd();
|
||||||
}
|
}
|
||||||
should_continue =
|
|
||||||
( hr != NULL) &&
|
should_continue = true;
|
||||||
( (adaptive_young_list_length()) ? time_remaining_ms > 0.0
|
if (hr == NULL) {
|
||||||
: _collection_set_size < _young_list_fixed_length );
|
// No need for an ergo verbose message here,
|
||||||
|
// getNextMarkRegion() does this when it returns NULL.
|
||||||
|
should_continue = false;
|
||||||
|
} else {
|
||||||
|
if (adaptive_young_list_length()) {
|
||||||
|
if (time_remaining_ms < 0.0) {
|
||||||
|
ergo_verbose1(ErgoCSetConstruction,
|
||||||
|
"stop adding old regions to CSet",
|
||||||
|
ergo_format_reason("remaining time is lower than 0")
|
||||||
|
ergo_format_ms("remaining time"),
|
||||||
|
time_remaining_ms);
|
||||||
|
should_continue = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_collection_set_size < _young_list_fixed_length) {
|
||||||
|
ergo_verbose2(ErgoCSetConstruction,
|
||||||
|
"stop adding old regions to CSet",
|
||||||
|
ergo_format_reason("CSet length lower than target")
|
||||||
|
ergo_format_region("CSet")
|
||||||
|
ergo_format_region("young target"),
|
||||||
|
_collection_set_size, _young_list_fixed_length);
|
||||||
|
should_continue = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} while (should_continue);
|
} while (should_continue);
|
||||||
|
|
||||||
if (!adaptive_young_list_length() &&
|
if (!adaptive_young_list_length() &&
|
||||||
_collection_set_size < _young_list_fixed_length)
|
_collection_set_size < _young_list_fixed_length) {
|
||||||
|
ergo_verbose2(ErgoCSetConstruction,
|
||||||
|
"request partially-young GCs end",
|
||||||
|
ergo_format_reason("CSet length lower than target")
|
||||||
|
ergo_format_region("CSet")
|
||||||
|
ergo_format_region("young target"),
|
||||||
|
_collection_set_size, _young_list_fixed_length);
|
||||||
_should_revert_to_full_young_gcs = true;
|
_should_revert_to_full_young_gcs = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
old_region_num = _collection_set_size - prev_collection_set_size;
|
||||||
|
|
||||||
|
ergo_verbose2(ErgoCSetConstruction | ErgoHigh,
|
||||||
|
"add old regions to CSet",
|
||||||
|
ergo_format_region("old")
|
||||||
|
ergo_format_ms("predicted old region time"),
|
||||||
|
old_region_num,
|
||||||
|
predicted_pause_time_ms - prev_predicted_pause_time_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
stop_incremental_cset_building();
|
stop_incremental_cset_building();
|
||||||
@ -2903,6 +3010,16 @@ G1CollectorPolicy_BestRegionsFirst::choose_collection_set(
|
|||||||
|
|
||||||
end_recording_regions();
|
end_recording_regions();
|
||||||
|
|
||||||
|
ergo_verbose5(ErgoCSetConstruction,
|
||||||
|
"finish choosing CSet",
|
||||||
|
ergo_format_region("eden")
|
||||||
|
ergo_format_region("survivors")
|
||||||
|
ergo_format_region("old")
|
||||||
|
ergo_format_ms("predicted pause time")
|
||||||
|
ergo_format_ms("target pause time"),
|
||||||
|
eden_region_num, survivor_region_num, old_region_num,
|
||||||
|
predicted_pause_time_ms, target_pause_time_ms);
|
||||||
|
|
||||||
double non_young_end_time_sec = os::elapsedTime();
|
double non_young_end_time_sec = os::elapsedTime();
|
||||||
_recorded_non_young_cset_choice_time_ms =
|
_recorded_non_young_cset_choice_time_ms =
|
||||||
(non_young_end_time_sec - non_young_start_time_sec) * 1000.0;
|
(non_young_end_time_sec - non_young_start_time_sec) * 1000.0;
|
||||||
@ -2913,12 +3030,6 @@ void G1CollectorPolicy_BestRegionsFirst::record_full_collection_end() {
|
|||||||
_collectionSetChooser->updateAfterFullCollection();
|
_collectionSetChooser->updateAfterFullCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
void G1CollectorPolicy_BestRegionsFirst::
|
|
||||||
expand_if_possible(size_t numRegions) {
|
|
||||||
size_t expansion_bytes = numRegions * HeapRegion::GrainBytes;
|
|
||||||
_g1->expand(expansion_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void G1CollectorPolicy_BestRegionsFirst::
|
void G1CollectorPolicy_BestRegionsFirst::
|
||||||
record_collection_pause_end() {
|
record_collection_pause_end() {
|
||||||
G1CollectorPolicy::record_collection_pause_end();
|
G1CollectorPolicy::record_collection_pause_end();
|
||||||
|
@ -493,7 +493,6 @@ public:
|
|||||||
|
|
||||||
// </NEW PREDICTION>
|
// </NEW PREDICTION>
|
||||||
|
|
||||||
public:
|
|
||||||
void cset_regions_freed() {
|
void cset_regions_freed() {
|
||||||
bool propagate = _last_young_gc_full && !_in_marking_window;
|
bool propagate = _last_young_gc_full && !_in_marking_window;
|
||||||
_short_lived_surv_rate_group->all_surviving_words_recorded(propagate);
|
_short_lived_surv_rate_group->all_surviving_words_recorded(propagate);
|
||||||
@ -1045,7 +1044,7 @@ public:
|
|||||||
// new cycle, as long as we are not already in one. It's best if it
|
// new cycle, as long as we are not already in one. It's best if it
|
||||||
// is called during a safepoint when the test whether a cycle is in
|
// is called during a safepoint when the test whether a cycle is in
|
||||||
// progress or not is stable.
|
// progress or not is stable.
|
||||||
bool force_initial_mark_if_outside_cycle();
|
bool force_initial_mark_if_outside_cycle(GCCause::Cause gc_cause);
|
||||||
|
|
||||||
// This is called at the very beginning of an evacuation pause (it
|
// This is called at the very beginning of an evacuation pause (it
|
||||||
// has to be the first thing that the pause does). If
|
// has to be the first thing that the pause does). If
|
||||||
@ -1234,8 +1233,6 @@ public:
|
|||||||
|
|
||||||
class G1CollectorPolicy_BestRegionsFirst: public G1CollectorPolicy {
|
class G1CollectorPolicy_BestRegionsFirst: public G1CollectorPolicy {
|
||||||
CollectionSetChooser* _collectionSetChooser;
|
CollectionSetChooser* _collectionSetChooser;
|
||||||
// If the estimated is less then desirable, resize if possible.
|
|
||||||
void expand_if_possible(size_t numRegions);
|
|
||||||
|
|
||||||
virtual void choose_collection_set(double target_pause_time_ms);
|
virtual void choose_collection_set(double target_pause_time_ms);
|
||||||
virtual void record_collection_pause_start(double start_time_sec,
|
virtual void record_collection_pause_start(double start_time_sec,
|
||||||
@ -1269,8 +1266,4 @@ inline double variance(int n, double sum_of_squares, double sum) {
|
|||||||
return (sum_of_squares - 2.0 * avg * sum + n_d * avg * avg) / n_d;
|
return (sum_of_squares - 2.0 * avg * sum + n_d * avg * avg) / n_d;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local Variables: ***
|
|
||||||
// c-indentation-style: gnu ***
|
|
||||||
// End: ***
|
|
||||||
|
|
||||||
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1COLLECTORPOLICY_HPP
|
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1COLLECTORPOLICY_HPP
|
||||||
|
65
hotspot/src/share/vm/gc_implementation/g1/g1ErgoVerbose.cpp
Normal file
65
hotspot/src/share/vm/gc_implementation/g1/g1ErgoVerbose.cpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "precompiled.hpp"
|
||||||
|
#include "gc_implementation/g1/g1ErgoVerbose.hpp"
|
||||||
|
#include "utilities/ostream.hpp"
|
||||||
|
|
||||||
|
ErgoLevel G1ErgoVerbose::_level;
|
||||||
|
bool G1ErgoVerbose::_enabled[ErgoHeuristicNum];
|
||||||
|
|
||||||
|
void G1ErgoVerbose::initialize() {
|
||||||
|
set_level(ErgoLow);
|
||||||
|
set_enabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void G1ErgoVerbose::set_level(ErgoLevel level) {
|
||||||
|
_level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
void G1ErgoVerbose::set_enabled(ErgoHeuristic n, bool enabled) {
|
||||||
|
assert(0 <= n && n < ErgoHeuristicNum, "pre-condition");
|
||||||
|
_enabled[n] = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void G1ErgoVerbose::set_enabled(bool enabled) {
|
||||||
|
for (int n = 0; n < ErgoHeuristicNum; n += 1) {
|
||||||
|
set_enabled((ErgoHeuristic) n, enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* G1ErgoVerbose::to_string(int tag) {
|
||||||
|
ErgoHeuristic n = extract_heuristic(tag);
|
||||||
|
switch (n) {
|
||||||
|
case ErgoHeapSizing: return "Heap Sizing";
|
||||||
|
case ErgoCSetConstruction: return "CSet Construction";
|
||||||
|
case ErgoConcCycles: return "Concurrent Cycles";
|
||||||
|
case ErgoPartiallyYoungGCs: return "Partially-Young GCs";
|
||||||
|
default:
|
||||||
|
ShouldNotReachHere();
|
||||||
|
// Keep the Windows compiler happy
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
197
hotspot/src/share/vm/gc_implementation/g1/g1ErgoVerbose.hpp
Normal file
197
hotspot/src/share/vm/gc_implementation/g1/g1ErgoVerbose.hpp
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1ERGOVERBOSE_HPP
|
||||||
|
#define SHARE_VM_GC_IMPLEMENTATION_G1_G1ERGOVERBOSE_HPP
|
||||||
|
|
||||||
|
#include "memory/allocation.hpp"
|
||||||
|
#include "utilities/debug.hpp"
|
||||||
|
|
||||||
|
// The log of G1's heuristic decisions comprises of a series of
|
||||||
|
// records which have a similar format in order to maintain
|
||||||
|
// consistency across records and ultimately easier parsing of the
|
||||||
|
// output, if we ever choose to do that. Each record consists of:
|
||||||
|
// * A time stamp to be able to easily correlate each record with
|
||||||
|
// other events.
|
||||||
|
// * A unique string to allow us to easily identify such records.
|
||||||
|
// * The name of the heuristic the record corresponds to.
|
||||||
|
// * An action string which describes the action that G1 did or is
|
||||||
|
// about to do.
|
||||||
|
// * An optional reason string which describes the reason for the
|
||||||
|
// action.
|
||||||
|
// * An optional number of name/value pairs which contributed to the
|
||||||
|
// decision to take the action described in the record.
|
||||||
|
//
|
||||||
|
// Each record is associated with a "tag" which is the combination of
|
||||||
|
// the heuristic the record corresponds to, as well as the min level
|
||||||
|
// of verboseness at which the record should be printed. The tag is
|
||||||
|
// checked against the current settings to determine whether the record
|
||||||
|
// should be printed or not.
|
||||||
|
|
||||||
|
// The available verboseness levels.
|
||||||
|
typedef enum {
|
||||||
|
// Determine which part of the tag is occupied by the level.
|
||||||
|
ErgoLevelShift = 8,
|
||||||
|
ErgoLevelMask = ~((1 << ErgoLevelShift) - 1),
|
||||||
|
|
||||||
|
// ErgoLow is 0 so that we don't have to explicitly or a heuristic
|
||||||
|
// id with ErgoLow to keep its use simpler.
|
||||||
|
ErgoLow = 0,
|
||||||
|
ErgoHigh = 1 << ErgoLevelShift,
|
||||||
|
} ErgoLevel;
|
||||||
|
|
||||||
|
// The available heuristics.
|
||||||
|
typedef enum {
|
||||||
|
// Determines which part of the tag is occupied by the heuristic id.
|
||||||
|
ErgoHeuristicMask = ~ErgoLevelMask,
|
||||||
|
|
||||||
|
ErgoHeapSizing = 0,
|
||||||
|
ErgoCSetConstruction,
|
||||||
|
ErgoConcCycles,
|
||||||
|
ErgoPartiallyYoungGCs,
|
||||||
|
|
||||||
|
ErgoHeuristicNum
|
||||||
|
} ErgoHeuristic;
|
||||||
|
|
||||||
|
class G1ErgoVerbose : AllStatic {
|
||||||
|
private:
|
||||||
|
// Determines the minimum verboseness level at which records will be
|
||||||
|
// printed.
|
||||||
|
static ErgoLevel _level;
|
||||||
|
// Determines which heuristics are currently enabled.
|
||||||
|
static bool _enabled[ErgoHeuristicNum];
|
||||||
|
|
||||||
|
static ErgoLevel extract_level(int tag) {
|
||||||
|
return (ErgoLevel) (tag & ErgoLevelMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ErgoHeuristic extract_heuristic(int tag) {
|
||||||
|
return (ErgoHeuristic) (tag & ErgoHeuristicMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Needs to be explicitly called at GC initialization.
|
||||||
|
static void initialize();
|
||||||
|
|
||||||
|
static void set_level(ErgoLevel level);
|
||||||
|
static void set_enabled(ErgoHeuristic h, bool enabled);
|
||||||
|
// It is applied to all heuristics.
|
||||||
|
static void set_enabled(bool enabled);
|
||||||
|
|
||||||
|
static bool enabled(int tag) {
|
||||||
|
ErgoLevel level = extract_level(tag);
|
||||||
|
ErgoHeuristic n = extract_heuristic(tag);
|
||||||
|
return level <= _level && _enabled[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the heuristic id from the tag and return a string with
|
||||||
|
// its name.
|
||||||
|
static const char* to_string(int tag);
|
||||||
|
};
|
||||||
|
|
||||||
|
// The macros below generate the format string for values of different
|
||||||
|
// types and/or metrics.
|
||||||
|
|
||||||
|
// The reason for the action is optional and is handled specially: the
|
||||||
|
// reason string is concatenated here so it's not necessary to pass it
|
||||||
|
// as a parameter.
|
||||||
|
#define ergo_format_reason(_reason_) ", reason: " _reason_
|
||||||
|
|
||||||
|
// Single parameter format strings
|
||||||
|
#define ergo_format_str(_name_) ", " _name_ ": %s"
|
||||||
|
#define ergo_format_region(_name_) ", " _name_ ": "SIZE_FORMAT" regions"
|
||||||
|
#define ergo_format_byte(_name_) ", " _name_ ": "SIZE_FORMAT" bytes"
|
||||||
|
#define ergo_format_double(_name_) ", " _name_ ": %1.2f"
|
||||||
|
#define ergo_format_perc(_name_) ", " _name_ ": %1.2f %%"
|
||||||
|
#define ergo_format_ms(_name_) ", " _name_ ": %1.2f ms"
|
||||||
|
|
||||||
|
// Double parameter format strings
|
||||||
|
#define ergo_format_byte_perc(_name_) \
|
||||||
|
", " _name_ ": "SIZE_FORMAT" bytes (%1.2f %%)"
|
||||||
|
|
||||||
|
// Generates the format string
|
||||||
|
#define ergo_format(_action_, _extra_format_) \
|
||||||
|
" %1.3f: [G1Ergonomics (%s) " _action_ _extra_format_ "]"
|
||||||
|
|
||||||
|
// Conditionally, prints an ergonomic decision record. _extra_format_
|
||||||
|
// is the format string for the optional items we'd like to print
|
||||||
|
// (i.e., the decision's reason and any associated values). This
|
||||||
|
// string should be built up using the ergo_*_format macros (see
|
||||||
|
// above) to ensure consistency.
|
||||||
|
//
|
||||||
|
// Since we cannot rely on the compiler supporting variable argument
|
||||||
|
// macros, this macro accepts a fixed number of arguments and passes
|
||||||
|
// them to the print method. For convenience, we have wrapper macros
|
||||||
|
// below which take a specific number of arguments and set the rest to
|
||||||
|
// a default value.
|
||||||
|
#define ergo_verbose_common(_tag_, _action_, _extra_format_, \
|
||||||
|
_arg0_, _arg1_, _arg2_, _arg3_, _arg4_, _arg5_) \
|
||||||
|
do { \
|
||||||
|
if (G1ErgoVerbose::enabled((_tag_))) { \
|
||||||
|
gclog_or_tty->print_cr(ergo_format(_action_, _extra_format_), \
|
||||||
|
os::elapsedTime(), \
|
||||||
|
G1ErgoVerbose::to_string((_tag_)), \
|
||||||
|
(_arg0_), (_arg1_), (_arg2_), \
|
||||||
|
(_arg3_), (_arg4_), (_arg5_)); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
#define ergo_verbose(_tag_, _action_) \
|
||||||
|
ergo_verbose_common(_tag_, _action_, "", 0, 0, 0, 0, 0, 0)
|
||||||
|
|
||||||
|
#define ergo_verbose0(_tag_, _action_, _extra_format_) \
|
||||||
|
ergo_verbose_common(_tag_, _action_, _extra_format_, 0, 0, 0, 0, 0, 0)
|
||||||
|
|
||||||
|
#define ergo_verbose1(_tag_, _action_, _extra_format_, \
|
||||||
|
_arg0_) \
|
||||||
|
ergo_verbose_common(_tag_, _action_, _extra_format_, \
|
||||||
|
_arg0_, 0, 0, 0, 0, 0)
|
||||||
|
|
||||||
|
#define ergo_verbose2(_tag_, _action_, _extra_format_, \
|
||||||
|
_arg0_, _arg1_) \
|
||||||
|
ergo_verbose_common(_tag_, _action_, _extra_format_, \
|
||||||
|
_arg0_, _arg1_, 0, 0, 0, 0)
|
||||||
|
|
||||||
|
#define ergo_verbose3(_tag_, _action_, _extra_format_, \
|
||||||
|
_arg0_, _arg1_, _arg2_) \
|
||||||
|
ergo_verbose_common(_tag_, _action_, _extra_format_, \
|
||||||
|
_arg0_, _arg1_, _arg2_, 0, 0, 0)
|
||||||
|
|
||||||
|
#define ergo_verbose4(_tag_, _action_, _extra_format_, \
|
||||||
|
_arg0_, _arg1_, _arg2_, _arg3_) \
|
||||||
|
ergo_verbose_common(_tag_, _action_, _extra_format_, \
|
||||||
|
_arg0_, _arg1_, _arg2_, _arg3_, 0, 0)
|
||||||
|
|
||||||
|
#define ergo_verbose5(_tag_, _action_, _extra_format_, \
|
||||||
|
_arg0_, _arg1_, _arg2_, _arg3_, _arg4_) \
|
||||||
|
ergo_verbose_common(_tag_, _action_, _extra_format_, \
|
||||||
|
_arg0_, _arg1_, _arg2_, _arg3_, _arg4_, 0)
|
||||||
|
|
||||||
|
#define ergo_verbose6(_tag_, _action_, _extra_format_, \
|
||||||
|
_arg0_, _arg1_, _arg2_, _arg3_, _arg4_, _arg5_) \
|
||||||
|
ergo_verbose_common(_tag_, _action_, _extra_format_, \
|
||||||
|
_arg0_, _arg1_, _arg2_, _arg3_, _arg4_, _arg5_)
|
||||||
|
|
||||||
|
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1ERGOVERBOSE_HPP
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -97,10 +97,6 @@ void G1MMUTrackerQueue::add_pause(double start, double end, bool gc_thread) {
|
|||||||
// or performance (we are GC'ing most of the time anyway!),
|
// or performance (we are GC'ing most of the time anyway!),
|
||||||
// simply overwrite the oldest entry in the tracker.
|
// simply overwrite the oldest entry in the tracker.
|
||||||
|
|
||||||
if (G1PolicyVerbose > 1) {
|
|
||||||
warning("MMU Tracker Queue overflow. Replacing earliest entry.");
|
|
||||||
}
|
|
||||||
|
|
||||||
_head_index = trim_index(_head_index + 1);
|
_head_index = trim_index(_head_index + 1);
|
||||||
assert(_head_index == _tail_index, "Because we have a full circular buffer");
|
assert(_head_index == _tail_index, "Because we have a full circular buffer");
|
||||||
_tail_index = trim_index(_tail_index + 1);
|
_tail_index = trim_index(_tail_index + 1);
|
||||||
|
@ -98,7 +98,7 @@ void VM_G1IncCollectionPause::doit() {
|
|||||||
|
|
||||||
// At this point we are supposed to start a concurrent cycle. We
|
// At this point we are supposed to start a concurrent cycle. We
|
||||||
// will do so if one is not already in progress.
|
// will do so if one is not already in progress.
|
||||||
bool res = g1h->g1_policy()->force_initial_mark_if_outside_cycle();
|
bool res = g1h->g1_policy()->force_initial_mark_if_outside_cycle(_gc_cause);
|
||||||
|
|
||||||
// The above routine returns true if we were able to force the
|
// The above routine returns true if we were able to force the
|
||||||
// next GC pause to be an initial mark; it returns false if a
|
// next GC pause to be an initial mark; it returns false if a
|
||||||
|
Loading…
Reference in New Issue
Block a user