提交 7a16a15c 编写于 作者: T tonyp

6882730: G1: parallel heap verification messes up region dump

Summary: It tidies up the G1 heap verification a bit. In particular, when the verification is done in parallel and there is a failure, this is propagated to the top level and the heap is dumped at the end, not by every thread that encounters a failure.
Reviewed-by: johnc, jmasa
上级 510d088c
...@@ -2210,40 +2210,58 @@ private: ...@@ -2210,40 +2210,58 @@ private:
bool _allow_dirty; bool _allow_dirty;
bool _par; bool _par;
bool _use_prev_marking; bool _use_prev_marking;
bool _failures;
public: public:
// use_prev_marking == true -> use "prev" marking information, // use_prev_marking == true -> use "prev" marking information,
// use_prev_marking == false -> use "next" marking information // use_prev_marking == false -> use "next" marking information
VerifyRegionClosure(bool allow_dirty, bool par, bool use_prev_marking) VerifyRegionClosure(bool allow_dirty, bool par, bool use_prev_marking)
: _allow_dirty(allow_dirty), : _allow_dirty(allow_dirty),
_par(par), _par(par),
_use_prev_marking(use_prev_marking) {} _use_prev_marking(use_prev_marking),
_failures(false) {}
bool failures() {
return _failures;
}
bool doHeapRegion(HeapRegion* r) { bool doHeapRegion(HeapRegion* r) {
guarantee(_par || r->claim_value() == HeapRegion::InitialClaimValue, guarantee(_par || r->claim_value() == HeapRegion::InitialClaimValue,
"Should be unclaimed at verify points."); "Should be unclaimed at verify points.");
if (!r->continuesHumongous()) { if (!r->continuesHumongous()) {
VerifyObjsInRegionClosure not_dead_yet_cl(r, _use_prev_marking); bool failures = false;
r->verify(_allow_dirty, _use_prev_marking); r->verify(_allow_dirty, _use_prev_marking, &failures);
r->object_iterate(&not_dead_yet_cl); if (failures) {
guarantee(r->max_live_bytes() >= not_dead_yet_cl.live_bytes(), _failures = true;
"More live objects than counted in last complete marking."); } else {
VerifyObjsInRegionClosure not_dead_yet_cl(r, _use_prev_marking);
r->object_iterate(&not_dead_yet_cl);
if (r->max_live_bytes() < not_dead_yet_cl.live_bytes()) {
gclog_or_tty->print_cr("["PTR_FORMAT","PTR_FORMAT"] "
"max_live_bytes "SIZE_FORMAT" "
"< calculated "SIZE_FORMAT,
r->bottom(), r->end(),
r->max_live_bytes(),
not_dead_yet_cl.live_bytes());
_failures = true;
}
}
} }
return false; return false; // stop the region iteration if we hit a failure
} }
}; };
class VerifyRootsClosure: public OopsInGenClosure { class VerifyRootsClosure: public OopsInGenClosure {
private: private:
G1CollectedHeap* _g1h; G1CollectedHeap* _g1h;
bool _failures;
bool _use_prev_marking; bool _use_prev_marking;
bool _failures;
public: public:
// use_prev_marking == true -> use "prev" marking information, // use_prev_marking == true -> use "prev" marking information,
// use_prev_marking == false -> use "next" marking information // use_prev_marking == false -> use "next" marking information
VerifyRootsClosure(bool use_prev_marking) : VerifyRootsClosure(bool use_prev_marking) :
_g1h(G1CollectedHeap::heap()), _g1h(G1CollectedHeap::heap()),
_failures(false), _use_prev_marking(use_prev_marking),
_use_prev_marking(use_prev_marking) { } _failures(false) { }
bool failures() { return _failures; } bool failures() { return _failures; }
...@@ -2253,7 +2271,7 @@ public: ...@@ -2253,7 +2271,7 @@ public:
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
if (_g1h->is_obj_dead_cond(obj, _use_prev_marking)) { if (_g1h->is_obj_dead_cond(obj, _use_prev_marking)) {
gclog_or_tty->print_cr("Root location "PTR_FORMAT" " gclog_or_tty->print_cr("Root location "PTR_FORMAT" "
"points to dead obj "PTR_FORMAT, p, (void*) obj); "points to dead obj "PTR_FORMAT, p, (void*) obj);
obj->print_on(gclog_or_tty); obj->print_on(gclog_or_tty);
_failures = true; _failures = true;
} }
...@@ -2271,6 +2289,7 @@ private: ...@@ -2271,6 +2289,7 @@ private:
G1CollectedHeap* _g1h; G1CollectedHeap* _g1h;
bool _allow_dirty; bool _allow_dirty;
bool _use_prev_marking; bool _use_prev_marking;
bool _failures;
public: public:
// use_prev_marking == true -> use "prev" marking information, // use_prev_marking == true -> use "prev" marking information,
...@@ -2280,13 +2299,21 @@ public: ...@@ -2280,13 +2299,21 @@ public:
AbstractGangTask("Parallel verify task"), AbstractGangTask("Parallel verify task"),
_g1h(g1h), _g1h(g1h),
_allow_dirty(allow_dirty), _allow_dirty(allow_dirty),
_use_prev_marking(use_prev_marking) { } _use_prev_marking(use_prev_marking),
_failures(false) { }
bool failures() {
return _failures;
}
void work(int worker_i) { void work(int worker_i) {
HandleMark hm; HandleMark hm;
VerifyRegionClosure blk(_allow_dirty, true, _use_prev_marking); VerifyRegionClosure blk(_allow_dirty, true, _use_prev_marking);
_g1h->heap_region_par_iterate_chunked(&blk, worker_i, _g1h->heap_region_par_iterate_chunked(&blk, worker_i,
HeapRegion::ParVerifyClaimValue); HeapRegion::ParVerifyClaimValue);
if (blk.failures()) {
_failures = true;
}
} }
}; };
...@@ -2307,6 +2334,7 @@ void G1CollectedHeap::verify(bool allow_dirty, ...@@ -2307,6 +2334,7 @@ void G1CollectedHeap::verify(bool allow_dirty,
&rootsCl, &rootsCl,
&blobsCl, &blobsCl,
&rootsCl); &rootsCl);
bool failures = rootsCl.failures();
rem_set()->invalidate(perm_gen()->used_region(), false); rem_set()->invalidate(perm_gen()->used_region(), false);
if (!silent) { gclog_or_tty->print("heapRegions "); } if (!silent) { gclog_or_tty->print("heapRegions "); }
if (GCParallelVerificationEnabled && ParallelGCThreads > 1) { if (GCParallelVerificationEnabled && ParallelGCThreads > 1) {
...@@ -2318,6 +2346,9 @@ void G1CollectedHeap::verify(bool allow_dirty, ...@@ -2318,6 +2346,9 @@ void G1CollectedHeap::verify(bool allow_dirty,
set_par_threads(n_workers); set_par_threads(n_workers);
workers()->run_task(&task); workers()->run_task(&task);
set_par_threads(0); set_par_threads(0);
if (task.failures()) {
failures = true;
}
assert(check_heap_region_claim_values(HeapRegion::ParVerifyClaimValue), assert(check_heap_region_claim_values(HeapRegion::ParVerifyClaimValue),
"sanity check"); "sanity check");
...@@ -2329,10 +2360,23 @@ void G1CollectedHeap::verify(bool allow_dirty, ...@@ -2329,10 +2360,23 @@ void G1CollectedHeap::verify(bool allow_dirty,
} else { } else {
VerifyRegionClosure blk(allow_dirty, false, use_prev_marking); VerifyRegionClosure blk(allow_dirty, false, use_prev_marking);
_hrs->iterate(&blk); _hrs->iterate(&blk);
if (blk.failures()) {
failures = true;
}
} }
if (!silent) gclog_or_tty->print("remset "); if (!silent) gclog_or_tty->print("remset ");
rem_set()->verify(); rem_set()->verify();
guarantee(!rootsCl.failures(), "should not have had failures");
if (failures) {
gclog_or_tty->print_cr("Heap:");
print_on(gclog_or_tty, true /* extended */);
gclog_or_tty->print_cr("");
if (VerifyDuringGC && G1VerifyConcMarkPrintReachable) {
concurrent_mark()->print_prev_bitmap_reachable();
}
gclog_or_tty->flush();
}
guarantee(!failures, "there should not have been any failures");
} else { } else {
if (!silent) gclog_or_tty->print("(SKIPPING roots, heapRegions, remset) "); if (!silent) gclog_or_tty->print("(SKIPPING roots, heapRegions, remset) ");
} }
...@@ -2374,6 +2418,7 @@ void G1CollectedHeap::print_on(outputStream* st, bool extended) const { ...@@ -2374,6 +2418,7 @@ void G1CollectedHeap::print_on(outputStream* st, bool extended) const {
st->cr(); st->cr();
perm()->as_gen()->print_on(st); perm()->as_gen()->print_on(st);
if (extended) { if (extended) {
st->cr();
print_on_extended(st); print_on_extended(st);
} }
} }
......
...@@ -722,12 +722,13 @@ void HeapRegion::print_on(outputStream* st) const { ...@@ -722,12 +722,13 @@ void HeapRegion::print_on(outputStream* st) const {
st->print(" F"); st->print(" F");
else else
st->print(" "); st->print(" ");
st->print(" %d", _gc_time_stamp); st->print(" %5d", _gc_time_stamp);
G1OffsetTableContigSpace::print_on(st); G1OffsetTableContigSpace::print_on(st);
} }
void HeapRegion::verify(bool allow_dirty) const { void HeapRegion::verify(bool allow_dirty) const {
verify(allow_dirty, /* use_prev_marking */ true); bool dummy = false;
verify(allow_dirty, /* use_prev_marking */ true, /* failures */ &dummy);
} }
#define OBJ_SAMPLE_INTERVAL 0 #define OBJ_SAMPLE_INTERVAL 0
...@@ -736,8 +737,11 @@ void HeapRegion::verify(bool allow_dirty) const { ...@@ -736,8 +737,11 @@ void HeapRegion::verify(bool allow_dirty) const {
// This really ought to be commoned up into OffsetTableContigSpace somehow. // This really ought to be commoned up into OffsetTableContigSpace somehow.
// We would need a mechanism to make that code skip dead objects. // We would need a mechanism to make that code skip dead objects.
void HeapRegion::verify(bool allow_dirty, bool use_prev_marking) const { void HeapRegion::verify(bool allow_dirty,
bool use_prev_marking,
bool* failures) const {
G1CollectedHeap* g1 = G1CollectedHeap::heap(); G1CollectedHeap* g1 = G1CollectedHeap::heap();
*failures = false;
HeapWord* p = bottom(); HeapWord* p = bottom();
HeapWord* prev_p = NULL; HeapWord* prev_p = NULL;
int objs = 0; int objs = 0;
...@@ -746,8 +750,14 @@ void HeapRegion::verify(bool allow_dirty, bool use_prev_marking) const { ...@@ -746,8 +750,14 @@ void HeapRegion::verify(bool allow_dirty, bool use_prev_marking) const {
while (p < top()) { while (p < top()) {
size_t size = oop(p)->size(); size_t size = oop(p)->size();
if (blocks == BLOCK_SAMPLE_INTERVAL) { if (blocks == BLOCK_SAMPLE_INTERVAL) {
guarantee(p == block_start_const(p + (size/2)), HeapWord* res = block_start_const(p + (size/2));
"check offset computation"); if (p != res) {
gclog_or_tty->print_cr("offset computation 1 for "PTR_FORMAT" and "
SIZE_FORMAT" returned "PTR_FORMAT,
p, size, res);
*failures = true;
return;
}
blocks = 0; blocks = 0;
} else { } else {
blocks++; blocks++;
...@@ -755,11 +765,34 @@ void HeapRegion::verify(bool allow_dirty, bool use_prev_marking) const { ...@@ -755,11 +765,34 @@ void HeapRegion::verify(bool allow_dirty, bool use_prev_marking) const {
if (objs == OBJ_SAMPLE_INTERVAL) { if (objs == OBJ_SAMPLE_INTERVAL) {
oop obj = oop(p); oop obj = oop(p);
if (!g1->is_obj_dead_cond(obj, this, use_prev_marking)) { if (!g1->is_obj_dead_cond(obj, this, use_prev_marking)) {
obj->verify(); if (obj->is_oop()) {
vl_cl.set_containing_obj(obj); klassOop klass = obj->klass();
obj->oop_iterate(&vl_cl); if (!klass->is_perm()) {
if (G1MaxVerifyFailures >= 0 gclog_or_tty->print_cr("klass "PTR_FORMAT" of object "PTR_FORMAT" "
&& vl_cl.n_failures() >= G1MaxVerifyFailures) break; "not in perm", klass, obj);
*failures = true;
return;
} else if (!klass->is_klass()) {
gclog_or_tty->print_cr("klass "PTR_FORMAT" of object "PTR_FORMAT" "
"not a klass", klass, obj);
*failures = true;
return;
} else {
vl_cl.set_containing_obj(obj);
obj->oop_iterate(&vl_cl);
if (vl_cl.failures()) {
*failures = true;
}
if (G1MaxVerifyFailures >= 0 &&
vl_cl.n_failures() >= G1MaxVerifyFailures) {
return;
}
}
} else {
gclog_or_tty->print_cr(PTR_FORMAT" no an oop", obj);
*failures = true;
return;
}
} }
objs = 0; objs = 0;
} else { } else {
...@@ -771,21 +804,22 @@ void HeapRegion::verify(bool allow_dirty, bool use_prev_marking) const { ...@@ -771,21 +804,22 @@ void HeapRegion::verify(bool allow_dirty, bool use_prev_marking) const {
HeapWord* rend = end(); HeapWord* rend = end();
HeapWord* rtop = top(); HeapWord* rtop = top();
if (rtop < rend) { if (rtop < rend) {
guarantee(block_start_const(rtop + (rend - rtop) / 2) == rtop, HeapWord* res = block_start_const(rtop + (rend - rtop) / 2);
"check offset computation"); if (res != rtop) {
} gclog_or_tty->print_cr("offset computation 2 for "PTR_FORMAT" and "
if (vl_cl.failures()) { PTR_FORMAT" returned "PTR_FORMAT,
gclog_or_tty->print_cr("Heap:"); rtop, rend, res);
G1CollectedHeap::heap()->print_on(gclog_or_tty, true /* extended */); *failures = true;
gclog_or_tty->print_cr(""); return;
}
} }
if (VerifyDuringGC &&
G1VerifyConcMarkPrintReachable && if (p != top()) {
vl_cl.failures()) { gclog_or_tty->print_cr("end of last object "PTR_FORMAT" "
g1->concurrent_mark()->print_prev_bitmap_reachable(); "does not match top "PTR_FORMAT, p, top());
*failures = true;
return;
} }
guarantee(!vl_cl.failures(), "region verification failed");
guarantee(p == top(), "end of last object must match end of space");
} }
// G1OffsetTableContigSpace code; copied from space.cpp. Hope this can go // G1OffsetTableContigSpace code; copied from space.cpp. Hope this can go
......
...@@ -798,7 +798,7 @@ class HeapRegion: public G1OffsetTableContigSpace { ...@@ -798,7 +798,7 @@ class HeapRegion: public G1OffsetTableContigSpace {
// use_prev_marking == true. Currently, there is only one case where // use_prev_marking == true. Currently, there is only one case where
// this is called with use_prev_marking == false, which is to verify // this is called with use_prev_marking == false, which is to verify
// the "next" marking information at the end of remark. // the "next" marking information at the end of remark.
void verify(bool allow_dirty, bool use_prev_marking) const; void verify(bool allow_dirty, bool use_prev_marking, bool *failures) const;
// Override; it uses the "prev" marking information // Override; it uses the "prev" marking information
virtual void verify(bool allow_dirty) const; virtual void verify(bool allow_dirty) const;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册