RFR (M): 8087198: G1 card refinement: batching, sorting

Kim Barrett kim.barrett at oracle.com
Thu Nov 21 20:35:11 UTC 2019

> On Nov 19, 2019, at 9:26 PM, Man Cao <manc at google.com> wrote:
> Hi all,
> Thanks! I have addressed all comments:
> Full: http://cr.openjdk.java.net/~manc/8087198/webrev.02/
> Incremental: http://cr.openjdk.java.net/~manc/8087198/webrev.01-02.inc/
> I also changed G1RemSet::clean_card_before_refine() to take a "CardValue**"
> parameter instead of "CardValue*&" to make it more obvious that it can
> modify
> the card pointer.

Thanks for that change; that seems to have made the code nicer.

This is looking pretty good.  Just a couple of possible improvements
and questions.

 247     QuickSort::sort(&_node_buffer[start_index],
 250                     true);

I *think* a false value for idempotent is better here.

We don't care about reordering of equal values, so there's no
correctness issue either way.  A true value will avoid unnecessary
swaps of equal entries, at the cost of an extra comparison.  The
comparison is very cheap, so if equal entries were somewhat common
that could be a win.  But because of the dirty-card-based filtering, I
think equal entries are uncommon, making the extra comparisons

 289   bool refine_cleaned_cards(size_t start_index) {
 290     for (size_t i = start_index; i < _node_buffer_size; ++i) {
 291       if (SuspendibleThreadSet::should_yield()) {
 292         redirty_unrefined_cards(i);
 293         _node->set_index(i);
 294         return false;
 295       }
 296       _g1rs->refine_card_concurrently(_node_buffer[i], _worker_id);
 297       (*_total_refined_cards)++;

 298     }
 299     _node->set_index(_node_buffer_size);
 300     return true;
 301   }

It would be better to bulk increment *_total_refined_cards at the end,
rather than on each iteration.  Maybe something like this:

bool refine_cleaned_cards(size_t start_index) {
  bool result = true;
  size_t i = start_index;
  for ( ; i < _node_buffer_size; ++i) {
    if (SuspendibleThreadSet::should_yield()) {
      result = false;
    _g1rs->refine_card_concurrently(_node_buffer[i], _worker_id);
  *_total_refined_cards += i - start_index;
  return result;

 321   bool refine() {
 322     size_t first_clean_index = clean_cards();

Is it worth checking whether the cleaned buffer is now empty, skipping
the rest altogether if so?  I don't know how often that actually
happens, and the rest isn't *that* expensive in the empty buffer case.
So I'm going to guess not worth the extra test, but something to consider.


More information about the hotspot-gc-dev mailing list