7075646: G1: fix inconsistencies in the monitoring data
Summary: Fixed a few inconsistencies in the monitoring data, in particular when reported from jstat.
Reviewed-by: jmasa, brutisso, johnc
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Sep 22 10:57:37 2011 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Fri Sep 23 16:07:49 2011 -0400
@@ -816,6 +816,11 @@
result =
humongous_obj_allocate_initialize_regions(first, num_regions, word_size);
assert(result != NULL, "it should always return a valid result");
+
+ // A successful humongous object allocation changes the used space
+ // information of the old generation so we need to recalculate the
+ // sizes and update the jstat counters here.
+ g1mm()->update_sizes();
}
verify_region_sets_optional();
@@ -1422,7 +1427,7 @@
if (PrintHeapAtGC) {
Universe::print_heap_after_gc();
}
- g1mm()->update_counters();
+ g1mm()->update_sizes();
post_full_gc_dump();
return true;
@@ -1790,6 +1795,7 @@
_evac_failure_scan_stack(NULL) ,
_mark_in_progress(false),
_cg1r(NULL), _summary_bytes_used(0),
+ _g1mm(NULL),
_refine_cte_cl(NULL),
_full_collection(false),
_free_list("Master Free List"),
@@ -2069,7 +2075,7 @@
// Do create of the monitoring and management support so that
// values in the heap have been properly initialized.
- _g1mm = new G1MonitoringSupport(this, &_g1_storage);
+ _g1mm = new G1MonitoringSupport(this);
return JNI_OK;
}
@@ -3702,7 +3708,7 @@
if (PrintHeapAtGC) {
Universe::print_heap_after_gc();
}
- g1mm()->update_counters();
+ g1mm()->update_sizes();
if (G1SummarizeRSetStats &&
(G1SummarizeRSetStatsPeriod > 0) &&
@@ -5815,7 +5821,6 @@
g1_policy()->update_region_num(true /* next_is_young */);
set_region_short_lived_locked(new_alloc_region);
_hr_printer.alloc(new_alloc_region, G1HRPrinter::Eden, young_list_full);
- g1mm()->update_eden_counters();
return new_alloc_region;
}
}
@@ -5830,6 +5835,10 @@
g1_policy()->add_region_to_incremental_cset_lhs(alloc_region);
_summary_bytes_used += allocated_bytes;
_hr_printer.retire(alloc_region);
+ // We update the eden sizes here, when the region is retired,
+ // instead of when it's allocated, since this is the point that its
+ // used space has been recored in _summary_bytes_used.
+ g1mm()->update_eden_size();
}
HeapRegion* MutatorAllocRegion::allocate_new_region(size_t word_size,
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Sep 22 10:57:37 2011 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Fri Sep 23 16:07:49 2011 -0400
@@ -597,7 +597,10 @@
public:
- G1MonitoringSupport* g1mm() { return _g1mm; }
+ G1MonitoringSupport* g1mm() {
+ assert(_g1mm != NULL, "should have been initialized");
+ return _g1mm;
+ }
// Expand the garbage-first heap by at least the given size (in bytes!).
// Returns true if the heap was expanded by the requested amount;
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Thu Sep 22 10:57:37 2011 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Fri Sep 23 16:07:49 2011 -0400
@@ -1149,6 +1149,10 @@
return young_list_length < young_list_max_length;
}
+ size_t young_list_max_length() {
+ return _young_list_max_length;
+ }
+
void update_region_num(bool young);
bool full_young_gcs() {
--- a/hotspot/src/share/vm/gc_implementation/g1/g1MonitoringSupport.cpp Thu Sep 22 10:57:37 2011 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1MonitoringSupport.cpp Fri Sep 23 16:07:49 2011 -0400
@@ -27,19 +27,69 @@
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
#include "gc_implementation/g1/g1CollectorPolicy.hpp"
-G1MonitoringSupport::G1MonitoringSupport(G1CollectedHeap* g1h,
- VirtualSpace* g1_storage_addr) :
+G1GenerationCounters::G1GenerationCounters(G1MonitoringSupport* g1mm,
+ const char* name,
+ int ordinal, int spaces,
+ size_t min_capacity,
+ size_t max_capacity,
+ size_t curr_capacity)
+ : GenerationCounters(name, ordinal, spaces, min_capacity,
+ max_capacity, curr_capacity), _g1mm(g1mm) { }
+
+// We pad the capacity three times given that the young generation
+// contains three spaces (eden and two survivors).
+G1YoungGenerationCounters::G1YoungGenerationCounters(G1MonitoringSupport* g1mm,
+ const char* name)
+ : G1GenerationCounters(g1mm, name, 0 /* ordinal */, 3 /* spaces */,
+ G1MonitoringSupport::pad_capacity(0, 3) /* min_capacity */,
+ G1MonitoringSupport::pad_capacity(g1mm->young_gen_max(), 3),
+ G1MonitoringSupport::pad_capacity(0, 3) /* curr_capacity */) {
+ update_all();
+}
+
+G1OldGenerationCounters::G1OldGenerationCounters(G1MonitoringSupport* g1mm,
+ const char* name)
+ : G1GenerationCounters(g1mm, name, 1 /* ordinal */, 1 /* spaces */,
+ G1MonitoringSupport::pad_capacity(0) /* min_capacity */,
+ G1MonitoringSupport::pad_capacity(g1mm->old_gen_max()),
+ G1MonitoringSupport::pad_capacity(0) /* curr_capacity */) {
+ update_all();
+}
+
+void G1YoungGenerationCounters::update_all() {
+ size_t committed =
+ G1MonitoringSupport::pad_capacity(_g1mm->young_gen_committed(), 3);
+ _current_size->set_value(committed);
+}
+
+void G1OldGenerationCounters::update_all() {
+ size_t committed =
+ G1MonitoringSupport::pad_capacity(_g1mm->old_gen_committed());
+ _current_size->set_value(committed);
+}
+
+G1MonitoringSupport::G1MonitoringSupport(G1CollectedHeap* g1h) :
_g1h(g1h),
_incremental_collection_counters(NULL),
_full_collection_counters(NULL),
- _non_young_collection_counters(NULL),
+ _old_collection_counters(NULL),
_old_space_counters(NULL),
_young_collection_counters(NULL),
_eden_counters(NULL),
_from_counters(NULL),
_to_counters(NULL),
- _g1_storage_addr(g1_storage_addr)
-{
+
+ _overall_reserved(0),
+ _overall_committed(0), _overall_used(0),
+ _young_region_num(0),
+ _young_gen_committed(0),
+ _eden_committed(0), _eden_used(0),
+ _survivor_committed(0), _survivor_used(0),
+ _old_committed(0), _old_used(0) {
+
+ _overall_reserved = g1h->max_capacity();
+ recalculate_sizes();
+
// Counters for GC collections
//
// name "collector.0". In a generational collector this would be the
@@ -69,110 +119,147 @@
// generational GC terms. The "1, 1" parameters are for
// the n-th generation (=1) with 1 space.
// Counters are created from minCapacity, maxCapacity, and capacity
- _non_young_collection_counters =
- new GenerationCounters("whole heap", 1, 1, _g1_storage_addr);
+ _old_collection_counters = new G1OldGenerationCounters(this, "old");
// name "generation.1.space.0"
// Counters are created from maxCapacity, capacity, initCapacity,
// and used.
- _old_space_counters = new HSpaceCounters("space", 0,
- _g1h->max_capacity(), _g1h->capacity(), _non_young_collection_counters);
+ _old_space_counters = new HSpaceCounters("space", 0 /* ordinal */,
+ pad_capacity(overall_reserved()) /* max_capacity */,
+ pad_capacity(old_space_committed()) /* init_capacity */,
+ _old_collection_counters);
// Young collection set
// name "generation.0". This is logically the young generation.
// The "0, 3" are paremeters for the n-th genertaion (=0) with 3 spaces.
- // See _non_young_collection_counters for additional counters
- _young_collection_counters = new GenerationCounters("young", 0, 3, NULL);
+ // See _old_collection_counters for additional counters
+ _young_collection_counters = new G1YoungGenerationCounters(this, "young");
- // Replace "max_heap_byte_size() with maximum young gen size for
- // g1Collectedheap
// name "generation.0.space.0"
// See _old_space_counters for additional counters
- _eden_counters = new HSpaceCounters("eden", 0,
- _g1h->max_capacity(), eden_space_committed(),
+ _eden_counters = new HSpaceCounters("eden", 0 /* ordinal */,
+ pad_capacity(overall_reserved()) /* max_capacity */,
+ pad_capacity(eden_space_committed()) /* init_capacity */,
_young_collection_counters);
// name "generation.0.space.1"
// See _old_space_counters for additional counters
// Set the arguments to indicate that this survivor space is not used.
- _from_counters = new HSpaceCounters("s0", 1, (long) 0, (long) 0,
+ _from_counters = new HSpaceCounters("s0", 1 /* ordinal */,
+ pad_capacity(0) /* max_capacity */,
+ pad_capacity(0) /* init_capacity */,
_young_collection_counters);
+ // Given that this survivor space is not used, we update it here
+ // once to reflect that its used space is 0 so that we don't have to
+ // worry about updating it again later.
+ _from_counters->update_used(0);
// name "generation.0.space.2"
// See _old_space_counters for additional counters
- _to_counters = new HSpaceCounters("s1", 2,
- _g1h->max_capacity(),
- survivor_space_committed(),
+ _to_counters = new HSpaceCounters("s1", 2 /* ordinal */,
+ pad_capacity(overall_reserved()) /* max_capacity */,
+ pad_capacity(survivor_space_committed()) /* init_capacity */,
_young_collection_counters);
}
-size_t G1MonitoringSupport::overall_committed() {
- return g1h()->capacity();
-}
+void G1MonitoringSupport::recalculate_sizes() {
+ G1CollectedHeap* g1 = g1h();
+
+ // Recalculate all the sizes from scratch. We assume that this is
+ // called at a point where no concurrent updates to the various
+ // values we read here are possible (i.e., at a STW phase at the end
+ // of a GC).
-size_t G1MonitoringSupport::overall_used() {
- return g1h()->used_unlocked();
-}
+ size_t young_list_length = g1->young_list()->length();
+ size_t survivor_list_length = g1->g1_policy()->recorded_survivor_regions();
+ assert(young_list_length >= survivor_list_length, "invariant");
+ size_t eden_list_length = young_list_length - survivor_list_length;
+ // Max length includes any potential extensions to the young gen
+ // we'll do when the GC locker is active.
+ size_t young_list_max_length = g1->g1_policy()->young_list_max_length();
+ assert(young_list_max_length >= survivor_list_length, "invariant");
+ size_t eden_list_max_length = young_list_max_length - survivor_list_length;
-size_t G1MonitoringSupport::eden_space_committed() {
- return MAX2(eden_space_used(), (size_t) HeapRegion::GrainBytes);
-}
+ _overall_used = g1->used_unlocked();
+ _eden_used = eden_list_length * HeapRegion::GrainBytes;
+ _survivor_used = survivor_list_length * HeapRegion::GrainBytes;
+ _young_region_num = young_list_length;
+ _old_used = subtract_up_to_zero(_overall_used, _eden_used + _survivor_used);
+
+ // First calculate the committed sizes that can be calculated independently.
+ _survivor_committed = _survivor_used;
+ _old_committed = HeapRegion::align_up_to_region_byte_size(_old_used);
-size_t G1MonitoringSupport::eden_space_used() {
- size_t young_list_length = g1h()->young_list()->length();
- size_t eden_used = young_list_length * HeapRegion::GrainBytes;
- size_t survivor_used = survivor_space_used();
- eden_used = subtract_up_to_zero(eden_used, survivor_used);
- return eden_used;
-}
+ // Next, start with the overall committed size.
+ _overall_committed = g1->capacity();
+ size_t committed = _overall_committed;
+
+ // Remove the committed size we have calculated so far (for the
+ // survivor and old space).
+ assert(committed >= (_survivor_committed + _old_committed), "sanity");
+ committed -= _survivor_committed + _old_committed;
+
+ // Next, calculate and remove the committed size for the eden.
+ _eden_committed = eden_list_max_length * HeapRegion::GrainBytes;
+ // Somewhat defensive: be robust in case there are inaccuracies in
+ // the calculations
+ _eden_committed = MIN2(_eden_committed, committed);
+ committed -= _eden_committed;
-size_t G1MonitoringSupport::survivor_space_committed() {
- return MAX2(survivor_space_used(),
- (size_t) HeapRegion::GrainBytes);
-}
+ // Finally, give the rest to the old space...
+ _old_committed += committed;
+ // ..and calculate the young gen committed.
+ _young_gen_committed = _eden_committed + _survivor_committed;
-size_t G1MonitoringSupport::survivor_space_used() {
- size_t survivor_num = g1h()->g1_policy()->recorded_survivor_regions();
- size_t survivor_used = survivor_num * HeapRegion::GrainBytes;
- return survivor_used;
+ assert(_overall_committed ==
+ (_eden_committed + _survivor_committed + _old_committed),
+ "the committed sizes should add up");
+ // Somewhat defensive: cap the eden used size to make sure it
+ // never exceeds the committed size.
+ _eden_used = MIN2(_eden_used, _eden_committed);
+ // _survivor_committed and _old_committed are calculated in terms of
+ // the corresponding _*_used value, so the next two conditions
+ // should hold.
+ assert(_survivor_used <= _survivor_committed, "post-condition");
+ assert(_old_used <= _old_committed, "post-condition");
}
-size_t G1MonitoringSupport::old_space_committed() {
- size_t committed = overall_committed();
- size_t eden_committed = eden_space_committed();
- size_t survivor_committed = survivor_space_committed();
- committed = subtract_up_to_zero(committed, eden_committed);
- committed = subtract_up_to_zero(committed, survivor_committed);
- committed = MAX2(committed, (size_t) HeapRegion::GrainBytes);
- return committed;
-}
+void G1MonitoringSupport::recalculate_eden_size() {
+ G1CollectedHeap* g1 = g1h();
+
+ // When a new eden region is allocated, only the eden_used size is
+ // affected (since we have recalculated everything else at the last GC).
-// See the comment near the top of g1MonitoringSupport.hpp for
-// an explanation of these calculations for "used" and "capacity".
-size_t G1MonitoringSupport::old_space_used() {
- size_t used = overall_used();
- size_t eden_used = eden_space_used();
- size_t survivor_used = survivor_space_used();
- used = subtract_up_to_zero(used, eden_used);
- used = subtract_up_to_zero(used, survivor_used);
- return used;
-}
-
-void G1MonitoringSupport::update_counters() {
- if (UsePerfData) {
- eden_counters()->update_capacity(eden_space_committed());
- eden_counters()->update_used(eden_space_used());
- to_counters()->update_capacity(survivor_space_committed());
- to_counters()->update_used(survivor_space_used());
- old_space_counters()->update_capacity(old_space_committed());
- old_space_counters()->update_used(old_space_used());
- non_young_collection_counters()->update_all();
+ size_t young_region_num = g1h()->young_list()->length();
+ if (young_region_num > _young_region_num) {
+ size_t diff = young_region_num - _young_region_num;
+ _eden_used += diff * HeapRegion::GrainBytes;
+ // Somewhat defensive: cap the eden used size to make sure it
+ // never exceeds the committed size.
+ _eden_used = MIN2(_eden_used, _eden_committed);
+ _young_region_num = young_region_num;
}
}
-void G1MonitoringSupport::update_eden_counters() {
+void G1MonitoringSupport::update_sizes() {
+ recalculate_sizes();
if (UsePerfData) {
- eden_counters()->update_capacity(eden_space_committed());
+ eden_counters()->update_capacity(pad_capacity(eden_space_committed()));
+ eden_counters()->update_used(eden_space_used());
+ // only the to survivor space (s1) is active, so we don't need to
+ // update the counteres for the from survivor space (s0)
+ to_counters()->update_capacity(pad_capacity(survivor_space_committed()));
+ to_counters()->update_used(survivor_space_used());
+ old_space_counters()->update_capacity(pad_capacity(old_space_committed()));
+ old_space_counters()->update_used(old_space_used());
+ old_collection_counters()->update_all();
+ young_collection_counters()->update_all();
+ }
+}
+
+void G1MonitoringSupport::update_eden_size() {
+ recalculate_eden_size();
+ if (UsePerfData) {
eden_counters()->update_used(eden_space_used());
}
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1MonitoringSupport.hpp Thu Sep 22 10:57:37 2011 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1MonitoringSupport.hpp Fri Sep 23 16:07:49 2011 -0400
@@ -28,101 +28,93 @@
#include "gc_implementation/shared/hSpaceCounters.hpp"
class G1CollectedHeap;
-class G1SpaceMonitoringSupport;
-// Class for monitoring logical spaces in G1.
-// G1 defines a set of regions as a young
-// collection (analogous to a young generation).
-// The young collection is a logical generation
-// with no fixed chunk (see space.hpp) reflecting
-// the address space for the generation. In addition
-// to the young collection there is its complement
-// the non-young collection that is simply the regions
-// not in the young collection. The non-young collection
-// is treated here as a logical old generation only
-// because the monitoring tools expect a generational
-// heap. The monitoring tools expect that a Space
-// (see space.hpp) exists that describe the
-// address space of young collection and non-young
-// collection and such a view is provided here.
+// Class for monitoring logical spaces in G1. It provides data for
+// both G1's jstat counters as well as G1's memory pools.
+//
+// G1 splits the heap into heap regions and each heap region belongs
+// to one of the following categories:
+//
+// * eden : regions that have been allocated since the last GC
+// * survivors : regions with objects that survived the last few GCs
+// * old : long-lived non-humongous regions
+// * humongous : humongous regions
+// * free : free regions
+//
+// The combination of eden and survivor regions form the equivalent of
+// the young generation in the other GCs. The combination of old and
+// humongous regions form the equivalent of the old generation in the
+// other GCs. Free regions do not have a good equivalent in the other
+// GCs given that they can be allocated as any of the other region types.
//
-// This class provides interfaces to access
-// the value of variables for the young collection
-// that include the "capacity" and "used" of the
-// young collection along with constant values
-// for the minimum and maximum capacities for
-// the logical spaces. Similarly for the non-young
-// collection.
-//
-// Also provided are counters for G1 concurrent collections
-// and stop-the-world full heap collecitons.
+// The monitoring tools expect the heap to contain a number of
+// generations (young, old, perm) and each generation to contain a
+// number of spaces (young: eden, survivors, old). Given that G1 does
+// not maintain those spaces physically (e.g., the set of
+// non-contiguous eden regions can be considered as a "logical"
+// space), we'll provide the illusion that those generations and
+// spaces exist. In reality, each generation and space refers to a set
+// of heap regions that are potentially non-contiguous.
//
-// Below is a description of how "used" and "capactiy"
-// (or committed) is calculated for the logical spaces.
+// This class provides interfaces to access the min, current, and max
+// capacity and current occupancy for each of G1's logical spaces and
+// generations we expose to the monitoring tools. Also provided are
+// counters for G1 concurrent collections and stop-the-world full heap
+// collections.
//
-// 1) The used space calculation for a pool is not necessarily
-// independent of the others. We can easily get from G1 the overall
-// used space in the entire heap, the number of regions in the young
-// generation (includes both eden and survivors), and the number of
-// survivor regions. So, from that we calculate:
+// Below is a description of how the various sizes are calculated.
//
-// survivor_used = survivor_num * region_size
-// eden_used = young_region_num * region_size - survivor_used
-// old_gen_used = overall_used - eden_used - survivor_used
+// * Current Capacity
//
-// Note that survivor_used and eden_used are upper bounds. To get the
-// actual value we would have to iterate over the regions and add up
-// ->used(). But that'd be expensive. So, we'll accept some lack of
-// accuracy for those two. But, we have to be careful when calculating
-// old_gen_used, in case we subtract from overall_used more then the
-// actual number and our result goes negative.
+// - heap_capacity = current heap capacity (e.g., current committed size)
+// - young_gen_capacity = current max young gen target capacity
+// (i.e., young gen target capacity + max allowed expansion capacity)
+// - survivor_capacity = current survivor region capacity
+// - eden_capacity = young_gen_capacity - survivor_capacity
+// - old_capacity = heap_capacity - young_gen_capacity
+//
+// What we do in the above is to distribute the free regions among
+// eden_capacity and old_capacity.
//
-// 2) Calculating the used space is straightforward, as described
-// above. However, how do we calculate the committed space, given that
-// we allocate space for the eden, survivor, and old gen out of the
-// same pool of regions? One way to do this is to use the used value
-// as also the committed value for the eden and survivor spaces and
-// then calculate the old gen committed space as follows:
+// * Occupancy
//
-// old_gen_committed = overall_committed - eden_committed - survivor_committed
+// - young_gen_used = current young region capacity
+// - survivor_used = survivor_capacity
+// - eden_used = young_gen_used - survivor_used
+// - old_used = overall_used - young_gen_used
//
-// Maybe a better way to do that would be to calculate used for eden
-// and survivor as a sum of ->used() over their regions and then
-// calculate committed as region_num * region_size (i.e., what we use
-// to calculate the used space now). This is something to consider
-// in the future.
+// Unfortunately, we currently only keep track of the number of
+// currently allocated young and survivor regions + the overall used
+// bytes in the heap, so the above can be a little inaccurate.
+//
+// * Min Capacity
//
-// 3) Another decision that is again not straightforward is what is
-// the max size that each memory pool can grow to. One way to do this
-// would be to use the committed size for the max for the eden and
-// survivors and calculate the old gen max as follows (basically, it's
-// a similar pattern to what we use for the committed space, as
-// described above):
+// We set this to 0 for all spaces. We could consider setting the old
+// min capacity to the min capacity of the heap (see 7078465).
+//
+// * Max Capacity
//
-// old_gen_max = overall_max - eden_max - survivor_max
+// For jstat, we set the max capacity of all spaces to heap_capacity,
+// given that we don't always have a reasonably upper bound on how big
+// each space can grow. For the memory pools, we actually make the max
+// capacity undefined. We could consider setting the old max capacity
+// to the max capacity of the heap (see 7078465).
//
-// Unfortunately, the above makes the max of each pool fluctuate over
-// time and, even though this is allowed according to the spec, it
-// broke several assumptions in the M&M framework (there were cases
-// where used would reach a value greater than max). So, for max we
-// use -1, which means "undefined" according to the spec.
+// If we had more accurate occupancy / capacity information per
+// region set the above calculations would be greatly simplified and
+// be made more accurate.
//
-// 4) Now, there is a very subtle issue with all the above. The
-// framework will call get_memory_usage() on the three pools
-// asynchronously. As a result, each call might get a different value
-// for, say, survivor_num which will yield inconsistent values for
-// eden_used, survivor_used, and old_gen_used (as survivor_num is used
-// in the calculation of all three). This would normally be
-// ok. However, it's possible that this might cause the sum of
-// eden_used, survivor_used, and old_gen_used to go over the max heap
-// size and this seems to sometimes cause JConsole (and maybe other
-// clients) to get confused. There's not a really an easy / clean
-// solution to this problem, due to the asynchrounous nature of the
-// framework.
+// We update all the above synchronously and we store the results in
+// fields so that we just read said fields when needed. A subtle point
+// is that all the above sizes need to be recalculated when the old
+// gen changes capacity (after a GC or after a humongous allocation)
+// but only the eden occupancy changes when a new eden region is
+// allocated. So, in the latter case we have minimal recalcuation to
+// do which is important as we want to keep the eden region allocation
+// path as low-overhead as possible.
class G1MonitoringSupport : public CHeapObj {
G1CollectedHeap* _g1h;
- VirtualSpace* _g1_storage_addr;
// jstat performance counters
// incremental collections both fully and partially young
@@ -133,9 +125,9 @@
// _from_counters, and _to_counters are associated with
// this "generational" counter.
GenerationCounters* _young_collection_counters;
- // non-young collection set counters. The _old_space_counters
+ // old collection set counters. The _old_space_counters
// below are associated with this "generational" counter.
- GenerationCounters* _non_young_collection_counters;
+ GenerationCounters* _old_collection_counters;
// Counters for the capacity and used for
// the whole heap
HSpaceCounters* _old_space_counters;
@@ -145,6 +137,27 @@
HSpaceCounters* _from_counters;
HSpaceCounters* _to_counters;
+ // When it's appropriate to recalculate the various sizes (at the
+ // end of a GC, when a new eden region is allocated, etc.) we store
+ // them here so that we can easily report them when needed and not
+ // have to recalculate them every time.
+
+ size_t _overall_reserved;
+ size_t _overall_committed;
+ size_t _overall_used;
+
+ size_t _young_region_num;
+ size_t _young_gen_committed;
+ size_t _eden_committed;
+ size_t _eden_used;
+ size_t _survivor_committed;
+ size_t _survivor_used;
+
+ size_t _old_committed;
+ size_t _old_used;
+
+ G1CollectedHeap* g1h() { return _g1h; }
+
// It returns x - y if x > y, 0 otherwise.
// As described in the comment above, some of the inputs to the
// calculations we have to do are obtained concurrently and hence
@@ -160,15 +173,35 @@
}
}
+ // Recalculate all the sizes.
+ void recalculate_sizes();
+ // Recalculate only what's necessary when a new eden region is allocated.
+ void recalculate_eden_size();
+
public:
- G1MonitoringSupport(G1CollectedHeap* g1h, VirtualSpace* g1_storage_addr);
+ G1MonitoringSupport(G1CollectedHeap* g1h);
- G1CollectedHeap* g1h() { return _g1h; }
- VirtualSpace* g1_storage_addr() { return _g1_storage_addr; }
+ // Unfortunately, the jstat tool assumes that no space has 0
+ // capacity. In our case, given that each space is logical, it's
+ // possible that no regions will be allocated to it, hence to have 0
+ // capacity (e.g., if there are no survivor regions, the survivor
+ // space has 0 capacity). The way we deal with this is to always pad
+ // each capacity value we report to jstat by a very small amount to
+ // make sure that it's never zero. Given that we sometimes have to
+ // report a capacity of a generation that contains several spaces
+ // (e.g., young gen includes one eden, two survivor spaces), the
+ // mult parameter is provided in order to adding the appropriate
+ // padding multiple times so that the capacities add up correctly.
+ static size_t pad_capacity(size_t size_bytes, size_t mult = 1) {
+ return size_bytes + MinObjAlignmentInBytes * mult;
+ }
- // Performance Counter accessors
- void update_counters();
- void update_eden_counters();
+ // Recalculate all the sizes from scratch and update all the jstat
+ // counters accordingly.
+ void update_sizes();
+ // Recalculate only what's necessary when a new eden region is
+ // allocated and update any jstat counters that need to be updated.
+ void update_eden_size();
CollectorCounters* incremental_collection_counters() {
return _incremental_collection_counters;
@@ -176,8 +209,11 @@
CollectorCounters* full_collection_counters() {
return _full_collection_counters;
}
- GenerationCounters* non_young_collection_counters() {
- return _non_young_collection_counters;
+ GenerationCounters* young_collection_counters() {
+ return _young_collection_counters;
+ }
+ GenerationCounters* old_collection_counters() {
+ return _old_collection_counters;
}
HSpaceCounters* old_space_counters() { return _old_space_counters; }
HSpaceCounters* eden_counters() { return _eden_counters; }
@@ -187,17 +223,45 @@
// Monitoring support used by
// MemoryService
// jstat counters
- size_t overall_committed();
- size_t overall_used();
+
+ size_t overall_reserved() { return _overall_reserved; }
+ size_t overall_committed() { return _overall_committed; }
+ size_t overall_used() { return _overall_used; }
- size_t eden_space_committed();
- size_t eden_space_used();
+ size_t young_gen_committed() { return _young_gen_committed; }
+ size_t young_gen_max() { return overall_reserved(); }
+ size_t eden_space_committed() { return _eden_committed; }
+ size_t eden_space_used() { return _eden_used; }
+ size_t survivor_space_committed() { return _survivor_committed; }
+ size_t survivor_space_used() { return _survivor_used; }
+
+ size_t old_gen_committed() { return old_space_committed(); }
+ size_t old_gen_max() { return overall_reserved(); }
+ size_t old_space_committed() { return _old_committed; }
+ size_t old_space_used() { return _old_used; }
+};
- size_t survivor_space_committed();
- size_t survivor_space_used();
+class G1GenerationCounters: public GenerationCounters {
+protected:
+ G1MonitoringSupport* _g1mm;
+
+public:
+ G1GenerationCounters(G1MonitoringSupport* g1mm,
+ const char* name, int ordinal, int spaces,
+ size_t min_capacity, size_t max_capacity,
+ size_t curr_capacity);
+};
- size_t old_space_committed();
- size_t old_space_used();
+class G1YoungGenerationCounters: public G1GenerationCounters {
+public:
+ G1YoungGenerationCounters(G1MonitoringSupport* g1mm, const char* name);
+ virtual void update_all();
+};
+
+class G1OldGenerationCounters: public G1GenerationCounters {
+public:
+ G1OldGenerationCounters(G1MonitoringSupport* g1mm, const char* name);
+ virtual void update_all();
};
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1MONITORINGSUPPORT_HPP
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp Thu Sep 22 10:57:37 2011 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp Fri Sep 23 16:07:49 2011 -0400
@@ -357,6 +357,11 @@
static int GrainWords;
static int CardsPerRegion;
+ static size_t align_up_to_region_byte_size(size_t sz) {
+ return (sz + (size_t) GrainBytes - 1) &
+ ~((1 << (size_t) LogOfHRGrainBytes) - 1);
+ }
+
// It sets up the heap region size (GrainBytes / GrainWords), as
// well as other related fields that are based on the heap region
// size (LogOfHRGrainBytes / LogOfHRGrainWords /
--- a/hotspot/src/share/vm/gc_implementation/shared/generationCounters.cpp Thu Sep 22 10:57:37 2011 -0700
+++ b/hotspot/src/share/vm/gc_implementation/shared/generationCounters.cpp Fri Sep 23 16:07:49 2011 -0400
@@ -26,14 +26,10 @@
#include "gc_implementation/shared/generationCounters.hpp"
#include "memory/resourceArea.hpp"
-
-GenerationCounters::GenerationCounters(const char* name,
- int ordinal, int spaces,
- VirtualSpace* v):
- _virtual_space(v) {
-
+void GenerationCounters::initialize(const char* name, int ordinal, int spaces,
+ size_t min_capacity, size_t max_capacity,
+ size_t curr_capacity) {
if (UsePerfData) {
-
EXCEPTION_MARK;
ResourceMark rm;
@@ -51,18 +47,37 @@
cname = PerfDataManager::counter_name(_name_space, "minCapacity");
PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_Bytes,
- _virtual_space == NULL ? 0 :
- _virtual_space->committed_size(), CHECK);
+ min_capacity, CHECK);
cname = PerfDataManager::counter_name(_name_space, "maxCapacity");
PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_Bytes,
- _virtual_space == NULL ? 0 :
- _virtual_space->reserved_size(), CHECK);
+ max_capacity, CHECK);
cname = PerfDataManager::counter_name(_name_space, "capacity");
- _current_size = PerfDataManager::create_variable(SUN_GC, cname,
- PerfData::U_Bytes,
- _virtual_space == NULL ? 0 :
- _virtual_space->committed_size(), CHECK);
+ _current_size =
+ PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes,
+ curr_capacity, CHECK);
}
}
+
+GenerationCounters::GenerationCounters(const char* name,
+ int ordinal, int spaces,
+ VirtualSpace* v)
+ : _virtual_space(v) {
+ assert(v != NULL, "don't call this constructor if v == NULL");
+ initialize(name, ordinal, spaces,
+ v->committed_size(), v->reserved_size(), v->committed_size());
+}
+
+GenerationCounters::GenerationCounters(const char* name,
+ int ordinal, int spaces,
+ size_t min_capacity, size_t max_capacity,
+ size_t curr_capacity)
+ : _virtual_space(NULL) {
+ initialize(name, ordinal, spaces, min_capacity, max_capacity, curr_capacity);
+}
+
+void GenerationCounters::update_all() {
+ assert(_virtual_space != NULL, "otherwise, override this method");
+ _current_size->set_value(_virtual_space->committed_size());
+}
--- a/hotspot/src/share/vm/gc_implementation/shared/generationCounters.hpp Thu Sep 22 10:57:37 2011 -0700
+++ b/hotspot/src/share/vm/gc_implementation/shared/generationCounters.hpp Fri Sep 23 16:07:49 2011 -0400
@@ -34,6 +34,11 @@
class GenerationCounters: public CHeapObj {
friend class VMStructs;
+private:
+ void initialize(const char* name, int ordinal, int spaces,
+ size_t min_capacity, size_t max_capacity,
+ size_t curr_capacity);
+
protected:
PerfVariable* _current_size;
VirtualSpace* _virtual_space;
@@ -48,11 +53,18 @@
char* _name_space;
// This constructor is only meant for use with the PSGenerationCounters
- // constructor. The need for such an constructor should be eliminated
+ // constructor. The need for such an constructor should be eliminated
// when VirtualSpace and PSVirtualSpace are unified.
- GenerationCounters() : _name_space(NULL), _current_size(NULL), _virtual_space(NULL) {}
+ GenerationCounters()
+ : _name_space(NULL), _current_size(NULL), _virtual_space(NULL) {}
+
+ // This constructor is used for subclasses that do not have a space
+ // associated with them (e.g, in G1).
+ GenerationCounters(const char* name, int ordinal, int spaces,
+ size_t min_capacity, size_t max_capacity,
+ size_t curr_capacity);
+
public:
-
GenerationCounters(const char* name, int ordinal, int spaces,
VirtualSpace* v);
@@ -60,10 +72,7 @@
if (_name_space != NULL) FREE_C_HEAP_ARRAY(char, _name_space);
}
- virtual void update_all() {
- _current_size->set_value(_virtual_space == NULL ? 0 :
- _virtual_space->committed_size());
- }
+ virtual void update_all();
const char* name_space() const { return _name_space; }
--- a/hotspot/src/share/vm/services/g1MemoryPool.cpp Thu Sep 22 10:57:37 2011 -0700
+++ b/hotspot/src/share/vm/services/g1MemoryPool.cpp Fri Sep 23 16:07:49 2011 -0400
@@ -32,56 +32,28 @@
G1MemoryPoolSuper::G1MemoryPoolSuper(G1CollectedHeap* g1h,
const char* name,
size_t init_size,
+ size_t max_size,
bool support_usage_threshold) :
- _g1h(g1h), CollectedMemoryPool(name,
- MemoryPool::Heap,
- init_size,
- undefined_max(),
- support_usage_threshold) {
+ _g1mm(g1h->g1mm()), CollectedMemoryPool(name,
+ MemoryPool::Heap,
+ init_size,
+ max_size,
+ support_usage_threshold) {
assert(UseG1GC, "sanity");
}
-// See the comment at the top of g1MemoryPool.hpp
-size_t G1MemoryPoolSuper::eden_space_committed(G1CollectedHeap* g1h) {
- return MAX2(eden_space_used(g1h), (size_t) HeapRegion::GrainBytes);
-}
-
-// See the comment at the top of g1MemoryPool.hpp
-size_t G1MemoryPoolSuper::eden_space_used(G1CollectedHeap* g1h) {
- return g1h->g1mm()->eden_space_used();
-}
-
-// See the comment at the top of g1MemoryPool.hpp
-size_t G1MemoryPoolSuper::survivor_space_committed(G1CollectedHeap* g1h) {
- return g1h->g1mm()->survivor_space_committed();
-}
-
-// See the comment at the top of g1MemoryPool.hpp
-size_t G1MemoryPoolSuper::survivor_space_used(G1CollectedHeap* g1h) {
- return g1h->g1mm()->survivor_space_used();
-}
-
-// See the comment at the top of g1MemoryPool.hpp
-size_t G1MemoryPoolSuper::old_space_committed(G1CollectedHeap* g1h) {
- return g1h->g1mm()->old_space_committed();
-}
-
-// See the comment at the top of g1MemoryPool.hpp
-size_t G1MemoryPoolSuper::old_space_used(G1CollectedHeap* g1h) {
- return g1h->g1mm()->old_space_used();
-}
-
G1EdenPool::G1EdenPool(G1CollectedHeap* g1h) :
G1MemoryPoolSuper(g1h,
"G1 Eden Space",
- eden_space_committed(g1h), /* init_size */
+ g1h->g1mm()->eden_space_committed(), /* init_size */
+ _undefined_max,
false /* support_usage_threshold */) { }
MemoryUsage G1EdenPool::get_memory_usage() {
size_t initial_sz = initial_size();
size_t max_sz = max_size();
size_t used = used_in_bytes();
- size_t committed = eden_space_committed(_g1h);
+ size_t committed = _g1mm->eden_space_committed();
return MemoryUsage(initial_sz, used, committed, max_sz);
}
@@ -89,14 +61,15 @@
G1SurvivorPool::G1SurvivorPool(G1CollectedHeap* g1h) :
G1MemoryPoolSuper(g1h,
"G1 Survivor Space",
- survivor_space_committed(g1h), /* init_size */
+ g1h->g1mm()->survivor_space_committed(), /* init_size */
+ _undefined_max,
false /* support_usage_threshold */) { }
MemoryUsage G1SurvivorPool::get_memory_usage() {
size_t initial_sz = initial_size();
size_t max_sz = max_size();
size_t used = used_in_bytes();
- size_t committed = survivor_space_committed(_g1h);
+ size_t committed = _g1mm->survivor_space_committed();
return MemoryUsage(initial_sz, used, committed, max_sz);
}
@@ -104,14 +77,15 @@
G1OldGenPool::G1OldGenPool(G1CollectedHeap* g1h) :
G1MemoryPoolSuper(g1h,
"G1 Old Gen",
- old_space_committed(g1h), /* init_size */
+ g1h->g1mm()->old_space_committed(), /* init_size */
+ _undefined_max,
true /* support_usage_threshold */) { }
MemoryUsage G1OldGenPool::get_memory_usage() {
size_t initial_sz = initial_size();
size_t max_sz = max_size();
size_t used = used_in_bytes();
- size_t committed = old_space_committed(_g1h);
+ size_t committed = _g1mm->old_space_committed();
return MemoryUsage(initial_sz, used, committed, max_sz);
}
--- a/hotspot/src/share/vm/services/g1MemoryPool.hpp Thu Sep 22 10:57:37 2011 -0700
+++ b/hotspot/src/share/vm/services/g1MemoryPool.hpp Fri Sep 23 16:07:49 2011 -0400
@@ -26,12 +26,11 @@
#define SHARE_VM_SERVICES_G1MEMORYPOOL_HPP
#ifndef SERIALGC
+#include "gc_implementation/g1/g1MonitoringSupport.hpp"
#include "services/memoryPool.hpp"
#include "services/memoryUsage.hpp"
#endif
-class G1CollectedHeap;
-
// This file contains the three classes that represent the memory
// pools of the G1 spaces: G1EdenPool, G1SurvivorPool, and
// G1OldGenPool. In G1, unlike our other GCs, we do not have a
@@ -50,37 +49,19 @@
// on this model.
//
-
// This class is shared by the three G1 memory pool classes
-// (G1EdenPool, G1SurvivorPool, G1OldGenPool). Given that the way we
-// calculate used / committed bytes for these three pools is related
-// (see comment above), we put the calculations in this class so that
-// we can easily share them among the subclasses.
+// (G1EdenPool, G1SurvivorPool, G1OldGenPool).
class G1MemoryPoolSuper : public CollectedMemoryPool {
protected:
- G1CollectedHeap* _g1h;
+ const static size_t _undefined_max = (size_t) -1;
+ G1MonitoringSupport* _g1mm;
// Would only be called from subclasses.
G1MemoryPoolSuper(G1CollectedHeap* g1h,
const char* name,
size_t init_size,
+ size_t max_size,
bool support_usage_threshold);
-
- // The reason why all the code is in static methods is so that it
- // can be safely called from the constructors of the subclasses.
-
- static size_t undefined_max() {
- return (size_t) -1;
- }
-
- static size_t eden_space_committed(G1CollectedHeap* g1h);
- static size_t eden_space_used(G1CollectedHeap* g1h);
-
- static size_t survivor_space_committed(G1CollectedHeap* g1h);
- static size_t survivor_space_used(G1CollectedHeap* g1h);
-
- static size_t old_space_committed(G1CollectedHeap* g1h);
- static size_t old_space_used(G1CollectedHeap* g1h);
};
// Memory pool that represents the G1 eden.
@@ -89,10 +70,10 @@
G1EdenPool(G1CollectedHeap* g1h);
size_t used_in_bytes() {
- return eden_space_used(_g1h);
+ return _g1mm->eden_space_used();
}
size_t max_size() const {
- return undefined_max();
+ return _undefined_max;
}
MemoryUsage get_memory_usage();
};
@@ -103,10 +84,10 @@
G1SurvivorPool(G1CollectedHeap* g1h);
size_t used_in_bytes() {
- return survivor_space_used(_g1h);
+ return _g1mm->survivor_space_used();
}
size_t max_size() const {
- return undefined_max();
+ return _undefined_max;
}
MemoryUsage get_memory_usage();
};
@@ -117,10 +98,10 @@
G1OldGenPool(G1CollectedHeap* g1h);
size_t used_in_bytes() {
- return old_space_used(_g1h);
+ return _g1mm->old_space_used();
}
size_t max_size() const {
- return undefined_max();
+ return _undefined_max;
}
MemoryUsage get_memory_usage();
};