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

Fri, 12 Aug 2011 11:31:06 -0400

author
tonyp
date
Fri, 12 Aug 2011 11:31:06 -0400
changeset 3028
f44782f04dd4
parent 2715
abdfc822206f
child 3713
720b6a76dd9d
permissions
-rw-r--r--

7039627: G1: avoid BOT updates for survivor allocations and dirty survivor regions incrementally
Summary: Refactor the allocation code during GC to use the G1AllocRegion abstraction. Use separate subclasses of G1AllocRegion for survivor and old regions. Avoid BOT updates and dirty survivor cards incrementally for the former.
Reviewed-by: brutisso, johnc, ysr

     1 /*
     2  * Copyright (c) 2011, 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/g1AllocRegion.inline.hpp"
    27 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
    29 G1CollectedHeap* G1AllocRegion::_g1h = NULL;
    30 HeapRegion* G1AllocRegion::_dummy_region = NULL;
    32 void G1AllocRegion::setup(G1CollectedHeap* g1h, HeapRegion* dummy_region) {
    33   assert(_dummy_region == NULL, "should be set once");
    34   assert(dummy_region != NULL, "pre-condition");
    35   assert(dummy_region->free() == 0, "pre-condition");
    37   // Make sure that any allocation attempt on this region will fail
    38   // and will not trigger any asserts.
    39   assert(allocate(dummy_region, 1, false) == NULL, "should fail");
    40   assert(par_allocate(dummy_region, 1, false) == NULL, "should fail");
    41   assert(allocate(dummy_region, 1, true) == NULL, "should fail");
    42   assert(par_allocate(dummy_region, 1, true) == NULL, "should fail");
    44   _g1h = g1h;
    45   _dummy_region = dummy_region;
    46 }
    48 void G1AllocRegion::fill_up_remaining_space(HeapRegion* alloc_region,
    49                                             bool bot_updates) {
    50   assert(alloc_region != NULL && alloc_region != _dummy_region,
    51          "pre-condition");
    53   // Other threads might still be trying to allocate using a CAS out
    54   // of the region we are trying to retire, as they can do so without
    55   // holding the lock. So, we first have to make sure that noone else
    56   // can allocate out of it by doing a maximal allocation. Even if our
    57   // CAS attempt fails a few times, we'll succeed sooner or later
    58   // given that failed CAS attempts mean that the region is getting
    59   // closed to being full.
    60   size_t free_word_size = alloc_region->free() / HeapWordSize;
    62   // This is the minimum free chunk we can turn into a dummy
    63   // object. If the free space falls below this, then noone can
    64   // allocate in this region anyway (all allocation requests will be
    65   // of a size larger than this) so we won't have to perform the dummy
    66   // allocation.
    67   size_t min_word_size_to_fill = CollectedHeap::min_fill_size();
    69   while (free_word_size >= min_word_size_to_fill) {
    70     HeapWord* dummy = par_allocate(alloc_region, free_word_size, bot_updates);
    71     if (dummy != NULL) {
    72       // If the allocation was successful we should fill in the space.
    73       CollectedHeap::fill_with_object(dummy, free_word_size);
    74       alloc_region->set_pre_dummy_top(dummy);
    75       break;
    76     }
    78     free_word_size = alloc_region->free() / HeapWordSize;
    79     // It's also possible that someone else beats us to the
    80     // allocation and they fill up the region. In that case, we can
    81     // just get out of the loop.
    82   }
    83   assert(alloc_region->free() / HeapWordSize < min_word_size_to_fill,
    84          "post-condition");
    85 }
    87 void G1AllocRegion::retire(bool fill_up) {
    88   assert(_alloc_region != NULL, ar_ext_msg(this, "not initialized properly"));
    90   trace("retiring");
    91   HeapRegion* alloc_region = _alloc_region;
    92   if (alloc_region != _dummy_region) {
    93     // We never have to check whether the active region is empty or not,
    94     // and potentially free it if it is, given that it's guaranteed that
    95     // it will never be empty.
    96     assert(!alloc_region->is_empty(),
    97            ar_ext_msg(this, "the alloc region should never be empty"));
    99     if (fill_up) {
   100       fill_up_remaining_space(alloc_region, _bot_updates);
   101     }
   103     assert(alloc_region->used() >= _used_bytes_before,
   104            ar_ext_msg(this, "invariant"));
   105     size_t allocated_bytes = alloc_region->used() - _used_bytes_before;
   106     retire_region(alloc_region, allocated_bytes);
   107     _used_bytes_before = 0;
   108     _alloc_region = _dummy_region;
   109   }
   110   trace("retired");
   111 }
   113 HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size,
   114                                                        bool force) {
   115   assert(_alloc_region == _dummy_region, ar_ext_msg(this, "pre-condition"));
   116   assert(_used_bytes_before == 0, ar_ext_msg(this, "pre-condition"));
   118   trace("attempting region allocation");
   119   HeapRegion* new_alloc_region = allocate_new_region(word_size, force);
   120   if (new_alloc_region != NULL) {
   121     new_alloc_region->reset_pre_dummy_top();
   122     // Need to do this before the allocation
   123     _used_bytes_before = new_alloc_region->used();
   124     HeapWord* result = allocate(new_alloc_region, word_size, _bot_updates);
   125     assert(result != NULL, ar_ext_msg(this, "the allocation should succeeded"));
   127     OrderAccess::storestore();
   128     // Note that we first perform the allocation and then we store the
   129     // region in _alloc_region. This is the reason why an active region
   130     // can never be empty.
   131     _alloc_region = new_alloc_region;
   132     _count += 1;
   133     trace("region allocation successful");
   134     return result;
   135   } else {
   136     trace("region allocation failed");
   137     return NULL;
   138   }
   139   ShouldNotReachHere();
   140 }
   142 void G1AllocRegion::fill_in_ext_msg(ar_ext_msg* msg, const char* message) {
   143   msg->append("[%s] %s c: "SIZE_FORMAT" b: %s r: "PTR_FORMAT" u: "SIZE_FORMAT,
   144               _name, message, _count, BOOL_TO_STR(_bot_updates),
   145               _alloc_region, _used_bytes_before);
   146 }
   148 void G1AllocRegion::init() {
   149   trace("initializing");
   150   assert(_alloc_region == NULL && _used_bytes_before == 0,
   151          ar_ext_msg(this, "pre-condition"));
   152   assert(_dummy_region != NULL, ar_ext_msg(this, "should have been set"));
   153   _alloc_region = _dummy_region;
   154   _count = 0;
   155   trace("initialized");
   156 }
   158 void G1AllocRegion::set(HeapRegion* alloc_region) {
   159   trace("setting");
   160   // We explicitly check that the region is not empty to make sure we
   161   // maintain the "the alloc region cannot be empty" invariant.
   162   assert(alloc_region != NULL && !alloc_region->is_empty(),
   163          ar_ext_msg(this, "pre-condition"));
   164   assert(_alloc_region == _dummy_region &&
   165          _used_bytes_before == 0 && _count == 0,
   166          ar_ext_msg(this, "pre-condition"));
   168   _used_bytes_before = alloc_region->used();
   169   _alloc_region = alloc_region;
   170   _count += 1;
   171   trace("set");
   172 }
   174 HeapRegion* G1AllocRegion::release() {
   175   trace("releasing");
   176   HeapRegion* alloc_region = _alloc_region;
   177   retire(false /* fill_up */);
   178   assert(_alloc_region == _dummy_region,
   179          ar_ext_msg(this, "post-condition of retire()"));
   180   _alloc_region = NULL;
   181   trace("released");
   182   return (alloc_region == _dummy_region) ? NULL : alloc_region;
   183 }
   185 #if G1_ALLOC_REGION_TRACING
   186 void G1AllocRegion::trace(const char* str, size_t word_size, HeapWord* result) {
   187   // All the calls to trace that set either just the size or the size
   188   // and the result are considered part of level 2 tracing and are
   189   // skipped during level 1 tracing.
   190   if ((word_size == 0 && result == NULL) || (G1_ALLOC_REGION_TRACING > 1)) {
   191     const size_t buffer_length = 128;
   192     char hr_buffer[buffer_length];
   193     char rest_buffer[buffer_length];
   195     HeapRegion* alloc_region = _alloc_region;
   196     if (alloc_region == NULL) {
   197       jio_snprintf(hr_buffer, buffer_length, "NULL");
   198     } else if (alloc_region == _dummy_region) {
   199       jio_snprintf(hr_buffer, buffer_length, "DUMMY");
   200     } else {
   201       jio_snprintf(hr_buffer, buffer_length,
   202                    HR_FORMAT, HR_FORMAT_PARAMS(alloc_region));
   203     }
   205     if (G1_ALLOC_REGION_TRACING > 1) {
   206       if (result != NULL) {
   207         jio_snprintf(rest_buffer, buffer_length, SIZE_FORMAT" "PTR_FORMAT,
   208                      word_size, result);
   209       } else if (word_size != 0) {
   210         jio_snprintf(rest_buffer, buffer_length, SIZE_FORMAT, word_size);
   211       } else {
   212         jio_snprintf(rest_buffer, buffer_length, "");
   213       }
   214     } else {
   215       jio_snprintf(rest_buffer, buffer_length, "");
   216     }
   218     tty->print_cr("[%s] "SIZE_FORMAT" %s : %s %s",
   219                   _name, _count, hr_buffer, str, rest_buffer);
   220   }
   221 }
   222 #endif // G1_ALLOC_REGION_TRACING
   224 G1AllocRegion::G1AllocRegion(const char* name,
   225                              bool bot_updates)
   226   : _name(name), _bot_updates(bot_updates),
   227     _alloc_region(NULL), _count(0), _used_bytes_before(0) { }

mercurial