mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-27 15:20:53 +00:00
210 lines
8.5 KiB
C++
210 lines
8.5 KiB
C++
/*
|
|
* Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*
|
|
*/
|
|
|
|
#ifndef SHARE_GC_SHARED_PARTIALARRAYSTATE_HPP
|
|
#define SHARE_GC_SHARED_PARTIALARRAYSTATE_HPP
|
|
|
|
#include "memory/allocation.hpp"
|
|
#include "oops/oopsHierarchy.hpp"
|
|
#include "runtime/atomic.hpp"
|
|
#include "utilities/globalDefinitions.hpp"
|
|
#include "utilities/macros.hpp"
|
|
|
|
class Arena;
|
|
class PartialArrayStateAllocator;
|
|
class PartialArrayStateManager;
|
|
|
|
// Instances of this class are used to represent processing progress for an
|
|
// array task in a taskqueue. When a sufficiently large array needs to be
|
|
// processed, such that it is desirable to split up the processing into
|
|
// parallelizable subtasks, a state object is allocated for the array.
|
|
// Multiple tasks referring to the state can then be added to the taskqueue
|
|
// for later processing, either by the current thread or by some other thread
|
|
// that steals one of those tasks.
|
|
//
|
|
// Processing a state involves using the state to claim a segment of the
|
|
// array, and processing that segment. Claiming is done by atomically
|
|
// incrementing the index, thereby claiming the segment from the old to new
|
|
// index values. New tasks should also be added as needed to ensure the
|
|
// entire array will be processed. A PartialArrayTaskStepper can be used to
|
|
// help with this.
|
|
//
|
|
// States are allocated and released using a PartialArrayStateAllocator.
|
|
// States are reference counted to aid in that management. Each task
|
|
// referring to a given state that is added to a taskqueue must increase the
|
|
// reference count by one. When the processing of a task referring to a state
|
|
// is complete, the reference count must be decreased by one. When the
|
|
// reference count reaches zero the state is released to the allocator for
|
|
// later reuse.
|
|
class PartialArrayState {
|
|
oop _source;
|
|
oop _destination;
|
|
size_t _length;
|
|
size_t _chunk_size;
|
|
Atomic<size_t> _index;
|
|
Atomic<size_t> _refcount;
|
|
|
|
friend class PartialArrayStateAllocator;
|
|
|
|
PartialArrayState(oop src, oop dst,
|
|
size_t index, size_t length,
|
|
size_t chunk_size, size_t initial_refcount);
|
|
|
|
public:
|
|
// Deleted to require management by allocator object.
|
|
~PartialArrayState() = delete;
|
|
|
|
NONCOPYABLE(PartialArrayState);
|
|
|
|
// Add count references, one per referring task being added to a taskqueue.
|
|
void add_references(size_t count);
|
|
|
|
// The source array oop.
|
|
oop source() const { return _source; }
|
|
|
|
// The destination array oop. In some circumstances the source and
|
|
// destination may be the same.
|
|
oop destination() const { return _destination; }
|
|
|
|
// The length of the array oop.
|
|
size_t length() const { return _length; }
|
|
|
|
size_t chunk_size() const { return _chunk_size; }
|
|
|
|
// A pointer to the start index for the next segment to process, for atomic
|
|
// update.
|
|
Atomic<size_t>* index_addr() { return &_index; }
|
|
};
|
|
|
|
// This class provides memory management for PartialArrayStates.
|
|
//
|
|
// States are initially arena allocated from the manager, using a per-thread
|
|
// allocator. This allows the entire set of allocated states to be discarded
|
|
// without the need to keep track of or find them under some circumstances.
|
|
// For example, if G1 concurrent marking is aborted and needs to restart
|
|
// because of a full marking queue, the queue doesn't need to be searched for
|
|
// tasks referring to states to allow releasing them. Instead the queue
|
|
// contents can just be discarded, and the memory for the no longer referenced
|
|
// states will eventually be reclaimed when the arena is reset.
|
|
//
|
|
// The allocators each provide a free-list of states. When a state is
|
|
// released and its reference count has reached zero, it is added to the
|
|
// allocator's free-list, for use by future allocation requests. This causes
|
|
// the maximum number of allocated states to be based on the number of
|
|
// in-progress arrays, rather than the total number of arrays that need to be
|
|
// processed.
|
|
//
|
|
// An allocator object is not thread-safe.
|
|
class PartialArrayStateAllocator : public CHeapObj<mtGC> {
|
|
class FreeListEntry;
|
|
|
|
PartialArrayStateManager* _manager;
|
|
FreeListEntry* _free_list;
|
|
Arena* _arena; // Obtained from _manager.
|
|
|
|
public:
|
|
explicit PartialArrayStateAllocator(PartialArrayStateManager* manager);
|
|
~PartialArrayStateAllocator();
|
|
|
|
NONCOPYABLE(PartialArrayStateAllocator);
|
|
|
|
// Create a new state, obtaining the memory for it from the free-list or
|
|
// from the associated manager.
|
|
PartialArrayState* allocate(oop src, oop dst,
|
|
size_t index, size_t length,
|
|
size_t chunk_size,
|
|
size_t initial_refcount);
|
|
|
|
// Decrement the state's refcount. If the new refcount is zero, add the
|
|
// state to the free-list associated with worker_id. The state must have
|
|
// been allocated by this allocator, but that allocation doesn't need to
|
|
// have been associated with worker_id.
|
|
void release(PartialArrayState* state);
|
|
};
|
|
|
|
// This class provides memory management for PartialArrayStates.
|
|
//
|
|
// States are allocated using an allocator object. Those allocators in turn
|
|
// may request memory for a state from their associated manager. The manager
|
|
// is responsible for obtaining and releasing memory used for states by the
|
|
// associated allocators.
|
|
//
|
|
// A state may be allocated by one allocator, but end up on the free-list of a
|
|
// different allocator. This can happen because a task referring to the state
|
|
// may be stolen from the queue where it was initially added. This is permitted
|
|
// because a state's memory won't be reclaimed until all of the allocators
|
|
// associated with the manager that is ultimately providing the memory have
|
|
// been deleted and the manager is reset.
|
|
//
|
|
// A manager is used in two distinct and non-overlapping phases.
|
|
//
|
|
// - allocating: This is the initial phase. During this phase, new allocators
|
|
// may be created, and allocators may request memory from the manager.
|
|
//
|
|
// - releasing: When an allocator is destroyed the manager transitions to this
|
|
// phase. It remains in this phase until all extent allocators associated with
|
|
// this manager have been destroyed. During this phase, new allocators may not
|
|
// be created, nor may extent allocators request memory from this manager.
|
|
//
|
|
// Once all the associated allocators have been destroyed the releasing phase
|
|
// ends and the manager may be reset or deleted. Resetting transitions back
|
|
// to the allocating phase.
|
|
class PartialArrayStateManager : public CHeapObj<mtGC> {
|
|
friend class PartialArrayStateAllocator;
|
|
|
|
// Use an arena for each allocator, for thread-safe concurrent allocation by
|
|
// different allocators.
|
|
Arena* _arenas;
|
|
|
|
// Limit on the number of allocators this manager supports.
|
|
uint _max_allocators;
|
|
|
|
// The number of allocators that have been registered/released.
|
|
// Atomic to support concurrent registration, and concurrent release.
|
|
// Phasing restriction forbids registration concurrent with release.
|
|
Atomic<uint> _registered_allocators;
|
|
DEBUG_ONLY(Atomic<uint> _released_allocators;)
|
|
|
|
// These are all for sole use of the befriended allocator class.
|
|
Arena* register_allocator();
|
|
void release_allocator() NOT_DEBUG_RETURN;
|
|
|
|
public:
|
|
explicit PartialArrayStateManager(uint max_allocators);
|
|
|
|
// Release the memory that has been requested by allocators associated with
|
|
// this manager.
|
|
// precondition: all associated allocators have been deleted.
|
|
~PartialArrayStateManager();
|
|
|
|
NONCOPYABLE(PartialArrayStateManager);
|
|
|
|
// Recycle the memory that has been requested by allocators associated with
|
|
// this manager.
|
|
// precondition: all associated allocators have been deleted.
|
|
void reset();
|
|
};
|
|
|
|
#endif // SHARE_GC_SHARED_PARTIALARRAYSTATE_HPP
|