6819065: G1: eliminate high serial card table clearing time

Tue, 19 May 2009 04:05:31 -0700

author
apetrusenko
date
Tue, 19 May 2009 04:05:31 -0700
changeset 1231
29e7d79232b9
parent 1230
215f81b4d9b3
child 1232
7fd05714f579

6819065: G1: eliminate high serial card table clearing time
Reviewed-by: iveresov, tonyp

src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/g1RemSet.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	Mon May 18 11:52:46 2009 -0700
     1.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Tue May 19 04:05:31 2009 -0700
     1.3 @@ -446,6 +446,59 @@
     1.4    gclog_or_tty->print_cr("");
     1.5  }
     1.6  
     1.7 +void G1CollectedHeap::push_dirty_cards_region(HeapRegion* hr)
     1.8 +{
     1.9 +  // Claim the right to put the region on the dirty cards region list
    1.10 +  // by installing a self pointer.
    1.11 +  HeapRegion* next = hr->get_next_dirty_cards_region();
    1.12 +  if (next == NULL) {
    1.13 +    HeapRegion* res = (HeapRegion*)
    1.14 +      Atomic::cmpxchg_ptr(hr, hr->next_dirty_cards_region_addr(),
    1.15 +                          NULL);
    1.16 +    if (res == NULL) {
    1.17 +      HeapRegion* head;
    1.18 +      do {
    1.19 +        // Put the region to the dirty cards region list.
    1.20 +        head = _dirty_cards_region_list;
    1.21 +        next = (HeapRegion*)
    1.22 +          Atomic::cmpxchg_ptr(hr, &_dirty_cards_region_list, head);
    1.23 +        if (next == head) {
    1.24 +          assert(hr->get_next_dirty_cards_region() == hr,
    1.25 +                 "hr->get_next_dirty_cards_region() != hr");
    1.26 +          if (next == NULL) {
    1.27 +            // The last region in the list points to itself.
    1.28 +            hr->set_next_dirty_cards_region(hr);
    1.29 +          } else {
    1.30 +            hr->set_next_dirty_cards_region(next);
    1.31 +          }
    1.32 +        }
    1.33 +      } while (next != head);
    1.34 +    }
    1.35 +  }
    1.36 +}
    1.37 +
    1.38 +HeapRegion* G1CollectedHeap::pop_dirty_cards_region()
    1.39 +{
    1.40 +  HeapRegion* head;
    1.41 +  HeapRegion* hr;
    1.42 +  do {
    1.43 +    head = _dirty_cards_region_list;
    1.44 +    if (head == NULL) {
    1.45 +      return NULL;
    1.46 +    }
    1.47 +    HeapRegion* new_head = head->get_next_dirty_cards_region();
    1.48 +    if (head == new_head) {
    1.49 +      // The last region.
    1.50 +      new_head = NULL;
    1.51 +    }
    1.52 +    hr = (HeapRegion*)Atomic::cmpxchg_ptr(new_head, &_dirty_cards_region_list,
    1.53 +                                          head);
    1.54 +  } while (hr != head);
    1.55 +  assert(hr != NULL, "invariant");
    1.56 +  hr->set_next_dirty_cards_region(NULL);
    1.57 +  return hr;
    1.58 +}
    1.59 +
    1.60  void G1CollectedHeap::stop_conc_gc_threads() {
    1.61    _cg1r->stop();
    1.62    _czft->stop();
    1.63 @@ -1329,7 +1382,8 @@
    1.64    _gc_time_stamp(0),
    1.65    _surviving_young_words(NULL),
    1.66    _in_cset_fast_test(NULL),
    1.67 -  _in_cset_fast_test_base(NULL) {
    1.68 +  _in_cset_fast_test_base(NULL),
    1.69 +  _dirty_cards_region_list(NULL) {
    1.70    _g1h = this; // To catch bugs.
    1.71    if (_process_strong_tasks == NULL || !_process_strong_tasks->valid()) {
    1.72      vm_exit_during_initialization("Failed necessary allocation.");
    1.73 @@ -4691,15 +4745,58 @@
    1.74    }
    1.75  }
    1.76  
    1.77 +
    1.78 +class G1ParCleanupCTTask : public AbstractGangTask {
    1.79 +  CardTableModRefBS* _ct_bs;
    1.80 +  G1CollectedHeap* _g1h;
    1.81 +public:
    1.82 +  G1ParCleanupCTTask(CardTableModRefBS* ct_bs,
    1.83 +                     G1CollectedHeap* g1h) :
    1.84 +    AbstractGangTask("G1 Par Cleanup CT Task"),
    1.85 +    _ct_bs(ct_bs),
    1.86 +    _g1h(g1h)
    1.87 +  { }
    1.88 +
    1.89 +  void work(int i) {
    1.90 +    HeapRegion* r;
    1.91 +    while (r = _g1h->pop_dirty_cards_region()) {
    1.92 +      clear_cards(r);
    1.93 +    }
    1.94 +  }
    1.95 +  void clear_cards(HeapRegion* r) {
    1.96 +    // Cards for Survivor and Scan-Only regions will be dirtied later.
    1.97 +    if (!r->is_scan_only() && !r->is_survivor()) {
    1.98 +      _ct_bs->clear(MemRegion(r->bottom(), r->end()));
    1.99 +    }
   1.100 +  }
   1.101 +};
   1.102 +
   1.103 +
   1.104  void G1CollectedHeap::cleanUpCardTable() {
   1.105    CardTableModRefBS* ct_bs = (CardTableModRefBS*) (barrier_set());
   1.106    double start = os::elapsedTime();
   1.107  
   1.108 -  ct_bs->clear(_g1_committed);
   1.109 -
   1.110 +  // Iterate over the dirty cards region list.
   1.111 +  G1ParCleanupCTTask cleanup_task(ct_bs, this);
   1.112 +  if (ParallelGCThreads > 0) {
   1.113 +    set_par_threads(workers()->total_workers());
   1.114 +    workers()->run_task(&cleanup_task);
   1.115 +    set_par_threads(0);
   1.116 +  } else {
   1.117 +    while (_dirty_cards_region_list) {
   1.118 +      HeapRegion* r = _dirty_cards_region_list;
   1.119 +      cleanup_task.clear_cards(r);
   1.120 +      _dirty_cards_region_list = r->get_next_dirty_cards_region();
   1.121 +      if (_dirty_cards_region_list == r) {
   1.122 +        // The last region.
   1.123 +        _dirty_cards_region_list = NULL;
   1.124 +      }
   1.125 +      r->set_next_dirty_cards_region(NULL);
   1.126 +    }
   1.127 +  }
   1.128    // now, redirty the cards of the scan-only and survivor regions
   1.129    // (it seemed faster to do it this way, instead of iterating over
   1.130 -  // all regions and then clearing / dirtying as approprite)
   1.131 +  // all regions and then clearing / dirtying as appropriate)
   1.132    dirtyCardsForYoungRegions(ct_bs, _young_list->first_scan_only_region());
   1.133    dirtyCardsForYoungRegions(ct_bs, _young_list->first_survivor_region());
   1.134  
     2.1 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp	Mon May 18 11:52:46 2009 -0700
     2.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp	Tue May 19 04:05:31 2009 -0700
     2.3 @@ -158,6 +158,7 @@
     2.4    friend class RegionSorter;
     2.5    friend class CountRCClosure;
     2.6    friend class EvacPopObjClosure;
     2.7 +  friend class G1ParCleanupCTTask;
     2.8  
     2.9    // Other related classes.
    2.10    friend class G1MarkSweep;
    2.11 @@ -1191,6 +1192,16 @@
    2.12    ConcurrentMark* concurrent_mark() const { return _cm; }
    2.13    ConcurrentG1Refine* concurrent_g1_refine() const { return _cg1r; }
    2.14  
    2.15 +  // The dirty cards region list is used to record a subset of regions
    2.16 +  // whose cards need clearing. The list if populated during the
    2.17 +  // remembered set scanning and drained during the card table
    2.18 +  // cleanup. Although the methods are reentrant, population/draining
    2.19 +  // phases must not overlap. For synchronization purposes the last
    2.20 +  // element on the list points to itself.
    2.21 +  HeapRegion* _dirty_cards_region_list;
    2.22 +  void push_dirty_cards_region(HeapRegion* hr);
    2.23 +  HeapRegion* pop_dirty_cards_region();
    2.24 +
    2.25  public:
    2.26    void stop_conc_gc_threads();
    2.27  
     3.1 --- a/src/share/vm/gc_implementation/g1/g1RemSet.cpp	Mon May 18 11:52:46 2009 -0700
     3.2 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.cpp	Tue May 19 04:05:31 2009 -0700
     3.3 @@ -219,6 +219,7 @@
     3.4      HeapRegionRemSet* hrrs = r->rem_set();
     3.5      if (hrrs->iter_is_complete()) return false; // All done.
     3.6      if (!_try_claimed && !hrrs->claim_iter()) return false;
     3.7 +    _g1h->push_dirty_cards_region(r);
     3.8      // If we didn't return above, then
     3.9      //   _try_claimed || r->claim_iter()
    3.10      // is true: either we're supposed to work on claimed-but-not-complete
    3.11 @@ -242,6 +243,10 @@
    3.12        assert(card_region != NULL, "Yielding cards not in the heap?");
    3.13        _cards++;
    3.14  
    3.15 +      if (!card_region->is_on_dirty_cards_region_list()) {
    3.16 +        _g1h->push_dirty_cards_region(card_region);
    3.17 +      }
    3.18 +
    3.19         // If the card is dirty, then we will scan it during updateRS.
    3.20        if (!card_region->in_collection_set() && !_ct_bs->is_card_dirty(card_index)) {
    3.21            if (!_ct_bs->is_card_claimed(card_index) && _ct_bs->claim_card(card_index)) {
     4.1 --- a/src/share/vm/gc_implementation/g1/heapRegion.cpp	Mon May 18 11:52:46 2009 -0700
     4.2 +++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp	Tue May 19 04:05:31 2009 -0700
     4.3 @@ -351,6 +351,7 @@
     4.4      _claimed(InitialClaimValue), _evacuation_failed(false),
     4.5      _prev_marked_bytes(0), _next_marked_bytes(0), _sort_index(-1),
     4.6      _young_type(NotYoung), _next_young_region(NULL),
     4.7 +    _next_dirty_cards_region(NULL),
     4.8      _young_index_in_cset(-1), _surv_rate_group(NULL), _age_index(-1),
     4.9      _rem_set(NULL), _zfs(NotZeroFilled)
    4.10  {
     5.1 --- a/src/share/vm/gc_implementation/g1/heapRegion.hpp	Mon May 18 11:52:46 2009 -0700
     5.2 +++ b/src/share/vm/gc_implementation/g1/heapRegion.hpp	Tue May 19 04:05:31 2009 -0700
     5.3 @@ -227,6 +227,9 @@
     5.4    // next region in the young "generation" region set
     5.5    HeapRegion* _next_young_region;
     5.6  
     5.7 +  // Next region whose cards need cleaning
     5.8 +  HeapRegion* _next_dirty_cards_region;
     5.9 +
    5.10    // For parallel heapRegion traversal.
    5.11    jint _claimed;
    5.12  
    5.13 @@ -468,6 +471,11 @@
    5.14      _next_young_region = hr;
    5.15    }
    5.16  
    5.17 +  HeapRegion* get_next_dirty_cards_region() const { return _next_dirty_cards_region; }
    5.18 +  HeapRegion** next_dirty_cards_region_addr() { return &_next_dirty_cards_region; }
    5.19 +  void set_next_dirty_cards_region(HeapRegion* hr) { _next_dirty_cards_region = hr; }
    5.20 +  bool is_on_dirty_cards_region_list() const { return get_next_dirty_cards_region() != NULL; }
    5.21 +
    5.22    // Allows logical separation between objects allocated before and after.
    5.23    void save_marks();
    5.24  

mercurial