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

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

author
tschatzl
date
Fri, 10 Oct 2014 15:51:58 +0200
changeset 7257
e7d0505c8a30
parent 6930
570cb6369f17
child 7535
7ae4e26cb1e0
child 8662
9975dd8382d5
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, 2010, 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/dirtyCardQueue.hpp"
    27 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
    28 #include "gc_implementation/g1/heapRegionRemSet.hpp"
    29 #include "runtime/atomic.hpp"
    30 #include "runtime/mutexLocker.hpp"
    31 #include "runtime/safepoint.hpp"
    32 #include "runtime/thread.inline.hpp"
    33 #include "utilities/workgroup.hpp"
    35 bool DirtyCardQueue::apply_closure(CardTableEntryClosure* cl,
    36                                    bool consume,
    37                                    uint worker_i) {
    38   bool res = true;
    39   if (_buf != NULL) {
    40     res = apply_closure_to_buffer(cl, _buf, _index, _sz,
    41                                   consume,
    42                                   worker_i);
    43     if (res && consume) _index = _sz;
    44   }
    45   return res;
    46 }
    48 bool DirtyCardQueue::apply_closure_to_buffer(CardTableEntryClosure* cl,
    49                                              void** buf,
    50                                              size_t index, size_t sz,
    51                                              bool consume,
    52                                              uint worker_i) {
    53   if (cl == NULL) return true;
    54   for (size_t i = index; i < sz; i += oopSize) {
    55     int ind = byte_index_to_index((int)i);
    56     jbyte* card_ptr = (jbyte*)buf[ind];
    57     if (card_ptr != NULL) {
    58       // Set the entry to null, so we don't do it again (via the test
    59       // above) if we reconsider this buffer.
    60       if (consume) buf[ind] = NULL;
    61       if (!cl->do_card_ptr(card_ptr, worker_i)) return false;
    62     }
    63   }
    64   return true;
    65 }
    67 #ifdef _MSC_VER // the use of 'this' below gets a warning, make it go away
    68 #pragma warning( disable:4355 ) // 'this' : used in base member initializer list
    69 #endif // _MSC_VER
    71 DirtyCardQueueSet::DirtyCardQueueSet(bool notify_when_complete) :
    72   PtrQueueSet(notify_when_complete),
    73   _mut_process_closure(NULL),
    74   _shared_dirty_card_queue(this, true /*perm*/),
    75   _free_ids(NULL),
    76   _processed_buffers_mut(0), _processed_buffers_rs_thread(0)
    77 {
    78   _all_active = true;
    79 }
    81 // Determines how many mutator threads can process the buffers in parallel.
    82 uint DirtyCardQueueSet::num_par_ids() {
    83   return (uint)os::processor_count();
    84 }
    86 void DirtyCardQueueSet::initialize(CardTableEntryClosure* cl, Monitor* cbl_mon, Mutex* fl_lock,
    87                                    int process_completed_threshold,
    88                                    int max_completed_queue,
    89                                    Mutex* lock, PtrQueueSet* fl_owner) {
    90   _mut_process_closure = cl;
    91   PtrQueueSet::initialize(cbl_mon, fl_lock, process_completed_threshold,
    92                           max_completed_queue, fl_owner);
    93   set_buffer_size(G1UpdateBufferSize);
    94   _shared_dirty_card_queue.set_lock(lock);
    95   _free_ids = new FreeIdSet((int) num_par_ids(), _cbl_mon);
    96 }
    98 void DirtyCardQueueSet::handle_zero_index_for_thread(JavaThread* t) {
    99   t->dirty_card_queue().handle_zero_index();
   100 }
   102 void DirtyCardQueueSet::iterate_closure_all_threads(CardTableEntryClosure* cl,
   103                                                     bool consume,
   104                                                     uint worker_i) {
   105   assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
   106   for(JavaThread* t = Threads::first(); t; t = t->next()) {
   107     bool b = t->dirty_card_queue().apply_closure(cl, consume);
   108     guarantee(b, "Should not be interrupted.");
   109   }
   110   bool b = shared_dirty_card_queue()->apply_closure(cl,
   111                                                     consume,
   112                                                     worker_i);
   113   guarantee(b, "Should not be interrupted.");
   114 }
   116 bool DirtyCardQueueSet::mut_process_buffer(void** buf) {
   118   // Used to determine if we had already claimed a par_id
   119   // before entering this method.
   120   bool already_claimed = false;
   122   // We grab the current JavaThread.
   123   JavaThread* thread = JavaThread::current();
   125   // We get the the number of any par_id that this thread
   126   // might have already claimed.
   127   uint worker_i = thread->get_claimed_par_id();
   129   // If worker_i is not UINT_MAX then the thread has already claimed
   130   // a par_id. We make note of it using the already_claimed value
   131   if (worker_i != UINT_MAX) {
   132     already_claimed = true;
   133   } else {
   135     // Otherwise we need to claim a par id
   136     worker_i = _free_ids->claim_par_id();
   138     // And store the par_id value in the thread
   139     thread->set_claimed_par_id(worker_i);
   140   }
   142   bool b = false;
   143   if (worker_i != UINT_MAX) {
   144     b = DirtyCardQueue::apply_closure_to_buffer(_mut_process_closure, buf, 0,
   145                                                 _sz, true, worker_i);
   146     if (b) Atomic::inc(&_processed_buffers_mut);
   148     // If we had not claimed an id before entering the method
   149     // then we must release the id.
   150     if (!already_claimed) {
   152       // we release the id
   153       _free_ids->release_par_id(worker_i);
   155       // and set the claimed_id in the thread to UINT_MAX
   156       thread->set_claimed_par_id(UINT_MAX);
   157     }
   158   }
   159   return b;
   160 }
   163 BufferNode*
   164 DirtyCardQueueSet::get_completed_buffer(int stop_at) {
   165   BufferNode* nd = NULL;
   166   MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
   168   if ((int)_n_completed_buffers <= stop_at) {
   169     _process_completed = false;
   170     return NULL;
   171   }
   173   if (_completed_buffers_head != NULL) {
   174     nd = _completed_buffers_head;
   175     _completed_buffers_head = nd->next();
   176     if (_completed_buffers_head == NULL)
   177       _completed_buffers_tail = NULL;
   178     _n_completed_buffers--;
   179     assert(_n_completed_buffers >= 0, "Invariant");
   180   }
   181   debug_only(assert_completed_buffer_list_len_correct_locked());
   182   return nd;
   183 }
   185 bool DirtyCardQueueSet::
   186 apply_closure_to_completed_buffer_helper(CardTableEntryClosure* cl,
   187                                          uint worker_i,
   188                                          BufferNode* nd) {
   189   if (nd != NULL) {
   190     void **buf = BufferNode::make_buffer_from_node(nd);
   191     size_t index = nd->index();
   192     bool b =
   193       DirtyCardQueue::apply_closure_to_buffer(cl, buf,
   194                                               index, _sz,
   195                                               true, worker_i);
   196     if (b) {
   197       deallocate_buffer(buf);
   198       return true;  // In normal case, go on to next buffer.
   199     } else {
   200       enqueue_complete_buffer(buf, index);
   201       return false;
   202     }
   203   } else {
   204     return false;
   205   }
   206 }
   208 bool DirtyCardQueueSet::apply_closure_to_completed_buffer(CardTableEntryClosure* cl,
   209                                                           uint worker_i,
   210                                                           int stop_at,
   211                                                           bool during_pause) {
   212   assert(!during_pause || stop_at == 0, "Should not leave any completed buffers during a pause");
   213   BufferNode* nd = get_completed_buffer(stop_at);
   214   bool res = apply_closure_to_completed_buffer_helper(cl, worker_i, nd);
   215   if (res) Atomic::inc(&_processed_buffers_rs_thread);
   216   return res;
   217 }
   219 void DirtyCardQueueSet::apply_closure_to_all_completed_buffers(CardTableEntryClosure* cl) {
   220   BufferNode* nd = _completed_buffers_head;
   221   while (nd != NULL) {
   222     bool b =
   223       DirtyCardQueue::apply_closure_to_buffer(cl,
   224                                               BufferNode::make_buffer_from_node(nd),
   225                                               0, _sz, false);
   226     guarantee(b, "Should not stop early.");
   227     nd = nd->next();
   228   }
   229 }
   231 void DirtyCardQueueSet::par_apply_closure_to_all_completed_buffers(CardTableEntryClosure* cl) {
   232   BufferNode* nd = _cur_par_buffer_node;
   233   while (nd != NULL) {
   234     BufferNode* next = (BufferNode*)nd->next();
   235     BufferNode* actual = (BufferNode*)Atomic::cmpxchg_ptr((void*)next, (volatile void*)&_cur_par_buffer_node, (void*)nd);
   236     if (actual == nd) {
   237       bool b =
   238         DirtyCardQueue::apply_closure_to_buffer(cl,
   239                                                 BufferNode::make_buffer_from_node(actual),
   240                                                 0, _sz, false);
   241       guarantee(b, "Should not stop early.");
   242       nd = next;
   243     } else {
   244       nd = actual;
   245     }
   246   }
   247 }
   249 // Deallocates any completed log buffers
   250 void DirtyCardQueueSet::clear() {
   251   BufferNode* buffers_to_delete = NULL;
   252   {
   253     MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
   254     while (_completed_buffers_head != NULL) {
   255       BufferNode* nd = _completed_buffers_head;
   256       _completed_buffers_head = nd->next();
   257       nd->set_next(buffers_to_delete);
   258       buffers_to_delete = nd;
   259     }
   260     _n_completed_buffers = 0;
   261     _completed_buffers_tail = NULL;
   262     debug_only(assert_completed_buffer_list_len_correct_locked());
   263   }
   264   while (buffers_to_delete != NULL) {
   265     BufferNode* nd = buffers_to_delete;
   266     buffers_to_delete = nd->next();
   267     deallocate_buffer(BufferNode::make_buffer_from_node(nd));
   268   }
   270 }
   272 void DirtyCardQueueSet::abandon_logs() {
   273   assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
   274   clear();
   275   // Since abandon is done only at safepoints, we can safely manipulate
   276   // these queues.
   277   for (JavaThread* t = Threads::first(); t; t = t->next()) {
   278     t->dirty_card_queue().reset();
   279   }
   280   shared_dirty_card_queue()->reset();
   281 }
   284 void DirtyCardQueueSet::concatenate_logs() {
   285   // Iterate over all the threads, if we find a partial log add it to
   286   // the global list of logs.  Temporarily turn off the limit on the number
   287   // of outstanding buffers.
   288   int save_max_completed_queue = _max_completed_queue;
   289   _max_completed_queue = max_jint;
   290   assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
   291   for (JavaThread* t = Threads::first(); t; t = t->next()) {
   292     DirtyCardQueue& dcq = t->dirty_card_queue();
   293     if (dcq.size() != 0) {
   294       void **buf = t->dirty_card_queue().get_buf();
   295       // We must NULL out the unused entries, then enqueue.
   296       for (size_t i = 0; i < t->dirty_card_queue().get_index(); i += oopSize) {
   297         buf[PtrQueue::byte_index_to_index((int)i)] = NULL;
   298       }
   299       enqueue_complete_buffer(dcq.get_buf(), dcq.get_index());
   300       dcq.reinitialize();
   301     }
   302   }
   303   if (_shared_dirty_card_queue.size() != 0) {
   304     enqueue_complete_buffer(_shared_dirty_card_queue.get_buf(),
   305                             _shared_dirty_card_queue.get_index());
   306     _shared_dirty_card_queue.reinitialize();
   307   }
   308   // Restore the completed buffer queue limit.
   309   _max_completed_queue = save_max_completed_queue;
   310 }

mercurial