6882730: G1: parallel heap verification messes up region dump

Fri, 02 Oct 2009 16:20:42 -0400

author
tonyp
date
Fri, 02 Oct 2009 16:20:42 -0400
changeset 1455
ff2402f6a50b
parent 1454
035d2e036a9b
child 1456
1f19207eefc2

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

src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/heapRegion.cpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/heapRegion.hpp file | annotate | diff | comparison | revisions
     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(&not_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(&not_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;

mercurial