src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp

Fri, 10 Oct 2014 15:51:58 +0200

author
tschatzl
date
Fri, 10 Oct 2014 15:51:58 +0200
changeset 7257
e7d0505c8a30
parent 7051
1f1d373cd044
child 7535
7ae4e26cb1e0
permissions
-rw-r--r--

8059758: Footprint regressions with JDK-8038423
Summary: Changes in JDK-8038423 always initialize (zero out) virtual memory used for auxiliary data structures. This causes a footprint regression for G1 in startup benchmarks. This is because they do not touch that memory at all, so the operating system does not actually commit these pages. The fix is to, if the initialization value of the data structures matches the default value of just committed memory (=0), do not do anything.
Reviewed-by: jwilhelm, brutisso

     1 /*
     2  * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     8  *
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    12  * version 2 for more details (a copy is included in the LICENSE file that
    13  * accompanied this code).
    14  *
    15  * You should have received a copy of the GNU General Public License version
    16  * 2 along with this work; if not, write to the Free Software Foundation,
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    18  *
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    22  *
    23  */
    25 #include "precompiled.hpp"
    26 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
    27 #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
    28 #include "gc_implementation/g1/heapRegion.hpp"
    29 #include "gc_implementation/g1/satbQueue.hpp"
    30 #include "runtime/mutexLocker.hpp"
    31 #include "runtime/orderAccess.inline.hpp"
    32 #include "runtime/thread.inline.hpp"
    34 G1SATBCardTableModRefBS::G1SATBCardTableModRefBS(MemRegion whole_heap,
    35                                                  int max_covered_regions) :
    36     CardTableModRefBSForCTRS(whole_heap, max_covered_regions)
    37 {
    38   _kind = G1SATBCT;
    39 }
    41 void G1SATBCardTableModRefBS::enqueue(oop pre_val) {
    42   // Nulls should have been already filtered.
    43   assert(pre_val->is_oop(true), "Error");
    45   if (!JavaThread::satb_mark_queue_set().is_active()) return;
    46   Thread* thr = Thread::current();
    47   if (thr->is_Java_thread()) {
    48     JavaThread* jt = (JavaThread*)thr;
    49     jt->satb_mark_queue().enqueue(pre_val);
    50   } else {
    51     MutexLockerEx x(Shared_SATB_Q_lock, Mutex::_no_safepoint_check_flag);
    52     JavaThread::satb_mark_queue_set().shared_satb_queue()->enqueue(pre_val);
    53   }
    54 }
    56 template <class T> void
    57 G1SATBCardTableModRefBS::write_ref_array_pre_work(T* dst, int count) {
    58   if (!JavaThread::satb_mark_queue_set().is_active()) return;
    59   T* elem_ptr = dst;
    60   for (int i = 0; i < count; i++, elem_ptr++) {
    61     T heap_oop = oopDesc::load_heap_oop(elem_ptr);
    62     if (!oopDesc::is_null(heap_oop)) {
    63       enqueue(oopDesc::decode_heap_oop_not_null(heap_oop));
    64     }
    65   }
    66 }
    68 void G1SATBCardTableModRefBS::write_ref_array_pre(oop* dst, int count, bool dest_uninitialized) {
    69   if (!dest_uninitialized) {
    70     write_ref_array_pre_work(dst, count);
    71   }
    72 }
    73 void G1SATBCardTableModRefBS::write_ref_array_pre(narrowOop* dst, int count, bool dest_uninitialized) {
    74   if (!dest_uninitialized) {
    75     write_ref_array_pre_work(dst, count);
    76   }
    77 }
    79 bool G1SATBCardTableModRefBS::mark_card_deferred(size_t card_index) {
    80   jbyte val = _byte_map[card_index];
    81   // It's already processed
    82   if ((val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val()) {
    83     return false;
    84   }
    86   if  (val == g1_young_gen) {
    87     // the card is for a young gen region. We don't need to keep track of all pointers into young
    88     return false;
    89   }
    91   // Cached bit can be installed either on a clean card or on a claimed card.
    92   jbyte new_val = val;
    93   if (val == clean_card_val()) {
    94     new_val = (jbyte)deferred_card_val();
    95   } else {
    96     if (val & claimed_card_val()) {
    97       new_val = val | (jbyte)deferred_card_val();
    98     }
    99   }
   100   if (new_val != val) {
   101     Atomic::cmpxchg(new_val, &_byte_map[card_index], val);
   102   }
   103   return true;
   104 }
   106 void G1SATBCardTableModRefBS::g1_mark_as_young(const MemRegion& mr) {
   107   jbyte *const first = byte_for(mr.start());
   108   jbyte *const last = byte_after(mr.last());
   110   // Below we may use an explicit loop instead of memset() because on
   111   // certain platforms memset() can give concurrent readers phantom zeros.
   112   if (UseMemSetInBOT) {
   113     memset(first, g1_young_gen, last - first);
   114   } else {
   115     for (jbyte* i = first; i < last; i++) {
   116       *i = g1_young_gen;
   117     }
   118   }
   119 }
   121 #ifndef PRODUCT
   122 void G1SATBCardTableModRefBS::verify_g1_young_region(MemRegion mr) {
   123   verify_region(mr, g1_young_gen,  true);
   124 }
   125 #endif
   127 void G1SATBCardTableLoggingModRefBSChangedListener::on_commit(uint start_idx, size_t num_regions, bool zero_filled) {
   128   // Default value for a clean card on the card table is -1. So we cannot take advantage of the zero_filled parameter.
   129   MemRegion mr(G1CollectedHeap::heap()->bottom_addr_for_region(start_idx), num_regions * HeapRegion::GrainWords);
   130   _card_table->clear(mr);
   131 }
   133 G1SATBCardTableLoggingModRefBS::
   134 G1SATBCardTableLoggingModRefBS(MemRegion whole_heap,
   135                                int max_covered_regions) :
   136   G1SATBCardTableModRefBS(whole_heap, max_covered_regions),
   137   _dcqs(JavaThread::dirty_card_queue_set()),
   138   _listener()
   139 {
   140   _kind = G1SATBCTLogging;
   141   _listener.set_card_table(this);
   142 }
   144 void G1SATBCardTableLoggingModRefBS::initialize(G1RegionToSpaceMapper* mapper) {
   145   mapper->set_mapping_changed_listener(&_listener);
   147   _byte_map_size = mapper->reserved().byte_size();
   149   _guard_index = cards_required(_whole_heap.word_size()) - 1;
   150   _last_valid_index = _guard_index - 1;
   152   HeapWord* low_bound  = _whole_heap.start();
   153   HeapWord* high_bound = _whole_heap.end();
   155   _cur_covered_regions = 1;
   156   _covered[0] = _whole_heap;
   158   _byte_map = (jbyte*) mapper->reserved().start();
   159   byte_map_base = _byte_map - (uintptr_t(low_bound) >> card_shift);
   160   assert(byte_for(low_bound) == &_byte_map[0], "Checking start of map");
   161   assert(byte_for(high_bound-1) <= &_byte_map[_last_valid_index], "Checking end of map");
   163   if (TraceCardTableModRefBS) {
   164     gclog_or_tty->print_cr("G1SATBCardTableModRefBS::G1SATBCardTableModRefBS: ");
   165     gclog_or_tty->print_cr("  "
   166                   "  &_byte_map[0]: " INTPTR_FORMAT
   167                   "  &_byte_map[_last_valid_index]: " INTPTR_FORMAT,
   168                   p2i(&_byte_map[0]),
   169                   p2i(&_byte_map[_last_valid_index]));
   170     gclog_or_tty->print_cr("  "
   171                   "  byte_map_base: " INTPTR_FORMAT,
   172                   p2i(byte_map_base));
   173   }
   174 }
   176 void
   177 G1SATBCardTableLoggingModRefBS::write_ref_field_work(void* field,
   178                                                      oop new_val,
   179                                                      bool release) {
   180   volatile jbyte* byte = byte_for(field);
   181   if (*byte == g1_young_gen) {
   182     return;
   183   }
   184   OrderAccess::storeload();
   185   if (*byte != dirty_card) {
   186     *byte = dirty_card;
   187     Thread* thr = Thread::current();
   188     if (thr->is_Java_thread()) {
   189       JavaThread* jt = (JavaThread*)thr;
   190       jt->dirty_card_queue().enqueue(byte);
   191     } else {
   192       MutexLockerEx x(Shared_DirtyCardQ_lock,
   193                       Mutex::_no_safepoint_check_flag);
   194       _dcqs.shared_dirty_card_queue()->enqueue(byte);
   195     }
   196   }
   197 }
   199 void
   200 G1SATBCardTableLoggingModRefBS::write_ref_field_static(void* field,
   201                                                        oop new_val) {
   202   uintptr_t field_uint = (uintptr_t)field;
   203   uintptr_t new_val_uint = cast_from_oop<uintptr_t>(new_val);
   204   uintptr_t comb = field_uint ^ new_val_uint;
   205   comb = comb >> HeapRegion::LogOfHRGrainBytes;
   206   if (comb == 0) return;
   207   if (new_val == NULL) return;
   208   // Otherwise, log it.
   209   G1SATBCardTableLoggingModRefBS* g1_bs =
   210     (G1SATBCardTableLoggingModRefBS*)Universe::heap()->barrier_set();
   211   g1_bs->write_ref_field_work(field, new_val);
   212 }
   214 void
   215 G1SATBCardTableLoggingModRefBS::invalidate(MemRegion mr, bool whole_heap) {
   216   volatile jbyte* byte = byte_for(mr.start());
   217   jbyte* last_byte = byte_for(mr.last());
   218   Thread* thr = Thread::current();
   219   if (whole_heap) {
   220     while (byte <= last_byte) {
   221       *byte = dirty_card;
   222       byte++;
   223     }
   224   } else {
   225     // skip all consecutive young cards
   226     for (; byte <= last_byte && *byte == g1_young_gen; byte++);
   228     if (byte <= last_byte) {
   229       OrderAccess::storeload();
   230       // Enqueue if necessary.
   231       if (thr->is_Java_thread()) {
   232         JavaThread* jt = (JavaThread*)thr;
   233         for (; byte <= last_byte; byte++) {
   234           if (*byte == g1_young_gen) {
   235             continue;
   236           }
   237           if (*byte != dirty_card) {
   238             *byte = dirty_card;
   239             jt->dirty_card_queue().enqueue(byte);
   240           }
   241         }
   242       } else {
   243         MutexLockerEx x(Shared_DirtyCardQ_lock,
   244                         Mutex::_no_safepoint_check_flag);
   245         for (; byte <= last_byte; byte++) {
   246           if (*byte == g1_young_gen) {
   247             continue;
   248           }
   249           if (*byte != dirty_card) {
   250             *byte = dirty_card;
   251             _dcqs.shared_dirty_card_queue()->enqueue(byte);
   252           }
   253         }
   254       }
   255     }
   256   }
   257 }

mercurial