提交 f8e4c60f 编写于 作者: T tonyp

7049999: G1: Make the G1PrintHeapRegions output consistent and complete

Summary: Extend and make more consistent the output from the G1PrintHeapRegions flag.
Reviewed-by: johnc, jmasa
上级 76ac10c6
......@@ -1655,6 +1655,23 @@ public:
_max_live_bytes += g1_note_end.max_live_bytes();
_freed_bytes += g1_note_end.freed_bytes();
// If we iterate over the global cleanup list at the end of
// cleanup to do this printing we will not guarantee to only
// generate output for the newly-reclaimed regions (the list
// might not be empty at the beginning of cleanup; we might
// still be working on its previous contents). So we do the
// printing here, before we append the new regions to the global
// cleanup list.
G1HRPrinter* hr_printer = _g1h->hr_printer();
if (hr_printer->is_active()) {
HeapRegionLinkedListIterator iter(&local_cleanup_list);
while (iter.more_available()) {
HeapRegion* hr = iter.get_next();
hr_printer->cleanup(hr);
}
}
_cleanup_list->add_as_tail(&local_cleanup_list);
assert(local_cleanup_list.is_empty(), "post-condition");
......
......@@ -584,12 +584,6 @@ HeapRegion* G1CollectedHeap::new_region(size_t word_size, bool do_expand) {
res = _free_list.remove_head_or_null();
}
}
if (res != NULL) {
if (G1PrintHeapRegions) {
gclog_or_tty->print_cr("new alloc region "HR_FORMAT,
HR_FORMAT_PARAMS(res));
}
}
return res;
}
......@@ -598,10 +592,15 @@ HeapRegion* G1CollectedHeap::new_gc_alloc_region(int purpose,
HeapRegion* alloc_region = NULL;
if (_gc_alloc_region_counts[purpose] < g1_policy()->max_regions(purpose)) {
alloc_region = new_region(word_size, true /* do_expand */);
if (purpose == GCAllocForSurvived && alloc_region != NULL) {
alloc_region->set_survivor();
if (alloc_region != NULL) {
if (purpose == GCAllocForSurvived) {
_hr_printer.alloc(alloc_region, G1HRPrinter::Survivor);
alloc_region->set_survivor();
} else {
_hr_printer.alloc(alloc_region, G1HRPrinter::Old);
}
++_gc_alloc_region_counts[purpose];
}
++_gc_alloc_region_counts[purpose];
} else {
g1_policy()->note_alloc_region_limit_reached(purpose);
}
......@@ -733,6 +732,17 @@ G1CollectedHeap::humongous_obj_allocate_initialize_regions(size_t first,
assert(first_hr->bottom() < new_top && new_top <= first_hr->end(),
"new_top should be in this region");
first_hr->set_top(new_top);
if (_hr_printer.is_active()) {
HeapWord* bottom = first_hr->bottom();
HeapWord* end = first_hr->orig_end();
if ((first + 1) == last) {
// the series has a single humongous region
_hr_printer.alloc(G1HRPrinter::SingleHumongous, first_hr, new_top);
} else {
// the series has more than one humongous regions
_hr_printer.alloc(G1HRPrinter::StartsHumongous, first_hr, end);
}
}
// Now, we will update the top fields of the "continues humongous"
// regions. The reason we need to do this is that, otherwise,
......@@ -753,10 +763,12 @@ G1CollectedHeap::humongous_obj_allocate_initialize_regions(size_t first,
assert(hr->bottom() < new_top && new_top <= hr->end(),
"new_top should fall on this region");
hr->set_top(new_top);
_hr_printer.alloc(G1HRPrinter::ContinuesHumongous, hr, new_top);
} else {
// not last one
assert(new_top > hr->end(), "new_top should be above this region");
hr->set_top(hr->end());
_hr_printer.alloc(G1HRPrinter::ContinuesHumongous, hr, hr->end());
}
}
// If we have continues humongous regions (hr != NULL), then the
......@@ -1154,6 +1166,35 @@ public:
}
};
class PostCompactionPrinterClosure: public HeapRegionClosure {
private:
G1HRPrinter* _hr_printer;
public:
bool doHeapRegion(HeapRegion* hr) {
assert(!hr->is_young(), "not expecting to find young regions");
// We only generate output for non-empty regions.
if (!hr->is_empty()) {
if (!hr->isHumongous()) {
_hr_printer->post_compaction(hr, G1HRPrinter::Old);
} else if (hr->startsHumongous()) {
if (hr->capacity() == (size_t) HeapRegion::GrainBytes) {
// single humongous region
_hr_printer->post_compaction(hr, G1HRPrinter::SingleHumongous);
} else {
_hr_printer->post_compaction(hr, G1HRPrinter::StartsHumongous);
}
} else {
assert(hr->continuesHumongous(), "only way to get here");
_hr_printer->post_compaction(hr, G1HRPrinter::ContinuesHumongous);
}
}
return false;
}
PostCompactionPrinterClosure(G1HRPrinter* hr_printer)
: _hr_printer(hr_printer) { }
};
bool G1CollectedHeap::do_collection(bool explicit_gc,
bool clear_all_soft_refs,
size_t word_size) {
......@@ -1235,6 +1276,11 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
g1_rem_set()->cleanupHRRS();
tear_down_region_lists();
// We should call this after we retire any currently active alloc
// regions so that all the ALLOC / RETIRE events are generated
// before the start GC event.
_hr_printer.start_gc(true /* full */, (size_t) total_collections());
// We may have added regions to the current incremental collection
// set between the last GC or pause and now. We need to clear the
// incremental collection set and then start rebuilding it afresh
......@@ -1299,6 +1345,17 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
// Resize the heap if necessary.
resize_if_necessary_after_full_collection(explicit_gc ? 0 : word_size);
if (_hr_printer.is_active()) {
// We should do this after we potentially resize the heap so
// that all the COMMIT / UNCOMMIT events are generated before
// the end GC event.
PostCompactionPrinterClosure cl(hr_printer());
heap_region_iterate(&cl);
_hr_printer.end_gc(true /* full */, (size_t) total_collections());
}
if (_cg1r->use_cache()) {
_cg1r->clear_and_record_card_counts();
_cg1r->clear_hot_cache();
......@@ -1654,6 +1711,16 @@ bool G1CollectedHeap::expand(size_t expand_bytes) {
update_committed_space(new_end, mr.end());
}
_free_list.add_as_tail(&expansion_list);
if (_hr_printer.is_active()) {
HeapWord* curr = mr.start();
while (curr < mr.end()) {
HeapWord* curr_end = curr + HeapRegion::GrainWords;
_hr_printer.commit(curr, curr_end);
curr = curr_end;
}
assert(curr == mr.end(), "post-condition");
}
} else {
// The expansion of the virtual storage space was unsuccessful.
// Let's see if it was because we ran out of swap.
......@@ -1684,6 +1751,16 @@ void G1CollectedHeap::shrink_helper(size_t shrink_bytes) {
HeapWord* old_end = (HeapWord*) _g1_storage.high();
assert(mr.end() == old_end, "post-condition");
if (mr.byte_size() > 0) {
if (_hr_printer.is_active()) {
HeapWord* curr = mr.end();
while (curr > mr.start()) {
HeapWord* curr_end = curr;
curr -= HeapRegion::GrainWords;
_hr_printer.uncommit(curr, curr_end);
}
assert(curr == mr.start(), "post-condition");
}
_g1_storage.shrink_by(mr.byte_size());
HeapWord* new_end = (HeapWord*) _g1_storage.high();
assert(mr.start() == new_end, "post-condition");
......@@ -1800,6 +1877,10 @@ jint G1CollectedHeap::initialize() {
MutexLocker x(Heap_lock);
// We have to initialize the printer before committing the heap, as
// it will be used then.
_hr_printer.set_active(G1PrintHeapRegions);
// While there are no constraints in the GC code that HeapWordSize
// be any particular value, there are multiple other areas in the
// system which believe this to be true (e.g. oop->object_size in some
......@@ -3346,6 +3427,11 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
// of the collection set!).
release_mutator_alloc_region();
// We should call this after we retire the mutator alloc
// region(s) so that all the ALLOC / RETIRE events are generated
// before the start GC event.
_hr_printer.start_gc(false /* full */, (size_t) total_collections());
// The elapsed time induced by the start time below deliberately elides
// the possible verification above.
double start_time_sec = os::elapsedTime();
......@@ -3397,6 +3483,22 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
g1_policy()->choose_collection_set(target_pause_time_ms);
if (_hr_printer.is_active()) {
HeapRegion* hr = g1_policy()->collection_set();
while (hr != NULL) {
G1HRPrinter::RegionType type;
if (!hr->is_young()) {
type = G1HRPrinter::Old;
} else if (hr->is_survivor()) {
type = G1HRPrinter::Survivor;
} else {
type = G1HRPrinter::Eden;
}
_hr_printer.cset(hr);
hr = hr->next_in_collection_set();
}
}
// We have chosen the complete collection set. If marking is
// active then, we clear the region fields of any of the
// concurrent marking tasks whose region fields point into
......@@ -3517,6 +3619,13 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
}
}
}
// We should do this after we potentially expand the heap so
// that all the COMMIT events are generated before the end GC
// event, and after we retire the GC alloc regions so that all
// RETIRE events are generated before the end GC event.
_hr_printer.end_gc(false /* full */, (size_t) total_collections());
// We have to do this after we decide whether to expand the heap or not.
g1_policy()->print_heap_transition();
......@@ -3756,10 +3865,8 @@ void G1CollectedHeap::get_gc_alloc_regions() {
} else {
// the region was retained from the last collection
++_gc_alloc_region_counts[ap];
if (G1PrintHeapRegions) {
gclog_or_tty->print_cr("new alloc region "HR_FORMAT,
HR_FORMAT_PARAMS(alloc_region));
}
_hr_printer.reuse(alloc_region);
}
if (alloc_region != NULL) {
......@@ -4132,11 +4239,7 @@ void G1CollectedHeap::handle_evacuation_failure_common(oop old, markOop m) {
HeapRegion* r = heap_region_containing(old);
if (!r->evacuation_failed()) {
r->set_evacuation_failed(true);
if (G1PrintHeapRegions) {
gclog_or_tty->print("overflow in heap region "PTR_FORMAT" "
"["PTR_FORMAT","PTR_FORMAT")\n",
r, r->bottom(), r->end());
}
_hr_printer.evac_failure(r);
}
push_on_evac_failure_scan_stack(old);
......@@ -4197,6 +4300,7 @@ void G1CollectedHeap::retire_alloc_region(HeapRegion* alloc_region,
// Now we can do the post-GC stuff on the region.
alloc_region->note_end_of_copying();
g1_policy()->record_after_bytes(alloc_region->used());
_hr_printer.retire(alloc_region);
}
HeapWord*
......@@ -5466,12 +5570,14 @@ HeapRegion* G1CollectedHeap::new_mutator_alloc_region(size_t word_size,
assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */);
assert(!force || g1_policy()->can_expand_young_list(),
"if force is true we should be able to expand the young list");
if (force || !g1_policy()->is_young_list_full()) {
bool young_list_full = g1_policy()->is_young_list_full();
if (force || !young_list_full) {
HeapRegion* new_alloc_region = new_region(word_size,
false /* do_expand */);
if (new_alloc_region != NULL) {
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;
}
......@@ -5486,6 +5592,7 @@ void G1CollectedHeap::retire_mutator_alloc_region(HeapRegion* alloc_region,
g1_policy()->add_region_to_incremental_cset_lhs(alloc_region);
_summary_bytes_used += allocated_bytes;
_hr_printer.retire(alloc_region);
}
HeapRegion* MutatorAllocRegion::allocate_new_region(size_t word_size,
......
......@@ -27,6 +27,7 @@
#include "gc_implementation/g1/concurrentMark.hpp"
#include "gc_implementation/g1/g1AllocRegion.hpp"
#include "gc_implementation/g1/g1HRPrinter.hpp"
#include "gc_implementation/g1/g1RemSet.hpp"
#include "gc_implementation/g1/g1MonitoringSupport.hpp"
#include "gc_implementation/g1/heapRegionSeq.hpp"
......@@ -298,6 +299,8 @@ private:
size_t* _surviving_young_words;
G1HRPrinter _hr_printer;
void setup_surviving_young_words();
void update_surviving_young_words(size_t* surv_young_words);
void cleanup_surviving_young_words();
......@@ -635,6 +638,8 @@ public:
return _full_collections_completed;
}
G1HRPrinter* hr_printer() { return &_hr_printer; }
protected:
// Shrink the garbage-first heap by at most the given size (in bytes!).
......
......@@ -2638,11 +2638,6 @@ add_to_collection_set(HeapRegion* hr) {
assert(_inc_cset_build_state == Active, "Precondition");
assert(!hr->is_young(), "non-incremental add of young region");
if (G1PrintHeapRegions) {
gclog_or_tty->print_cr("added region to cset "HR_FORMAT,
HR_FORMAT_PARAMS(hr));
}
if (_g1->mark_in_progress())
_g1->concurrent_mark()->registerCSetRegion(hr);
......@@ -2808,11 +2803,6 @@ void G1CollectorPolicy::add_region_to_incremental_cset_rhs(HeapRegion* hr) {
_inc_cset_tail->set_next_in_collection_set(hr);
}
_inc_cset_tail = hr;
if (G1PrintHeapRegions) {
gclog_or_tty->print_cr(" added region to incremental cset (RHS) "HR_FORMAT,
HR_FORMAT_PARAMS(hr));
}
}
// Add the region to the LHS of the incremental cset
......@@ -2830,11 +2820,6 @@ void G1CollectorPolicy::add_region_to_incremental_cset_lhs(HeapRegion* hr) {
_inc_cset_tail = hr;
}
_inc_cset_head = hr;
if (G1PrintHeapRegions) {
gclog_or_tty->print_cr(" added region to incremental cset (LHS) "HR_FORMAT,
HR_FORMAT_PARAMS(hr));
}
}
#ifndef PRODUCT
......
/*
* 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/g1HRPrinter.hpp"
#include "gc_implementation/g1/heapRegion.hpp"
#include "utilities/ostream.hpp"
const char* G1HRPrinter::action_name(ActionType action) {
switch(action) {
case Alloc: return "ALLOC";
case AllocForce: return "ALLOC-FORCE";
case Retire: return "RETIRE";
case Reuse: return "REUSE";
case CSet: return "CSET";
case EvacFailure: return "EVAC-FAILURE";
case Cleanup: return "CLEANUP";
case PostCompaction: return "POST-COMPACTION";
case Commit: return "COMMIT";
case Uncommit: return "UNCOMMIT";
default: ShouldNotReachHere();
}
// trying to keep the Windows compiler happy
return NULL;
}
const char* G1HRPrinter::region_type_name(RegionType type) {
switch (type) {
case Unset: return NULL;
case Eden: return "Eden";
case Survivor: return "Survivor";
case Old: return "Old";
case SingleHumongous: return "SingleH";
case StartsHumongous: return "StartsH";
case ContinuesHumongous: return "ContinuesH";
default: ShouldNotReachHere();
}
// trying to keep the Windows compiler happy
return NULL;
}
const char* G1HRPrinter::phase_name(PhaseType phase) {
switch (phase) {
case StartGC: return "StartGC";
case EndGC: return "EndGC";
case StartFullGC: return "StartFullGC";
case EndFullGC: return "EndFullGC";
default: ShouldNotReachHere();
}
// trying to keep the Windows compiler happy
return NULL;
}
#define G1HR_PREFIX " G1HR"
void G1HRPrinter::print(ActionType action, RegionType type,
HeapRegion* hr, HeapWord* top) {
const char* action_str = action_name(action);
const char* type_str = region_type_name(type);
HeapWord* bottom = hr->bottom();
if (type_str != NULL) {
if (top != NULL) {
gclog_or_tty->print_cr(G1HR_PREFIX" %s(%s) "PTR_FORMAT" "PTR_FORMAT,
action_str, type_str, bottom, top);
} else {
gclog_or_tty->print_cr(G1HR_PREFIX" %s(%s) "PTR_FORMAT,
action_str, type_str, bottom);
}
} else {
if (top != NULL) {
gclog_or_tty->print_cr(G1HR_PREFIX" %s "PTR_FORMAT" "PTR_FORMAT,
action_str, bottom, top);
} else {
gclog_or_tty->print_cr(G1HR_PREFIX" %s "PTR_FORMAT,
action_str, bottom);
}
}
}
void G1HRPrinter::print(ActionType action, HeapWord* bottom, HeapWord* end) {
const char* action_str = action_name(action);
gclog_or_tty->print_cr(G1HR_PREFIX" %s ["PTR_FORMAT","PTR_FORMAT"]",
action_str, bottom, end);
}
void G1HRPrinter::print(PhaseType phase, size_t phase_num) {
const char* phase_str = phase_name(phase);
gclog_or_tty->print_cr(G1HR_PREFIX" #%s "SIZE_FORMAT, phase_str, phase_num);
}
/*
* 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_G1HRPRINTER_HPP
#define SHARE_VM_GC_IMPLEMENTATION_G1_G1HRPRINTER_HPP
#include "memory/allocation.hpp"
#include "gc_implementation/g1/heapRegion.hpp"
#define SKIP_RETIRED_FULL_REGIONS 1
class G1HRPrinter VALUE_OBJ_CLASS_SPEC {
public:
typedef enum {
Alloc,
AllocForce,
Retire,
Reuse,
CSet,
EvacFailure,
Cleanup,
PostCompaction,
Commit,
Uncommit
} ActionType;
typedef enum {
Unset,
Eden,
Survivor,
Old,
SingleHumongous,
StartsHumongous,
ContinuesHumongous
} RegionType;
typedef enum {
StartGC,
EndGC,
StartFullGC,
EndFullGC
} PhaseType;
private:
bool _active;
static const char* action_name(ActionType action);
static const char* region_type_name(RegionType type);
static const char* phase_name(PhaseType phase);
// Print an action event. This version is used in most scenarios and
// only prints the region's bottom. The parameters type and top are
// optional (the "not set" values are Unset and NULL).
static void print(ActionType action, RegionType type,
HeapRegion* hr, HeapWord* top);
// Print an action event. This version prints both the region's
// bottom and end. Used for Commit / Uncommit events.
static void print(ActionType action, HeapWord* bottom, HeapWord* end);
// Print a phase event.
static void print(PhaseType phase, size_t phase_num);
public:
// In some places we iterate over a list in order to generate output
// for the list's elements. By exposing this we can avoid this
// iteration if the printer is not active.
const bool is_active() { return _active; }
// Have to set this explicitly as we have to do this during the
// heap's initialize() method, not in the constructor.
void set_active(bool active) { _active = active; }
// The methods below are convenient wrappers for the print() methods.
void alloc(HeapRegion* hr, RegionType type, bool force = false) {
if (is_active()) {
print((!force) ? Alloc : AllocForce, type, hr, NULL);
}
}
void alloc(RegionType type, HeapRegion* hr, HeapWord* top) {
if (is_active()) {
print(Alloc, type, hr, top);
}
}
void retire(HeapRegion* hr) {
if (is_active()) {
if (!SKIP_RETIRED_FULL_REGIONS || hr->top() < hr->end()) {
print(Retire, Unset, hr, hr->top());
}
}
}
void reuse(HeapRegion* hr) {
if (is_active()) {
print(Reuse, Unset, hr, NULL);
}
}
void cset(HeapRegion* hr) {
if (is_active()) {
print(CSet, Unset, hr, NULL);
}
}
void evac_failure(HeapRegion* hr) {
if (is_active()) {
print(EvacFailure, Unset, hr, NULL);
}
}
void cleanup(HeapRegion* hr) {
if (is_active()) {
print(Cleanup, Unset, hr, NULL);
}
}
void post_compaction(HeapRegion* hr, RegionType type) {
if (is_active()) {
print(PostCompaction, type, hr, hr->top());
}
}
void commit(HeapWord* bottom, HeapWord* end) {
if (is_active()) {
print(Commit, bottom, end);
}
}
void uncommit(HeapWord* bottom, HeapWord* end) {
if (is_active()) {
print(Uncommit, bottom, end);
}
}
void start_gc(bool full, size_t gc_num) {
if (is_active()) {
if (!full) {
print(StartGC, gc_num);
} else {
print(StartFullGC, gc_num);
}
}
}
void end_gc(bool full, size_t gc_num) {
if (is_active()) {
if (!full) {
print(EndGC, gc_num);
} else {
print(EndFullGC, gc_num);
}
}
}
G1HRPrinter() : _active(false) { }
};
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1HRPRINTER_HPP
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册