src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp
changeset 59233 bd9dba789919
parent 58508 d6058bd73982
child 59290 97d13893ec3c
equal deleted inserted replaced
59232:d4ddf19c2624 59233:bd9dba789919
    39 #include "runtime/mutexLocker.hpp"
    39 #include "runtime/mutexLocker.hpp"
    40 #include "runtime/os.hpp"
    40 #include "runtime/os.hpp"
    41 #include "runtime/safepoint.hpp"
    41 #include "runtime/safepoint.hpp"
    42 #include "runtime/thread.inline.hpp"
    42 #include "runtime/thread.inline.hpp"
    43 #include "runtime/threadSMR.hpp"
    43 #include "runtime/threadSMR.hpp"
       
    44 #include "utilities/quickSort.hpp"
    44 
    45 
    45 G1DirtyCardQueue::G1DirtyCardQueue(G1DirtyCardQueueSet* qset) :
    46 G1DirtyCardQueue::G1DirtyCardQueue(G1DirtyCardQueueSet* qset) :
    46   // Dirty card queues are always active, so we create them with their
    47   // Dirty card queues are always active, so we create them with their
    47   // active field set to true.
    48   // active field set to true.
    48   PtrQueue(qset, true /* active */)
    49   PtrQueue(qset, true /* active */)
   224   _completed_buffers_tail = NULL;
   225   _completed_buffers_tail = NULL;
   225   _num_cards = 0;
   226   _num_cards = 0;
   226   return result;
   227   return result;
   227 }
   228 }
   228 
   229 
       
   230 class G1RefineBufferedCards : public StackObj {
       
   231   BufferNode* const _node;
       
   232   CardTable::CardValue** const _node_buffer;
       
   233   const size_t _node_buffer_size;
       
   234   const uint _worker_id;
       
   235   size_t* _total_refined_cards;
       
   236   G1RemSet* const _g1rs;
       
   237 
       
   238   static inline int compare_card(const CardTable::CardValue* p1,
       
   239                                  const CardTable::CardValue* p2) {
       
   240     return p2 - p1;
       
   241   }
       
   242 
       
   243   // Sorts the cards from start_index to _node_buffer_size in *decreasing*
       
   244   // address order. Tests showed that this order is preferable to not sorting
       
   245   // or increasing address order.
       
   246   void sort_cards(size_t start_index) {
       
   247     QuickSort::sort(&_node_buffer[start_index],
       
   248                     _node_buffer_size - start_index,
       
   249                     compare_card,
       
   250                     false);
       
   251   }
       
   252 
       
   253   // Returns the index to the first clean card in the buffer.
       
   254   size_t clean_cards() {
       
   255     const size_t start = _node->index();
       
   256     assert(start <= _node_buffer_size, "invariant");
       
   257 
       
   258     // Two-fingered compaction algorithm similar to the filtering mechanism in
       
   259     // SATBMarkQueue. The main difference is that clean_card_before_refine()
       
   260     // could change the buffer element in-place.
       
   261     // We don't check for SuspendibleThreadSet::should_yield(), because
       
   262     // cleaning and redirtying the cards is fast.
       
   263     CardTable::CardValue** src = &_node_buffer[start];
       
   264     CardTable::CardValue** dst = &_node_buffer[_node_buffer_size];
       
   265     assert(src <= dst, "invariant");
       
   266     for ( ; src < dst; ++src) {
       
   267       // Search low to high for a card to keep.
       
   268       if (_g1rs->clean_card_before_refine(src)) {
       
   269         // Found keeper.  Search high to low for a card to discard.
       
   270         while (src < --dst) {
       
   271           if (!_g1rs->clean_card_before_refine(dst)) {
       
   272             *dst = *src;         // Replace discard with keeper.
       
   273             break;
       
   274           }
       
   275         }
       
   276         // If discard search failed (src == dst), the outer loop will also end.
       
   277       }
       
   278     }
       
   279 
       
   280     // dst points to the first retained clean card, or the end of the buffer
       
   281     // if all the cards were discarded.
       
   282     const size_t first_clean = dst - _node_buffer;
       
   283     assert(first_clean >= start && first_clean <= _node_buffer_size, "invariant");
       
   284     // Discarded cards are considered as refined.
       
   285     *_total_refined_cards += first_clean - start;
       
   286     return first_clean;
       
   287   }
       
   288 
       
   289   bool refine_cleaned_cards(size_t start_index) {
       
   290     bool result = true;
       
   291     size_t i = start_index;
       
   292     for ( ; i < _node_buffer_size; ++i) {
       
   293       if (SuspendibleThreadSet::should_yield()) {
       
   294         redirty_unrefined_cards(i);
       
   295         result = false;
       
   296         break;
       
   297       }
       
   298       _g1rs->refine_card_concurrently(_node_buffer[i], _worker_id);
       
   299     }
       
   300     _node->set_index(i);
       
   301     *_total_refined_cards += i - start_index;
       
   302     return result;
       
   303   }
       
   304 
       
   305   void redirty_unrefined_cards(size_t start) {
       
   306     for ( ; start < _node_buffer_size; ++start) {
       
   307       *_node_buffer[start] = G1CardTable::dirty_card_val();
       
   308     }
       
   309   }
       
   310 
       
   311 public:
       
   312   G1RefineBufferedCards(BufferNode* node,
       
   313                         size_t node_buffer_size,
       
   314                         uint worker_id,
       
   315                         size_t* total_refined_cards) :
       
   316     _node(node),
       
   317     _node_buffer(reinterpret_cast<CardTable::CardValue**>(BufferNode::make_buffer_from_node(node))),
       
   318     _node_buffer_size(node_buffer_size),
       
   319     _worker_id(worker_id),
       
   320     _total_refined_cards(total_refined_cards),
       
   321     _g1rs(G1CollectedHeap::heap()->rem_set()) {}
       
   322 
       
   323   bool refine() {
       
   324     size_t first_clean_index = clean_cards();
       
   325     if (first_clean_index == _node_buffer_size) {
       
   326       _node->set_index(first_clean_index);
       
   327       return true;
       
   328     }
       
   329     // This fence serves two purposes. First, the cards must be cleaned
       
   330     // before processing the contents. Second, we can't proceed with
       
   331     // processing a region until after the read of the region's top in
       
   332     // collect_and_clean_cards(), for synchronization with possibly concurrent
       
   333     // humongous object allocation (see comment at the StoreStore fence before
       
   334     // setting the regions' tops in humongous allocation path).
       
   335     // It's okay that reading region's top and reading region's type were racy
       
   336     // wrto each other. We need both set, in any order, to proceed.
       
   337     OrderAccess::fence();
       
   338     sort_cards(first_clean_index);
       
   339     return refine_cleaned_cards(first_clean_index);
       
   340   }
       
   341 };
       
   342 
   229 bool G1DirtyCardQueueSet::refine_buffer(BufferNode* node,
   343 bool G1DirtyCardQueueSet::refine_buffer(BufferNode* node,
   230                                         uint worker_id,
   344                                         uint worker_id,
   231                                         size_t* total_refined_cards) {
   345                                         size_t* total_refined_cards) {
   232   G1RemSet* rem_set = G1CollectedHeap::heap()->rem_set();
   346   G1RefineBufferedCards buffered_cards(node,
   233   size_t size = buffer_size();
   347                                        buffer_size(),
   234   void** buffer = BufferNode::make_buffer_from_node(node);
   348                                        worker_id,
   235   size_t i = node->index();
   349                                        total_refined_cards);
   236   assert(i <= size, "invariant");
   350   return buffered_cards.refine();
   237   for ( ; (i < size) && !SuspendibleThreadSet::should_yield(); ++i) {
       
   238     CardTable::CardValue* cp = static_cast<CardTable::CardValue*>(buffer[i]);
       
   239     rem_set->refine_card_concurrently(cp, worker_id);
       
   240   }
       
   241   *total_refined_cards += (i - node->index());
       
   242   node->set_index(i);
       
   243   return i == size;
       
   244 }
   351 }
   245 
   352 
   246 #ifndef ASSERT
   353 #ifndef ASSERT
   247 #define assert_fully_consumed(node, buffer_size)
   354 #define assert_fully_consumed(node, buffer_size)
   248 #else
   355 #else