Path: blob/master/src/hotspot/share/gc/parallel/psPromotionManager.cpp
41149 views
/*1* Copyright (c) 2002, 2020, 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 "classfile/javaClasses.inline.hpp"26#include "gc/parallel/mutableSpace.hpp"27#include "gc/parallel/parallelScavengeHeap.hpp"28#include "gc/parallel/psOldGen.hpp"29#include "gc/parallel/psPromotionManager.inline.hpp"30#include "gc/parallel/psScavenge.inline.hpp"31#include "gc/shared/gcTrace.hpp"32#include "gc/shared/preservedMarks.inline.hpp"33#include "gc/shared/taskqueue.inline.hpp"34#include "logging/log.hpp"35#include "logging/logStream.hpp"36#include "memory/allocation.inline.hpp"37#include "memory/iterator.inline.hpp"38#include "memory/memRegion.hpp"39#include "memory/padded.inline.hpp"40#include "memory/resourceArea.hpp"41#include "oops/access.inline.hpp"42#include "oops/compressedOops.inline.hpp"4344PaddedEnd<PSPromotionManager>* PSPromotionManager::_manager_array = NULL;45PSPromotionManager::PSScannerTasksQueueSet* PSPromotionManager::_stack_array_depth = NULL;46PreservedMarksSet* PSPromotionManager::_preserved_marks_set = NULL;47PSOldGen* PSPromotionManager::_old_gen = NULL;48MutableSpace* PSPromotionManager::_young_space = NULL;4950void PSPromotionManager::initialize() {51ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();5253_old_gen = heap->old_gen();54_young_space = heap->young_gen()->to_space();5556const uint promotion_manager_num = ParallelGCThreads + 1;5758// To prevent false sharing, we pad the PSPromotionManagers59// and make sure that the first instance starts at a cache line.60assert(_manager_array == NULL, "Attempt to initialize twice");61_manager_array = PaddedArray<PSPromotionManager, mtGC>::create_unfreeable(promotion_manager_num);6263_stack_array_depth = new PSScannerTasksQueueSet(ParallelGCThreads);6465// Create and register the PSPromotionManager(s) for the worker threads.66for(uint i=0; i<ParallelGCThreads; i++) {67stack_array_depth()->register_queue(i, _manager_array[i].claimed_stack_depth());68}69// The VMThread gets its own PSPromotionManager, which is not available70// for work stealing.7172assert(_preserved_marks_set == NULL, "Attempt to initialize twice");73_preserved_marks_set = new PreservedMarksSet(true /* in_c_heap */);74_preserved_marks_set->init(promotion_manager_num);75for (uint i = 0; i < promotion_manager_num; i += 1) {76_manager_array[i].register_preserved_marks(_preserved_marks_set->get(i));77}78}7980// Helper functions to get around the circular dependency between81// psScavenge.inline.hpp and psPromotionManager.inline.hpp.82bool PSPromotionManager::should_scavenge(oop* p, bool check_to_space) {83return PSScavenge::should_scavenge(p, check_to_space);84}85bool PSPromotionManager::should_scavenge(narrowOop* p, bool check_to_space) {86return PSScavenge::should_scavenge(p, check_to_space);87}8889PSPromotionManager* PSPromotionManager::gc_thread_promotion_manager(uint index) {90assert(index < ParallelGCThreads, "index out of range");91assert(_manager_array != NULL, "Sanity");92return &_manager_array[index];93}9495PSPromotionManager* PSPromotionManager::vm_thread_promotion_manager() {96assert(_manager_array != NULL, "Sanity");97return &_manager_array[ParallelGCThreads];98}99100void PSPromotionManager::pre_scavenge() {101ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();102103_preserved_marks_set->assert_empty();104_young_space = heap->young_gen()->to_space();105106for(uint i=0; i<ParallelGCThreads+1; i++) {107manager_array(i)->reset();108}109}110111bool PSPromotionManager::post_scavenge(YoungGCTracer& gc_tracer) {112bool promotion_failure_occurred = false;113114TASKQUEUE_STATS_ONLY(print_taskqueue_stats());115for (uint i = 0; i < ParallelGCThreads + 1; i++) {116PSPromotionManager* manager = manager_array(i);117assert(manager->claimed_stack_depth()->is_empty(), "should be empty");118if (manager->_promotion_failed_info.has_failed()) {119gc_tracer.report_promotion_failed(manager->_promotion_failed_info);120promotion_failure_occurred = true;121}122manager->flush_labs();123}124if (!promotion_failure_occurred) {125// If there was no promotion failure, the preserved mark stacks126// should be empty.127_preserved_marks_set->assert_empty();128}129return promotion_failure_occurred;130}131132#if TASKQUEUE_STATS133void134PSPromotionManager::print_local_stats(outputStream* const out, uint i) const {135#define FMT " " SIZE_FORMAT_W(10)136out->print_cr("%3u" FMT FMT FMT FMT,137i, _array_chunk_pushes, _array_chunk_steals,138_arrays_chunked, _array_chunks_processed);139#undef FMT140}141142static const char* const pm_stats_hdr[] = {143" ----partial array---- arrays array",144"thr push steal chunked chunks",145"--- ---------- ---------- ---------- ----------"146};147148void149PSPromotionManager::print_taskqueue_stats() {150if (!log_is_enabled(Trace, gc, task, stats)) {151return;152}153Log(gc, task, stats) log;154ResourceMark rm;155LogStream ls(log.trace());156outputStream* out = &ls;157out->print_cr("== GC Tasks Stats, GC %3d",158ParallelScavengeHeap::heap()->total_collections());159160TaskQueueStats totals;161out->print("thr "); TaskQueueStats::print_header(1, out); out->cr();162out->print("--- "); TaskQueueStats::print_header(2, out); out->cr();163for (uint i = 0; i < ParallelGCThreads + 1; ++i) {164TaskQueueStats& next = manager_array(i)->_claimed_stack_depth.stats;165out->print("%3d ", i); next.print(out); out->cr();166totals += next;167}168out->print("tot "); totals.print(out); out->cr();169170const uint hlines = sizeof(pm_stats_hdr) / sizeof(pm_stats_hdr[0]);171for (uint i = 0; i < hlines; ++i) out->print_cr("%s", pm_stats_hdr[i]);172for (uint i = 0; i < ParallelGCThreads + 1; ++i) {173manager_array(i)->print_local_stats(out, i);174}175}176177void178PSPromotionManager::reset_stats() {179claimed_stack_depth()->stats.reset();180_array_chunk_pushes = _array_chunk_steals = 0;181_arrays_chunked = _array_chunks_processed = 0;182}183#endif // TASKQUEUE_STATS184185PSPromotionManager::PSPromotionManager() {186ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();187188// We set the old lab's start array.189_old_lab.set_start_array(old_gen()->start_array());190191uint queue_size;192claimed_stack_depth()->initialize();193queue_size = claimed_stack_depth()->max_elems();194195_totally_drain = (ParallelGCThreads == 1) || (GCDrainStackTargetSize == 0);196if (_totally_drain) {197_target_stack_size = 0;198} else {199// don't let the target stack size to be more than 1/4 of the entries200_target_stack_size = (uint) MIN2((uint) GCDrainStackTargetSize,201(uint) (queue_size / 4));202}203204_array_chunk_size = ParGCArrayScanChunk;205// let's choose 1.5x the chunk size206_min_array_size_for_chunking = 3 * _array_chunk_size / 2;207208_preserved_marks = NULL;209210reset();211}212213void PSPromotionManager::reset() {214assert(stacks_empty(), "reset of non-empty stack");215216// We need to get an assert in here to make sure the labs are always flushed.217218ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();219220// Do not prefill the LAB's, save heap wastage!221HeapWord* lab_base = young_space()->top();222_young_lab.initialize(MemRegion(lab_base, (size_t)0));223_young_gen_is_full = false;224225lab_base = old_gen()->object_space()->top();226_old_lab.initialize(MemRegion(lab_base, (size_t)0));227_old_gen_is_full = false;228229_promotion_failed_info.reset();230231TASKQUEUE_STATS_ONLY(reset_stats());232}233234void PSPromotionManager::register_preserved_marks(PreservedMarks* preserved_marks) {235assert(_preserved_marks == NULL, "do not set it twice");236_preserved_marks = preserved_marks;237}238239void PSPromotionManager::restore_preserved_marks() {240_preserved_marks_set->restore(&ParallelScavengeHeap::heap()->workers());241}242243void PSPromotionManager::drain_stacks_depth(bool totally_drain) {244totally_drain = totally_drain || _totally_drain;245246#ifdef ASSERT247ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();248MutableSpace* to_space = heap->young_gen()->to_space();249MutableSpace* old_space = heap->old_gen()->object_space();250#endif /* ASSERT */251252PSScannerTasksQueue* const tq = claimed_stack_depth();253do {254ScannerTask task;255256// Drain overflow stack first, so other threads can steal from257// claimed stack while we work.258while (tq->pop_overflow(task)) {259process_popped_location_depth(task);260}261262if (totally_drain) {263while (tq->pop_local(task)) {264process_popped_location_depth(task);265}266} else {267while (tq->size() > _target_stack_size && tq->pop_local(task)) {268process_popped_location_depth(task);269}270}271} while ((totally_drain && !tq->taskqueue_empty()) || !tq->overflow_empty());272273assert(!totally_drain || tq->taskqueue_empty(), "Sanity");274assert(totally_drain || tq->size() <= _target_stack_size, "Sanity");275assert(tq->overflow_empty(), "Sanity");276}277278void PSPromotionManager::flush_labs() {279assert(stacks_empty(), "Attempt to flush lab with live stack");280281// If either promotion lab fills up, we can flush the282// lab but not refill it, so check first.283assert(!_young_lab.is_flushed() || _young_gen_is_full, "Sanity");284if (!_young_lab.is_flushed())285_young_lab.flush();286287assert(!_old_lab.is_flushed() || _old_gen_is_full, "Sanity");288if (!_old_lab.is_flushed())289_old_lab.flush();290291// Let PSScavenge know if we overflowed292if (_young_gen_is_full) {293PSScavenge::set_survivor_overflow(true);294}295}296297template <class T> void PSPromotionManager::process_array_chunk_work(298oop obj,299int start, int end) {300assert(start <= end, "invariant");301T* const base = (T*)objArrayOop(obj)->base();302T* p = base + start;303T* const chunk_end = base + end;304while (p < chunk_end) {305if (PSScavenge::should_scavenge(p)) {306claim_or_forward_depth(p);307}308++p;309}310}311312void PSPromotionManager::process_array_chunk(PartialArrayScanTask task) {313assert(PSChunkLargeArrays, "invariant");314315oop old = task.to_source_array();316assert(old->is_objArray(), "invariant");317assert(old->is_forwarded(), "invariant");318319TASKQUEUE_STATS_ONLY(++_array_chunks_processed);320321oop const obj = old->forwardee();322323int start;324int const end = arrayOop(old)->length();325if (end > (int) _min_array_size_for_chunking) {326// we'll chunk more327start = end - _array_chunk_size;328assert(start > 0, "invariant");329arrayOop(old)->set_length(start);330push_depth(ScannerTask(PartialArrayScanTask(old)));331TASKQUEUE_STATS_ONLY(++_array_chunk_pushes);332} else {333// this is the final chunk for this array334start = 0;335int const actual_length = arrayOop(obj)->length();336arrayOop(old)->set_length(actual_length);337}338339if (UseCompressedOops) {340process_array_chunk_work<narrowOop>(obj, start, end);341} else {342process_array_chunk_work<oop>(obj, start, end);343}344}345346oop PSPromotionManager::oop_promotion_failed(oop obj, markWord obj_mark) {347assert(_old_gen_is_full || PromotionFailureALot, "Sanity");348349// Attempt to CAS in the header.350// This tests if the header is still the same as when351// this started. If it is the same (i.e., no forwarding352// pointer has been installed), then this thread owns353// it.354if (obj->cas_forward_to(obj, obj_mark)) {355// We won any races, we "own" this object.356assert(obj == obj->forwardee(), "Sanity");357358_promotion_failed_info.register_copy_failure(obj->size());359360push_contents(obj);361362_preserved_marks->push_if_necessary(obj, obj_mark);363} else {364// We lost, someone else "owns" this object365guarantee(obj->is_forwarded(), "Object must be forwarded if the cas failed.");366367// No unallocation to worry about.368obj = obj->forwardee();369}370371log_develop_trace(gc, scavenge)("{promotion-failure %s " PTR_FORMAT " (%d)}", obj->klass()->internal_name(), p2i(obj), obj->size());372373return obj;374}375376377