Fri, 02 Oct 2009 16:20:42 -0400
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
1.1 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Fri Oct 02 16:12:07 2009 -0400 1.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Fri Oct 02 16:20:42 2009 -0400 1.3 @@ -2210,40 +2210,58 @@ 1.4 bool _allow_dirty; 1.5 bool _par; 1.6 bool _use_prev_marking; 1.7 + bool _failures; 1.8 public: 1.9 // use_prev_marking == true -> use "prev" marking information, 1.10 // use_prev_marking == false -> use "next" marking information 1.11 VerifyRegionClosure(bool allow_dirty, bool par, bool use_prev_marking) 1.12 : _allow_dirty(allow_dirty), 1.13 _par(par), 1.14 - _use_prev_marking(use_prev_marking) {} 1.15 + _use_prev_marking(use_prev_marking), 1.16 + _failures(false) {} 1.17 + 1.18 + bool failures() { 1.19 + return _failures; 1.20 + } 1.21 1.22 bool doHeapRegion(HeapRegion* r) { 1.23 guarantee(_par || r->claim_value() == HeapRegion::InitialClaimValue, 1.24 "Should be unclaimed at verify points."); 1.25 if (!r->continuesHumongous()) { 1.26 - VerifyObjsInRegionClosure not_dead_yet_cl(r, _use_prev_marking); 1.27 - r->verify(_allow_dirty, _use_prev_marking); 1.28 - r->object_iterate(¬_dead_yet_cl); 1.29 - guarantee(r->max_live_bytes() >= not_dead_yet_cl.live_bytes(), 1.30 - "More live objects than counted in last complete marking."); 1.31 + bool failures = false; 1.32 + r->verify(_allow_dirty, _use_prev_marking, &failures); 1.33 + if (failures) { 1.34 + _failures = true; 1.35 + } else { 1.36 + VerifyObjsInRegionClosure not_dead_yet_cl(r, _use_prev_marking); 1.37 + r->object_iterate(¬_dead_yet_cl); 1.38 + if (r->max_live_bytes() < not_dead_yet_cl.live_bytes()) { 1.39 + gclog_or_tty->print_cr("["PTR_FORMAT","PTR_FORMAT"] " 1.40 + "max_live_bytes "SIZE_FORMAT" " 1.41 + "< calculated "SIZE_FORMAT, 1.42 + r->bottom(), r->end(), 1.43 + r->max_live_bytes(), 1.44 + not_dead_yet_cl.live_bytes()); 1.45 + _failures = true; 1.46 + } 1.47 + } 1.48 } 1.49 - return false; 1.50 + return false; // stop the region iteration if we hit a failure 1.51 } 1.52 }; 1.53 1.54 class VerifyRootsClosure: public OopsInGenClosure { 1.55 private: 1.56 G1CollectedHeap* _g1h; 1.57 + bool _use_prev_marking; 1.58 bool _failures; 1.59 - bool _use_prev_marking; 1.60 public: 1.61 // use_prev_marking == true -> use "prev" marking information, 1.62 // use_prev_marking == false -> use "next" marking information 1.63 VerifyRootsClosure(bool use_prev_marking) : 1.64 _g1h(G1CollectedHeap::heap()), 1.65 - _failures(false), 1.66 - _use_prev_marking(use_prev_marking) { } 1.67 + _use_prev_marking(use_prev_marking), 1.68 + _failures(false) { } 1.69 1.70 bool failures() { return _failures; } 1.71 1.72 @@ -2253,7 +2271,7 @@ 1.73 oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); 1.74 if (_g1h->is_obj_dead_cond(obj, _use_prev_marking)) { 1.75 gclog_or_tty->print_cr("Root location "PTR_FORMAT" " 1.76 - "points to dead obj "PTR_FORMAT, p, (void*) obj); 1.77 + "points to dead obj "PTR_FORMAT, p, (void*) obj); 1.78 obj->print_on(gclog_or_tty); 1.79 _failures = true; 1.80 } 1.81 @@ -2271,6 +2289,7 @@ 1.82 G1CollectedHeap* _g1h; 1.83 bool _allow_dirty; 1.84 bool _use_prev_marking; 1.85 + bool _failures; 1.86 1.87 public: 1.88 // use_prev_marking == true -> use "prev" marking information, 1.89 @@ -2280,13 +2299,21 @@ 1.90 AbstractGangTask("Parallel verify task"), 1.91 _g1h(g1h), 1.92 _allow_dirty(allow_dirty), 1.93 - _use_prev_marking(use_prev_marking) { } 1.94 + _use_prev_marking(use_prev_marking), 1.95 + _failures(false) { } 1.96 + 1.97 + bool failures() { 1.98 + return _failures; 1.99 + } 1.100 1.101 void work(int worker_i) { 1.102 HandleMark hm; 1.103 VerifyRegionClosure blk(_allow_dirty, true, _use_prev_marking); 1.104 _g1h->heap_region_par_iterate_chunked(&blk, worker_i, 1.105 HeapRegion::ParVerifyClaimValue); 1.106 + if (blk.failures()) { 1.107 + _failures = true; 1.108 + } 1.109 } 1.110 }; 1.111 1.112 @@ -2307,6 +2334,7 @@ 1.113 &rootsCl, 1.114 &blobsCl, 1.115 &rootsCl); 1.116 + bool failures = rootsCl.failures(); 1.117 rem_set()->invalidate(perm_gen()->used_region(), false); 1.118 if (!silent) { gclog_or_tty->print("heapRegions "); } 1.119 if (GCParallelVerificationEnabled && ParallelGCThreads > 1) { 1.120 @@ -2318,6 +2346,9 @@ 1.121 set_par_threads(n_workers); 1.122 workers()->run_task(&task); 1.123 set_par_threads(0); 1.124 + if (task.failures()) { 1.125 + failures = true; 1.126 + } 1.127 1.128 assert(check_heap_region_claim_values(HeapRegion::ParVerifyClaimValue), 1.129 "sanity check"); 1.130 @@ -2329,10 +2360,23 @@ 1.131 } else { 1.132 VerifyRegionClosure blk(allow_dirty, false, use_prev_marking); 1.133 _hrs->iterate(&blk); 1.134 + if (blk.failures()) { 1.135 + failures = true; 1.136 + } 1.137 } 1.138 if (!silent) gclog_or_tty->print("remset "); 1.139 rem_set()->verify(); 1.140 - guarantee(!rootsCl.failures(), "should not have had failures"); 1.141 + 1.142 + if (failures) { 1.143 + gclog_or_tty->print_cr("Heap:"); 1.144 + print_on(gclog_or_tty, true /* extended */); 1.145 + gclog_or_tty->print_cr(""); 1.146 + if (VerifyDuringGC && G1VerifyConcMarkPrintReachable) { 1.147 + concurrent_mark()->print_prev_bitmap_reachable(); 1.148 + } 1.149 + gclog_or_tty->flush(); 1.150 + } 1.151 + guarantee(!failures, "there should not have been any failures"); 1.152 } else { 1.153 if (!silent) gclog_or_tty->print("(SKIPPING roots, heapRegions, remset) "); 1.154 } 1.155 @@ -2374,6 +2418,7 @@ 1.156 st->cr(); 1.157 perm()->as_gen()->print_on(st); 1.158 if (extended) { 1.159 + st->cr(); 1.160 print_on_extended(st); 1.161 } 1.162 }
2.1 --- a/src/share/vm/gc_implementation/g1/heapRegion.cpp Fri Oct 02 16:12:07 2009 -0400 2.2 +++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp Fri Oct 02 16:20:42 2009 -0400 2.3 @@ -722,12 +722,13 @@ 2.4 st->print(" F"); 2.5 else 2.6 st->print(" "); 2.7 - st->print(" %d", _gc_time_stamp); 2.8 + st->print(" %5d", _gc_time_stamp); 2.9 G1OffsetTableContigSpace::print_on(st); 2.10 } 2.11 2.12 void HeapRegion::verify(bool allow_dirty) const { 2.13 - verify(allow_dirty, /* use_prev_marking */ true); 2.14 + bool dummy = false; 2.15 + verify(allow_dirty, /* use_prev_marking */ true, /* failures */ &dummy); 2.16 } 2.17 2.18 #define OBJ_SAMPLE_INTERVAL 0 2.19 @@ -736,8 +737,11 @@ 2.20 // This really ought to be commoned up into OffsetTableContigSpace somehow. 2.21 // We would need a mechanism to make that code skip dead objects. 2.22 2.23 -void HeapRegion::verify(bool allow_dirty, bool use_prev_marking) const { 2.24 +void HeapRegion::verify(bool allow_dirty, 2.25 + bool use_prev_marking, 2.26 + bool* failures) const { 2.27 G1CollectedHeap* g1 = G1CollectedHeap::heap(); 2.28 + *failures = false; 2.29 HeapWord* p = bottom(); 2.30 HeapWord* prev_p = NULL; 2.31 int objs = 0; 2.32 @@ -746,8 +750,14 @@ 2.33 while (p < top()) { 2.34 size_t size = oop(p)->size(); 2.35 if (blocks == BLOCK_SAMPLE_INTERVAL) { 2.36 - guarantee(p == block_start_const(p + (size/2)), 2.37 - "check offset computation"); 2.38 + HeapWord* res = block_start_const(p + (size/2)); 2.39 + if (p != res) { 2.40 + gclog_or_tty->print_cr("offset computation 1 for "PTR_FORMAT" and " 2.41 + SIZE_FORMAT" returned "PTR_FORMAT, 2.42 + p, size, res); 2.43 + *failures = true; 2.44 + return; 2.45 + } 2.46 blocks = 0; 2.47 } else { 2.48 blocks++; 2.49 @@ -755,11 +765,34 @@ 2.50 if (objs == OBJ_SAMPLE_INTERVAL) { 2.51 oop obj = oop(p); 2.52 if (!g1->is_obj_dead_cond(obj, this, use_prev_marking)) { 2.53 - obj->verify(); 2.54 - vl_cl.set_containing_obj(obj); 2.55 - obj->oop_iterate(&vl_cl); 2.56 - if (G1MaxVerifyFailures >= 0 2.57 - && vl_cl.n_failures() >= G1MaxVerifyFailures) break; 2.58 + if (obj->is_oop()) { 2.59 + klassOop klass = obj->klass(); 2.60 + if (!klass->is_perm()) { 2.61 + gclog_or_tty->print_cr("klass "PTR_FORMAT" of object "PTR_FORMAT" " 2.62 + "not in perm", klass, obj); 2.63 + *failures = true; 2.64 + return; 2.65 + } else if (!klass->is_klass()) { 2.66 + gclog_or_tty->print_cr("klass "PTR_FORMAT" of object "PTR_FORMAT" " 2.67 + "not a klass", klass, obj); 2.68 + *failures = true; 2.69 + return; 2.70 + } else { 2.71 + vl_cl.set_containing_obj(obj); 2.72 + obj->oop_iterate(&vl_cl); 2.73 + if (vl_cl.failures()) { 2.74 + *failures = true; 2.75 + } 2.76 + if (G1MaxVerifyFailures >= 0 && 2.77 + vl_cl.n_failures() >= G1MaxVerifyFailures) { 2.78 + return; 2.79 + } 2.80 + } 2.81 + } else { 2.82 + gclog_or_tty->print_cr(PTR_FORMAT" no an oop", obj); 2.83 + *failures = true; 2.84 + return; 2.85 + } 2.86 } 2.87 objs = 0; 2.88 } else { 2.89 @@ -771,21 +804,22 @@ 2.90 HeapWord* rend = end(); 2.91 HeapWord* rtop = top(); 2.92 if (rtop < rend) { 2.93 - guarantee(block_start_const(rtop + (rend - rtop) / 2) == rtop, 2.94 - "check offset computation"); 2.95 + HeapWord* res = block_start_const(rtop + (rend - rtop) / 2); 2.96 + if (res != rtop) { 2.97 + gclog_or_tty->print_cr("offset computation 2 for "PTR_FORMAT" and " 2.98 + PTR_FORMAT" returned "PTR_FORMAT, 2.99 + rtop, rend, res); 2.100 + *failures = true; 2.101 + return; 2.102 + } 2.103 } 2.104 - if (vl_cl.failures()) { 2.105 - gclog_or_tty->print_cr("Heap:"); 2.106 - G1CollectedHeap::heap()->print_on(gclog_or_tty, true /* extended */); 2.107 - gclog_or_tty->print_cr(""); 2.108 + 2.109 + if (p != top()) { 2.110 + gclog_or_tty->print_cr("end of last object "PTR_FORMAT" " 2.111 + "does not match top "PTR_FORMAT, p, top()); 2.112 + *failures = true; 2.113 + return; 2.114 } 2.115 - if (VerifyDuringGC && 2.116 - G1VerifyConcMarkPrintReachable && 2.117 - vl_cl.failures()) { 2.118 - g1->concurrent_mark()->print_prev_bitmap_reachable(); 2.119 - } 2.120 - guarantee(!vl_cl.failures(), "region verification failed"); 2.121 - guarantee(p == top(), "end of last object must match end of space"); 2.122 } 2.123 2.124 // G1OffsetTableContigSpace code; copied from space.cpp. Hope this can go
3.1 --- a/src/share/vm/gc_implementation/g1/heapRegion.hpp Fri Oct 02 16:12:07 2009 -0400 3.2 +++ b/src/share/vm/gc_implementation/g1/heapRegion.hpp Fri Oct 02 16:20:42 2009 -0400 3.3 @@ -798,7 +798,7 @@ 3.4 // use_prev_marking == true. Currently, there is only one case where 3.5 // this is called with use_prev_marking == false, which is to verify 3.6 // the "next" marking information at the end of remark. 3.7 - void verify(bool allow_dirty, bool use_prev_marking) const; 3.8 + void verify(bool allow_dirty, bool use_prev_marking, bool *failures) const; 3.9 3.10 // Override; it uses the "prev" marking information 3.11 virtual void verify(bool allow_dirty) const;