--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Mon Apr 04 13:18:35 2011 -0400
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Mon Apr 04 14:23:17 2011 -0400
@@ -1204,7 +1204,6 @@
g1p->record_concurrent_mark_remark_end();
}
-
#define CARD_BM_TEST_MODE 0
class CalcLiveObjectsClosure: public HeapRegionClosure {
@@ -1726,6 +1725,11 @@
}
_total_counting_time += this_final_counting_time;
+ if (G1PrintRegionLivenessInfo) {
+ G1PrintRegionLivenessInfoClosure cl(gclog_or_tty, "Post-Marking");
+ _g1h->heap_region_iterate(&cl);
+ }
+
// Install newly created mark bitMap as "prev".
swapMarkBitMaps();
@@ -4423,3 +4427,175 @@
_marking_step_diffs_ms.add(0.5);
}
+
+// These are formatting macros that are used below to ensure
+// consistent formatting. The *_H_* versions are used to format the
+// header for a particular value and they should be kept consistent
+// with the corresponding macro. Also note that most of the macros add
+// the necessary white space (as a prefix) which makes them a bit
+// easier to compose.
+
+// All the output lines are prefixed with this string to be able to
+// identify them easily in a large log file.
+#define G1PPRL_LINE_PREFIX "###"
+
+#define G1PPRL_ADDR_BASE_FORMAT " "PTR_FORMAT"-"PTR_FORMAT
+#ifdef _LP64
+#define G1PPRL_ADDR_BASE_H_FORMAT " %37s"
+#else // _LP64
+#define G1PPRL_ADDR_BASE_H_FORMAT " %21s"
+#endif // _LP64
+
+// For per-region info
+#define G1PPRL_TYPE_FORMAT " %-4s"
+#define G1PPRL_TYPE_H_FORMAT " %4s"
+#define G1PPRL_BYTE_FORMAT " "SIZE_FORMAT_W(9)
+#define G1PPRL_BYTE_H_FORMAT " %9s"
+#define G1PPRL_DOUBLE_FORMAT " %14.1f"
+#define G1PPRL_DOUBLE_H_FORMAT " %14s"
+
+// For summary info
+#define G1PPRL_SUM_ADDR_FORMAT(tag) " "tag":"G1PPRL_ADDR_BASE_FORMAT
+#define G1PPRL_SUM_BYTE_FORMAT(tag) " "tag": "SIZE_FORMAT
+#define G1PPRL_SUM_MB_FORMAT(tag) " "tag": %1.2f MB"
+#define G1PPRL_SUM_MB_PERC_FORMAT(tag) G1PPRL_SUM_MB_FORMAT(tag)" / %1.2f %%"
+
+G1PrintRegionLivenessInfoClosure::
+G1PrintRegionLivenessInfoClosure(outputStream* out, const char* phase_name)
+ : _out(out),
+ _total_used_bytes(0), _total_capacity_bytes(0),
+ _total_prev_live_bytes(0), _total_next_live_bytes(0),
+ _hum_used_bytes(0), _hum_capacity_bytes(0),
+ _hum_prev_live_bytes(0), _hum_next_live_bytes(0) {
+ G1CollectedHeap* g1h = G1CollectedHeap::heap();
+ MemRegion g1_committed = g1h->g1_committed();
+ MemRegion g1_reserved = g1h->g1_reserved();
+ double now = os::elapsedTime();
+
+ // Print the header of the output.
+ _out->cr();
+ _out->print_cr(G1PPRL_LINE_PREFIX" PHASE %s @ %1.3f", phase_name, now);
+ _out->print_cr(G1PPRL_LINE_PREFIX" HEAP"
+ G1PPRL_SUM_ADDR_FORMAT("committed")
+ G1PPRL_SUM_ADDR_FORMAT("reserved")
+ G1PPRL_SUM_BYTE_FORMAT("region-size"),
+ g1_committed.start(), g1_committed.end(),
+ g1_reserved.start(), g1_reserved.end(),
+ HeapRegion::GrainBytes);
+ _out->print_cr(G1PPRL_LINE_PREFIX);
+ _out->print_cr(G1PPRL_LINE_PREFIX
+ G1PPRL_TYPE_H_FORMAT
+ G1PPRL_ADDR_BASE_H_FORMAT
+ G1PPRL_BYTE_H_FORMAT
+ G1PPRL_BYTE_H_FORMAT
+ G1PPRL_BYTE_H_FORMAT
+ G1PPRL_DOUBLE_H_FORMAT,
+ "type", "address-range",
+ "used", "prev-live", "next-live", "gc-eff");
+}
+
+// It takes as a parameter a reference to one of the _hum_* fields, it
+// deduces the corresponding value for a region in a humongous region
+// series (either the region size, or what's left if the _hum_* field
+// is < the region size), and updates the _hum_* field accordingly.
+size_t G1PrintRegionLivenessInfoClosure::get_hum_bytes(size_t* hum_bytes) {
+ size_t bytes = 0;
+ // The > 0 check is to deal with the prev and next live bytes which
+ // could be 0.
+ if (*hum_bytes > 0) {
+ bytes = MIN2((size_t) HeapRegion::GrainBytes, *hum_bytes);
+ *hum_bytes -= bytes;
+ }
+ return bytes;
+}
+
+// It deduces the values for a region in a humongous region series
+// from the _hum_* fields and updates those accordingly. It assumes
+// that that _hum_* fields have already been set up from the "starts
+// humongous" region and we visit the regions in address order.
+void G1PrintRegionLivenessInfoClosure::get_hum_bytes(size_t* used_bytes,
+ size_t* capacity_bytes,
+ size_t* prev_live_bytes,
+ size_t* next_live_bytes) {
+ assert(_hum_used_bytes > 0 && _hum_capacity_bytes > 0, "pre-condition");
+ *used_bytes = get_hum_bytes(&_hum_used_bytes);
+ *capacity_bytes = get_hum_bytes(&_hum_capacity_bytes);
+ *prev_live_bytes = get_hum_bytes(&_hum_prev_live_bytes);
+ *next_live_bytes = get_hum_bytes(&_hum_next_live_bytes);
+}
+
+bool G1PrintRegionLivenessInfoClosure::doHeapRegion(HeapRegion* r) {
+ const char* type = "";
+ HeapWord* bottom = r->bottom();
+ HeapWord* end = r->end();
+ size_t capacity_bytes = r->capacity();
+ size_t used_bytes = r->used();
+ size_t prev_live_bytes = r->live_bytes();
+ size_t next_live_bytes = r->next_live_bytes();
+ double gc_eff = r->gc_efficiency();
+ if (r->used() == 0) {
+ type = "FREE";
+ } else if (r->is_survivor()) {
+ type = "SURV";
+ } else if (r->is_young()) {
+ type = "EDEN";
+ } else if (r->startsHumongous()) {
+ type = "HUMS";
+
+ assert(_hum_used_bytes == 0 && _hum_capacity_bytes == 0 &&
+ _hum_prev_live_bytes == 0 && _hum_next_live_bytes == 0,
+ "they should have been zeroed after the last time we used them");
+ // Set up the _hum_* fields.
+ _hum_capacity_bytes = capacity_bytes;
+ _hum_used_bytes = used_bytes;
+ _hum_prev_live_bytes = prev_live_bytes;
+ _hum_next_live_bytes = next_live_bytes;
+ get_hum_bytes(&used_bytes, &capacity_bytes,
+ &prev_live_bytes, &next_live_bytes);
+ end = bottom + HeapRegion::GrainWords;
+ } else if (r->continuesHumongous()) {
+ type = "HUMC";
+ get_hum_bytes(&used_bytes, &capacity_bytes,
+ &prev_live_bytes, &next_live_bytes);
+ assert(end == bottom + HeapRegion::GrainWords, "invariant");
+ } else {
+ type = "OLD";
+ }
+
+ _total_used_bytes += used_bytes;
+ _total_capacity_bytes += capacity_bytes;
+ _total_prev_live_bytes += prev_live_bytes;
+ _total_next_live_bytes += next_live_bytes;
+
+ // Print a line for this particular region.
+ _out->print_cr(G1PPRL_LINE_PREFIX
+ G1PPRL_TYPE_FORMAT
+ G1PPRL_ADDR_BASE_FORMAT
+ G1PPRL_BYTE_FORMAT
+ G1PPRL_BYTE_FORMAT
+ G1PPRL_BYTE_FORMAT
+ G1PPRL_DOUBLE_FORMAT,
+ type, bottom, end,
+ used_bytes, prev_live_bytes, next_live_bytes, gc_eff);
+
+ return false;
+}
+
+G1PrintRegionLivenessInfoClosure::~G1PrintRegionLivenessInfoClosure() {
+ // Print the footer of the output.
+ _out->print_cr(G1PPRL_LINE_PREFIX);
+ _out->print_cr(G1PPRL_LINE_PREFIX
+ " SUMMARY"
+ G1PPRL_SUM_MB_FORMAT("capacity")
+ G1PPRL_SUM_MB_PERC_FORMAT("used")
+ G1PPRL_SUM_MB_PERC_FORMAT("prev-live")
+ G1PPRL_SUM_MB_PERC_FORMAT("next-live"),
+ bytes_to_mb(_total_capacity_bytes),
+ bytes_to_mb(_total_used_bytes),
+ perc(_total_used_bytes, _total_capacity_bytes),
+ bytes_to_mb(_total_prev_live_bytes),
+ perc(_total_prev_live_bytes, _total_capacity_bytes),
+ bytes_to_mb(_total_next_live_bytes),
+ perc(_total_next_live_bytes, _total_capacity_bytes));
+ _out->cr();
+}