src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp

changeset 0
f90c822e73f8
child 1
2d8a650513c2
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp	Wed Apr 27 01:25:04 2016 +0800
     1.3 @@ -0,0 +1,344 @@
     1.4 +/*
     1.5 + * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.
    1.11 + *
    1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.15 + * version 2 for more details (a copy is included in the LICENSE file that
    1.16 + * accompanied this code).
    1.17 + *
    1.18 + * You should have received a copy of the GNU General Public License version
    1.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.21 + *
    1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.23 + * or visit www.oracle.com if you need additional information or have any
    1.24 + * questions.
    1.25 + *
    1.26 + */
    1.27 +
    1.28 +#include "precompiled.hpp"
    1.29 +#include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp"
    1.30 +#include "gc_implementation/parallelScavenge/psOldGen.hpp"
    1.31 +#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp"
    1.32 +#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp"
    1.33 +#include "gc_implementation/shared/gcTrace.hpp"
    1.34 +#include "gc_implementation/shared/mutableSpace.hpp"
    1.35 +#include "memory/allocation.inline.hpp"
    1.36 +#include "memory/memRegion.hpp"
    1.37 +#include "memory/padded.inline.hpp"
    1.38 +#include "oops/oop.inline.hpp"
    1.39 +#include "oops/oop.psgc.inline.hpp"
    1.40 +
    1.41 +PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
    1.42 +
    1.43 +PaddedEnd<PSPromotionManager>* PSPromotionManager::_manager_array = NULL;
    1.44 +OopStarTaskQueueSet*           PSPromotionManager::_stack_array_depth = NULL;
    1.45 +PSOldGen*                      PSPromotionManager::_old_gen = NULL;
    1.46 +MutableSpace*                  PSPromotionManager::_young_space = NULL;
    1.47 +
    1.48 +void PSPromotionManager::initialize() {
    1.49 +  ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
    1.50 +  assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity");
    1.51 +
    1.52 +  _old_gen = heap->old_gen();
    1.53 +  _young_space = heap->young_gen()->to_space();
    1.54 +
    1.55 +  // To prevent false sharing, we pad the PSPromotionManagers
    1.56 +  // and make sure that the first instance starts at a cache line.
    1.57 +  assert(_manager_array == NULL, "Attempt to initialize twice");
    1.58 +  _manager_array = PaddedArray<PSPromotionManager, mtGC>::create_unfreeable(ParallelGCThreads + 1);
    1.59 +  guarantee(_manager_array != NULL, "Could not initialize promotion manager");
    1.60 +
    1.61 +  _stack_array_depth = new OopStarTaskQueueSet(ParallelGCThreads);
    1.62 +  guarantee(_stack_array_depth != NULL, "Could not initialize promotion manager");
    1.63 +
    1.64 +  // Create and register the PSPromotionManager(s) for the worker threads.
    1.65 +  for(uint i=0; i<ParallelGCThreads; i++) {
    1.66 +    stack_array_depth()->register_queue(i, _manager_array[i].claimed_stack_depth());
    1.67 +  }
    1.68 +  // The VMThread gets its own PSPromotionManager, which is not available
    1.69 +  // for work stealing.
    1.70 +}
    1.71 +
    1.72 +PSPromotionManager* PSPromotionManager::gc_thread_promotion_manager(int index) {
    1.73 +  assert(index >= 0 && index < (int)ParallelGCThreads, "index out of range");
    1.74 +  assert(_manager_array != NULL, "Sanity");
    1.75 +  return &_manager_array[index];
    1.76 +}
    1.77 +
    1.78 +PSPromotionManager* PSPromotionManager::vm_thread_promotion_manager() {
    1.79 +  assert(_manager_array != NULL, "Sanity");
    1.80 +  return &_manager_array[ParallelGCThreads];
    1.81 +}
    1.82 +
    1.83 +void PSPromotionManager::pre_scavenge() {
    1.84 +  ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
    1.85 +  assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity");
    1.86 +
    1.87 +  _young_space = heap->young_gen()->to_space();
    1.88 +
    1.89 +  for(uint i=0; i<ParallelGCThreads+1; i++) {
    1.90 +    manager_array(i)->reset();
    1.91 +  }
    1.92 +}
    1.93 +
    1.94 +bool PSPromotionManager::post_scavenge(YoungGCTracer& gc_tracer) {
    1.95 +  bool promotion_failure_occurred = false;
    1.96 +
    1.97 +  TASKQUEUE_STATS_ONLY(if (PrintGCDetails && ParallelGCVerbose) print_stats());
    1.98 +  for (uint i = 0; i < ParallelGCThreads + 1; i++) {
    1.99 +    PSPromotionManager* manager = manager_array(i);
   1.100 +    assert(manager->claimed_stack_depth()->is_empty(), "should be empty");
   1.101 +    if (manager->_promotion_failed_info.has_failed()) {
   1.102 +      gc_tracer.report_promotion_failed(manager->_promotion_failed_info);
   1.103 +      promotion_failure_occurred = true;
   1.104 +    }
   1.105 +    manager->flush_labs();
   1.106 +  }
   1.107 +  return promotion_failure_occurred;
   1.108 +}
   1.109 +
   1.110 +#if TASKQUEUE_STATS
   1.111 +void
   1.112 +PSPromotionManager::print_taskqueue_stats(uint i) const {
   1.113 +  tty->print("%3u ", i);
   1.114 +  _claimed_stack_depth.stats.print();
   1.115 +  tty->cr();
   1.116 +}
   1.117 +
   1.118 +void
   1.119 +PSPromotionManager::print_local_stats(uint i) const {
   1.120 +  #define FMT " " SIZE_FORMAT_W(10)
   1.121 +  tty->print_cr("%3u" FMT FMT FMT FMT, i, _masked_pushes, _masked_steals,
   1.122 +                _arrays_chunked, _array_chunks_processed);
   1.123 +  #undef FMT
   1.124 +}
   1.125 +
   1.126 +static const char* const pm_stats_hdr[] = {
   1.127 +  "    --------masked-------     arrays      array",
   1.128 +  "thr       push      steal    chunked     chunks",
   1.129 +  "--- ---------- ---------- ---------- ----------"
   1.130 +};
   1.131 +
   1.132 +void
   1.133 +PSPromotionManager::print_stats() {
   1.134 +  tty->print_cr("== GC Tasks Stats, GC %3d",
   1.135 +                Universe::heap()->total_collections());
   1.136 +
   1.137 +  tty->print("thr "); TaskQueueStats::print_header(1); tty->cr();
   1.138 +  tty->print("--- "); TaskQueueStats::print_header(2); tty->cr();
   1.139 +  for (uint i = 0; i < ParallelGCThreads + 1; ++i) {
   1.140 +    manager_array(i)->print_taskqueue_stats(i);
   1.141 +  }
   1.142 +
   1.143 +  const uint hlines = sizeof(pm_stats_hdr) / sizeof(pm_stats_hdr[0]);
   1.144 +  for (uint i = 0; i < hlines; ++i) tty->print_cr("%s", pm_stats_hdr[i]);
   1.145 +  for (uint i = 0; i < ParallelGCThreads + 1; ++i) {
   1.146 +    manager_array(i)->print_local_stats(i);
   1.147 +  }
   1.148 +}
   1.149 +
   1.150 +void
   1.151 +PSPromotionManager::reset_stats() {
   1.152 +  claimed_stack_depth()->stats.reset();
   1.153 +  _masked_pushes = _masked_steals = 0;
   1.154 +  _arrays_chunked = _array_chunks_processed = 0;
   1.155 +}
   1.156 +#endif // TASKQUEUE_STATS
   1.157 +
   1.158 +PSPromotionManager::PSPromotionManager() {
   1.159 +  ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
   1.160 +  assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity");
   1.161 +
   1.162 +  // We set the old lab's start array.
   1.163 +  _old_lab.set_start_array(old_gen()->start_array());
   1.164 +
   1.165 +  uint queue_size;
   1.166 +  claimed_stack_depth()->initialize();
   1.167 +  queue_size = claimed_stack_depth()->max_elems();
   1.168 +
   1.169 +  _totally_drain = (ParallelGCThreads == 1) || (GCDrainStackTargetSize == 0);
   1.170 +  if (_totally_drain) {
   1.171 +    _target_stack_size = 0;
   1.172 +  } else {
   1.173 +    // don't let the target stack size to be more than 1/4 of the entries
   1.174 +    _target_stack_size = (uint) MIN2((uint) GCDrainStackTargetSize,
   1.175 +                                     (uint) (queue_size / 4));
   1.176 +  }
   1.177 +
   1.178 +  _array_chunk_size = ParGCArrayScanChunk;
   1.179 +  // let's choose 1.5x the chunk size
   1.180 +  _min_array_size_for_chunking = 3 * _array_chunk_size / 2;
   1.181 +
   1.182 +  reset();
   1.183 +}
   1.184 +
   1.185 +void PSPromotionManager::reset() {
   1.186 +  assert(stacks_empty(), "reset of non-empty stack");
   1.187 +
   1.188 +  // We need to get an assert in here to make sure the labs are always flushed.
   1.189 +
   1.190 +  ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
   1.191 +  assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity");
   1.192 +
   1.193 +  // Do not prefill the LAB's, save heap wastage!
   1.194 +  HeapWord* lab_base = young_space()->top();
   1.195 +  _young_lab.initialize(MemRegion(lab_base, (size_t)0));
   1.196 +  _young_gen_is_full = false;
   1.197 +
   1.198 +  lab_base = old_gen()->object_space()->top();
   1.199 +  _old_lab.initialize(MemRegion(lab_base, (size_t)0));
   1.200 +  _old_gen_is_full = false;
   1.201 +
   1.202 +  _promotion_failed_info.reset();
   1.203 +
   1.204 +  TASKQUEUE_STATS_ONLY(reset_stats());
   1.205 +}
   1.206 +
   1.207 +
   1.208 +void PSPromotionManager::drain_stacks_depth(bool totally_drain) {
   1.209 +  totally_drain = totally_drain || _totally_drain;
   1.210 +
   1.211 +#ifdef ASSERT
   1.212 +  ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
   1.213 +  assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity");
   1.214 +  MutableSpace* to_space = heap->young_gen()->to_space();
   1.215 +  MutableSpace* old_space = heap->old_gen()->object_space();
   1.216 +#endif /* ASSERT */
   1.217 +
   1.218 +  OopStarTaskQueue* const tq = claimed_stack_depth();
   1.219 +  do {
   1.220 +    StarTask p;
   1.221 +
   1.222 +    // Drain overflow stack first, so other threads can steal from
   1.223 +    // claimed stack while we work.
   1.224 +    while (tq->pop_overflow(p)) {
   1.225 +      process_popped_location_depth(p);
   1.226 +    }
   1.227 +
   1.228 +    if (totally_drain) {
   1.229 +      while (tq->pop_local(p)) {
   1.230 +        process_popped_location_depth(p);
   1.231 +      }
   1.232 +    } else {
   1.233 +      while (tq->size() > _target_stack_size && tq->pop_local(p)) {
   1.234 +        process_popped_location_depth(p);
   1.235 +      }
   1.236 +    }
   1.237 +  } while (totally_drain && !tq->taskqueue_empty() || !tq->overflow_empty());
   1.238 +
   1.239 +  assert(!totally_drain || tq->taskqueue_empty(), "Sanity");
   1.240 +  assert(totally_drain || tq->size() <= _target_stack_size, "Sanity");
   1.241 +  assert(tq->overflow_empty(), "Sanity");
   1.242 +}
   1.243 +
   1.244 +void PSPromotionManager::flush_labs() {
   1.245 +  assert(stacks_empty(), "Attempt to flush lab with live stack");
   1.246 +
   1.247 +  // If either promotion lab fills up, we can flush the
   1.248 +  // lab but not refill it, so check first.
   1.249 +  assert(!_young_lab.is_flushed() || _young_gen_is_full, "Sanity");
   1.250 +  if (!_young_lab.is_flushed())
   1.251 +    _young_lab.flush();
   1.252 +
   1.253 +  assert(!_old_lab.is_flushed() || _old_gen_is_full, "Sanity");
   1.254 +  if (!_old_lab.is_flushed())
   1.255 +    _old_lab.flush();
   1.256 +
   1.257 +  // Let PSScavenge know if we overflowed
   1.258 +  if (_young_gen_is_full) {
   1.259 +    PSScavenge::set_survivor_overflow(true);
   1.260 +  }
   1.261 +}
   1.262 +
   1.263 +template <class T> void PSPromotionManager::process_array_chunk_work(
   1.264 +                                                 oop obj,
   1.265 +                                                 int start, int end) {
   1.266 +  assert(start <= end, "invariant");
   1.267 +  T* const base      = (T*)objArrayOop(obj)->base();
   1.268 +  T* p               = base + start;
   1.269 +  T* const chunk_end = base + end;
   1.270 +  while (p < chunk_end) {
   1.271 +    if (PSScavenge::should_scavenge(p)) {
   1.272 +      claim_or_forward_depth(p);
   1.273 +    }
   1.274 +    ++p;
   1.275 +  }
   1.276 +}
   1.277 +
   1.278 +void PSPromotionManager::process_array_chunk(oop old) {
   1.279 +  assert(PSChunkLargeArrays, "invariant");
   1.280 +  assert(old->is_objArray(), "invariant");
   1.281 +  assert(old->is_forwarded(), "invariant");
   1.282 +
   1.283 +  TASKQUEUE_STATS_ONLY(++_array_chunks_processed);
   1.284 +
   1.285 +  oop const obj = old->forwardee();
   1.286 +
   1.287 +  int start;
   1.288 +  int const end = arrayOop(old)->length();
   1.289 +  if (end > (int) _min_array_size_for_chunking) {
   1.290 +    // we'll chunk more
   1.291 +    start = end - _array_chunk_size;
   1.292 +    assert(start > 0, "invariant");
   1.293 +    arrayOop(old)->set_length(start);
   1.294 +    push_depth(mask_chunked_array_oop(old));
   1.295 +    TASKQUEUE_STATS_ONLY(++_masked_pushes);
   1.296 +  } else {
   1.297 +    // this is the final chunk for this array
   1.298 +    start = 0;
   1.299 +    int const actual_length = arrayOop(obj)->length();
   1.300 +    arrayOop(old)->set_length(actual_length);
   1.301 +  }
   1.302 +
   1.303 +  if (UseCompressedOops) {
   1.304 +    process_array_chunk_work<narrowOop>(obj, start, end);
   1.305 +  } else {
   1.306 +    process_array_chunk_work<oop>(obj, start, end);
   1.307 +  }
   1.308 +}
   1.309 +
   1.310 +oop PSPromotionManager::oop_promotion_failed(oop obj, markOop obj_mark) {
   1.311 +  assert(_old_gen_is_full || PromotionFailureALot, "Sanity");
   1.312 +
   1.313 +  // Attempt to CAS in the header.
   1.314 +  // This tests if the header is still the same as when
   1.315 +  // this started.  If it is the same (i.e., no forwarding
   1.316 +  // pointer has been installed), then this thread owns
   1.317 +  // it.
   1.318 +  if (obj->cas_forward_to(obj, obj_mark)) {
   1.319 +    // We won any races, we "own" this object.
   1.320 +    assert(obj == obj->forwardee(), "Sanity");
   1.321 +
   1.322 +    _promotion_failed_info.register_copy_failure(obj->size());
   1.323 +
   1.324 +    obj->push_contents(this);
   1.325 +
   1.326 +    // Save the mark if needed
   1.327 +    PSScavenge::oop_promotion_failed(obj, obj_mark);
   1.328 +  }  else {
   1.329 +    // We lost, someone else "owns" this object
   1.330 +    guarantee(obj->is_forwarded(), "Object must be forwarded if the cas failed.");
   1.331 +
   1.332 +    // No unallocation to worry about.
   1.333 +    obj = obj->forwardee();
   1.334 +  }
   1.335 +
   1.336 +#ifndef PRODUCT
   1.337 +  if (TraceScavenge) {
   1.338 +    gclog_or_tty->print_cr("{%s %s 0x%x (%d)}",
   1.339 +                           "promotion-failure",
   1.340 +                           obj->klass()->internal_name(),
   1.341 +                           (void *)obj, obj->size());
   1.342 +
   1.343 +  }
   1.344 +#endif
   1.345 +
   1.346 +  return obj;
   1.347 +}

mercurial