Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp
38920 views
/*1* Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp"26#include "gc_implementation/parallelScavenge/psOldGen.hpp"27#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp"28#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp"29#include "gc_implementation/shared/gcTrace.hpp"30#include "gc_implementation/shared/mutableSpace.hpp"31#include "memory/allocation.inline.hpp"32#include "memory/memRegion.hpp"33#include "memory/padded.inline.hpp"34#include "oops/oop.inline.hpp"35#include "oops/oop.psgc.inline.hpp"3637PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC3839PaddedEnd<PSPromotionManager>* PSPromotionManager::_manager_array = NULL;40OopStarTaskQueueSet* PSPromotionManager::_stack_array_depth = NULL;41PSOldGen* PSPromotionManager::_old_gen = NULL;42MutableSpace* PSPromotionManager::_young_space = NULL;4344void PSPromotionManager::initialize() {45ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();46assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity");4748_old_gen = heap->old_gen();49_young_space = heap->young_gen()->to_space();5051// To prevent false sharing, we pad the PSPromotionManagers52// and make sure that the first instance starts at a cache line.53assert(_manager_array == NULL, "Attempt to initialize twice");54_manager_array = PaddedArray<PSPromotionManager, mtGC>::create_unfreeable(ParallelGCThreads + 1);55guarantee(_manager_array != NULL, "Could not initialize promotion manager");5657_stack_array_depth = new OopStarTaskQueueSet(ParallelGCThreads);58guarantee(_stack_array_depth != NULL, "Could not initialize promotion manager");5960// Create and register the PSPromotionManager(s) for the worker threads.61for(uint i=0; i<ParallelGCThreads; i++) {62stack_array_depth()->register_queue(i, _manager_array[i].claimed_stack_depth());63}64// The VMThread gets its own PSPromotionManager, which is not available65// for work stealing.66}6768PSPromotionManager* PSPromotionManager::gc_thread_promotion_manager(int index) {69assert(index >= 0 && index < (int)ParallelGCThreads, "index out of range");70assert(_manager_array != NULL, "Sanity");71return &_manager_array[index];72}7374PSPromotionManager* PSPromotionManager::vm_thread_promotion_manager() {75assert(_manager_array != NULL, "Sanity");76return &_manager_array[ParallelGCThreads];77}7879void PSPromotionManager::pre_scavenge() {80ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();81assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity");8283_young_space = heap->young_gen()->to_space();8485for(uint i=0; i<ParallelGCThreads+1; i++) {86manager_array(i)->reset();87}88}8990bool PSPromotionManager::post_scavenge(YoungGCTracer& gc_tracer) {91bool promotion_failure_occurred = false;9293TASKQUEUE_STATS_ONLY(if (PrintGCDetails && ParallelGCVerbose) print_stats());94for (uint i = 0; i < ParallelGCThreads + 1; i++) {95PSPromotionManager* manager = manager_array(i);96assert(manager->claimed_stack_depth()->is_empty(), "should be empty");97if (manager->_promotion_failed_info.has_failed()) {98gc_tracer.report_promotion_failed(manager->_promotion_failed_info);99promotion_failure_occurred = true;100}101manager->flush_labs();102}103return promotion_failure_occurred;104}105106#if TASKQUEUE_STATS107void108PSPromotionManager::print_taskqueue_stats(uint i) const {109tty->print("%3u ", i);110_claimed_stack_depth.stats.print();111tty->cr();112}113114void115PSPromotionManager::print_local_stats(uint i) const {116#define FMT " " SIZE_FORMAT_W(10)117tty->print_cr("%3u" FMT FMT FMT FMT, i, _masked_pushes, _masked_steals,118_arrays_chunked, _array_chunks_processed);119#undef FMT120}121122static const char* const pm_stats_hdr[] = {123" --------masked------- arrays array",124"thr push steal chunked chunks",125"--- ---------- ---------- ---------- ----------"126};127128void129PSPromotionManager::print_stats() {130tty->print_cr("== GC Tasks Stats, GC %3d",131Universe::heap()->total_collections());132133tty->print("thr "); TaskQueueStats::print_header(1); tty->cr();134tty->print("--- "); TaskQueueStats::print_header(2); tty->cr();135for (uint i = 0; i < ParallelGCThreads + 1; ++i) {136manager_array(i)->print_taskqueue_stats(i);137}138139const uint hlines = sizeof(pm_stats_hdr) / sizeof(pm_stats_hdr[0]);140for (uint i = 0; i < hlines; ++i) tty->print_cr("%s", pm_stats_hdr[i]);141for (uint i = 0; i < ParallelGCThreads + 1; ++i) {142manager_array(i)->print_local_stats(i);143}144}145146void147PSPromotionManager::reset_stats() {148claimed_stack_depth()->stats.reset();149_masked_pushes = _masked_steals = 0;150_arrays_chunked = _array_chunks_processed = 0;151}152#endif // TASKQUEUE_STATS153154PSPromotionManager::PSPromotionManager() {155ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();156assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity");157158// We set the old lab's start array.159_old_lab.set_start_array(old_gen()->start_array());160161uint queue_size;162claimed_stack_depth()->initialize();163queue_size = claimed_stack_depth()->max_elems();164165_totally_drain = (ParallelGCThreads == 1) || (GCDrainStackTargetSize == 0);166if (_totally_drain) {167_target_stack_size = 0;168} else {169// don't let the target stack size to be more than 1/4 of the entries170_target_stack_size = (uint) MIN2((uint) GCDrainStackTargetSize,171(uint) (queue_size / 4));172}173174_array_chunk_size = ParGCArrayScanChunk;175// let's choose 1.5x the chunk size176_min_array_size_for_chunking = 3 * _array_chunk_size / 2;177178reset();179}180181void PSPromotionManager::reset() {182assert(stacks_empty(), "reset of non-empty stack");183184// We need to get an assert in here to make sure the labs are always flushed.185186ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();187assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity");188189// Do not prefill the LAB's, save heap wastage!190HeapWord* lab_base = young_space()->top();191_young_lab.initialize(MemRegion(lab_base, (size_t)0));192_young_gen_is_full = false;193194lab_base = old_gen()->object_space()->top();195_old_lab.initialize(MemRegion(lab_base, (size_t)0));196_old_gen_is_full = false;197198_promotion_failed_info.reset();199200TASKQUEUE_STATS_ONLY(reset_stats());201}202203204void PSPromotionManager::drain_stacks_depth(bool totally_drain) {205totally_drain = totally_drain || _totally_drain;206207#ifdef ASSERT208ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();209assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity");210MutableSpace* to_space = heap->young_gen()->to_space();211MutableSpace* old_space = heap->old_gen()->object_space();212#endif /* ASSERT */213214OopStarTaskQueue* const tq = claimed_stack_depth();215do {216StarTask p;217218// Drain overflow stack first, so other threads can steal from219// claimed stack while we work.220while (tq->pop_overflow(p)) {221process_popped_location_depth(p);222}223224if (totally_drain) {225while (tq->pop_local(p)) {226process_popped_location_depth(p);227}228} else {229while (tq->size() > _target_stack_size && tq->pop_local(p)) {230process_popped_location_depth(p);231}232}233} while (totally_drain && !tq->taskqueue_empty() || !tq->overflow_empty());234235assert(!totally_drain || tq->taskqueue_empty(), "Sanity");236assert(totally_drain || tq->size() <= _target_stack_size, "Sanity");237assert(tq->overflow_empty(), "Sanity");238}239240void PSPromotionManager::flush_labs() {241assert(stacks_empty(), "Attempt to flush lab with live stack");242243// If either promotion lab fills up, we can flush the244// lab but not refill it, so check first.245assert(!_young_lab.is_flushed() || _young_gen_is_full, "Sanity");246if (!_young_lab.is_flushed())247_young_lab.flush();248249assert(!_old_lab.is_flushed() || _old_gen_is_full, "Sanity");250if (!_old_lab.is_flushed())251_old_lab.flush();252253// Let PSScavenge know if we overflowed254if (_young_gen_is_full) {255PSScavenge::set_survivor_overflow(true);256}257}258259template <class T> void PSPromotionManager::process_array_chunk_work(260oop obj,261int start, int end) {262assert(start <= end, "invariant");263T* const base = (T*)objArrayOop(obj)->base();264T* p = base + start;265T* const chunk_end = base + end;266while (p < chunk_end) {267if (PSScavenge::should_scavenge(p)) {268claim_or_forward_depth(p);269}270++p;271}272}273274void PSPromotionManager::process_array_chunk(oop old) {275assert(PSChunkLargeArrays, "invariant");276assert(old->is_objArray(), "invariant");277assert(old->is_forwarded(), "invariant");278279TASKQUEUE_STATS_ONLY(++_array_chunks_processed);280281oop const obj = old->forwardee();282283int start;284int const end = arrayOop(old)->length();285if (end > (int) _min_array_size_for_chunking) {286// we'll chunk more287start = end - _array_chunk_size;288assert(start > 0, "invariant");289arrayOop(old)->set_length(start);290push_depth(mask_chunked_array_oop(old));291TASKQUEUE_STATS_ONLY(++_masked_pushes);292} else {293// this is the final chunk for this array294start = 0;295int const actual_length = arrayOop(obj)->length();296arrayOop(old)->set_length(actual_length);297}298299if (UseCompressedOops) {300process_array_chunk_work<narrowOop>(obj, start, end);301} else {302process_array_chunk_work<oop>(obj, start, end);303}304}305306oop PSPromotionManager::oop_promotion_failed(oop obj, markOop obj_mark) {307assert(_old_gen_is_full || PromotionFailureALot, "Sanity");308309// Attempt to CAS in the header.310// This tests if the header is still the same as when311// this started. If it is the same (i.e., no forwarding312// pointer has been installed), then this thread owns313// it.314if (obj->cas_forward_to(obj, obj_mark)) {315// We won any races, we "own" this object.316assert(obj == obj->forwardee(), "Sanity");317318_promotion_failed_info.register_copy_failure(obj->size());319320obj->push_contents(this);321322// Save the mark if needed323PSScavenge::oop_promotion_failed(obj, obj_mark);324} else {325// We lost, someone else "owns" this object326guarantee(obj->is_forwarded(), "Object must be forwarded if the cas failed.");327328// No unallocation to worry about.329obj = obj->forwardee();330}331332#ifndef PRODUCT333if (TraceScavenge) {334gclog_or_tty->print_cr("{%s %s 0x%x (%d)}",335"promotion-failure",336obj->klass()->internal_name(),337(void *)obj, obj->size());338339}340#endif341342return obj;343}344345346