# HG changeset patch # User pliden # Date 1534161883 -7200 # Node ID f3cf91d5373f3ed7b8d2b400888d0c397737af60 # Parent 8ed5f86b15aa17eb716f03d35863d5010e01e14c 8209376: ZGC: Move ZMarkStackAllocator into a separate file Reviewed-by: eosterlund, kbarrett diff -r 8ed5f86b15aa -r f3cf91d5373f src/hotspot/share/gc/z/zMark.hpp --- a/src/hotspot/share/gc/z/zMark.hpp Mon Aug 13 14:04:42 2018 +0200 +++ b/src/hotspot/share/gc/z/zMark.hpp Mon Aug 13 14:04:43 2018 +0200 @@ -25,6 +25,7 @@ #define SHARE_GC_Z_ZMARK_HPP #include "gc/z/zMarkStack.hpp" +#include "gc/z/zMarkStackAllocator.hpp" #include "gc/z/zMarkTerminate.hpp" #include "oops/oopsHierarchy.hpp" #include "utilities/globalDefinitions.hpp" diff -r 8ed5f86b15aa -r f3cf91d5373f src/hotspot/share/gc/z/zMarkStack.cpp --- a/src/hotspot/share/gc/z/zMarkStack.cpp Mon Aug 13 14:04:42 2018 +0200 +++ b/src/hotspot/share/gc/z/zMarkStack.cpp Mon Aug 13 14:04:43 2018 +0200 @@ -22,169 +22,11 @@ */ #include "precompiled.hpp" -#include "gc/z/zErrno.hpp" -#include "gc/z/zGlobals.hpp" -#include "gc/z/zLock.inline.hpp" #include "gc/z/zMarkStack.inline.hpp" +#include "gc/z/zMarkStackAllocator.hpp" #include "logging/log.hpp" -#include "runtime/atomic.hpp" -#include "runtime/os.hpp" #include "utilities/debug.hpp" -uintptr_t ZMarkStackSpaceStart; - -ZMarkStackSpace::ZMarkStackSpace() : - _expand_lock(), - _start(0), - _top(0), - _end(0) { - assert(ZMarkStackSpaceLimit >= ZMarkStackSpaceExpandSize, "ZMarkStackSpaceLimit too small"); - - // Reserve address space - const size_t size = ZMarkStackSpaceLimit; - const size_t alignment = (size_t)os::vm_allocation_granularity(); - const uintptr_t addr = (uintptr_t)os::reserve_memory(size, NULL, alignment, mtGC); - if (addr == 0) { - log_error(gc, marking)("Failed to reserve address space for mark stacks"); - return; - } - - // Successfully initialized - _start = _top = _end = addr; - - // Register mark stack space start - ZMarkStackSpaceStart = _start; -} - -bool ZMarkStackSpace::is_initialized() const { - return _start != 0; -} - -uintptr_t ZMarkStackSpace::alloc_space(size_t size) { - uintptr_t top = Atomic::load(&_top); - - for (;;) { - const uintptr_t end = Atomic::load(&_end); - const uintptr_t new_top = top + size; - if (new_top > end) { - // Not enough space left - return 0; - } - - const uintptr_t prev_top = Atomic::cmpxchg(new_top, &_top, top); - if (prev_top == top) { - // Success - return top; - } - - // Retry - top = prev_top; - } -} - -uintptr_t ZMarkStackSpace::expand_and_alloc_space(size_t size) { - ZLocker locker(&_expand_lock); - - // Retry allocation before expanding - uintptr_t addr = alloc_space(size); - if (addr != 0) { - return addr; - } - - // Check expansion limit - const size_t expand_size = ZMarkStackSpaceExpandSize; - const size_t old_size = _end - _start; - const size_t new_size = old_size + expand_size; - if (new_size > ZMarkStackSpaceLimit) { - // Expansion limit reached. This is a fatal error since we - // currently can't recover from running out of mark stack space. - fatal("Mark stack space exhausted. Use -XX:ZMarkStackSpaceLimit= to increase the " - "maximum number of bytes allocated for mark stacks. Current limit is " SIZE_FORMAT "M.", - ZMarkStackSpaceLimit / M); - } - - log_debug(gc, marking)("Expanding mark stack space: " SIZE_FORMAT "M->" SIZE_FORMAT "M", - old_size / M, new_size / M); - - // Expand - os::commit_memory_or_exit((char*)_end, expand_size, false /* executable */, "Mark stack space"); - - // Increment top before end to make sure another - // thread can't steal out newly expanded space. - addr = Atomic::add(size, &_top) - size; - Atomic::add(expand_size, &_end); - - return addr; -} - -uintptr_t ZMarkStackSpace::alloc(size_t size) { - const uintptr_t addr = alloc_space(size); - if (addr != 0) { - return addr; - } - - return expand_and_alloc_space(size); -} - -ZMarkStackAllocator::ZMarkStackAllocator() : - _freelist(), - _space() { - guarantee(sizeof(ZMarkStack) == ZMarkStackSize, "Size mismatch"); - guarantee(sizeof(ZMarkStackMagazine) <= ZMarkStackSize, "Size mismatch"); - - // Prime free list to avoid an immediate space - // expansion when marking starts. - if (_space.is_initialized()) { - prime_freelist(); - } -} - -bool ZMarkStackAllocator::is_initialized() const { - return _space.is_initialized(); -} - -void ZMarkStackAllocator::prime_freelist() { - for (size_t size = 0; size < ZMarkStackSpaceExpandSize; size += ZMarkStackMagazineSize) { - const uintptr_t addr = _space.alloc(ZMarkStackMagazineSize); - ZMarkStackMagazine* const magazine = create_magazine_from_space(addr, ZMarkStackMagazineSize); - free_magazine(magazine); - } -} - -ZMarkStackMagazine* ZMarkStackAllocator::create_magazine_from_space(uintptr_t addr, size_t size) { - assert(is_aligned(size, ZMarkStackSize), "Invalid size"); - - // Use first stack as magazine - ZMarkStackMagazine* const magazine = new ((void*)addr) ZMarkStackMagazine(); - for (size_t i = ZMarkStackSize; i < size; i += ZMarkStackSize) { - ZMarkStack* const stack = new ((void*)(addr + i)) ZMarkStack(); - const bool success = magazine->push(stack); - assert(success, "Magazine should never get full"); - } - - return magazine; -} - -ZMarkStackMagazine* ZMarkStackAllocator::alloc_magazine() { - // Try allocating from the free list first - ZMarkStackMagazine* const magazine = _freelist.pop_atomic(); - if (magazine != NULL) { - return magazine; - } - - // Allocate new magazine - const uintptr_t addr = _space.alloc(ZMarkStackMagazineSize); - if (addr == 0) { - return NULL; - } - - return create_magazine_from_space(addr, ZMarkStackMagazineSize); -} - -void ZMarkStackAllocator::free_magazine(ZMarkStackMagazine* magazine) { - _freelist.push_atomic(magazine); -} - ZMarkStripe::ZMarkStripe() : _published(), _overflowed() {} diff -r 8ed5f86b15aa -r f3cf91d5373f src/hotspot/share/gc/z/zMarkStack.hpp --- a/src/hotspot/share/gc/z/zMarkStack.hpp Mon Aug 13 14:04:42 2018 +0200 +++ b/src/hotspot/share/gc/z/zMarkStack.hpp Mon Aug 13 14:04:43 2018 +0200 @@ -25,9 +25,7 @@ #define SHARE_GC_Z_ZMARKSTACK_HPP #include "gc/z/zGlobals.hpp" -#include "gc/z/zLock.hpp" #include "gc/z/zMarkStackEntry.hpp" -#include "memory/allocation.hpp" #include "utilities/globalDefinitions.hpp" template @@ -73,43 +71,6 @@ typedef ZStack ZMarkStackMagazine; typedef ZStackList ZMarkStackMagazineList; -class ZMarkStackSpace { -private: - ZLock _expand_lock; - uintptr_t _start; - volatile uintptr_t _top; - volatile uintptr_t _end; - - void expand(); - - uintptr_t alloc_space(size_t size); - uintptr_t expand_and_alloc_space(size_t size); - -public: - ZMarkStackSpace(); - - bool is_initialized() const; - - uintptr_t alloc(size_t size); -}; - -class ZMarkStackAllocator { -private: - ZMarkStackMagazineList _freelist ATTRIBUTE_ALIGNED(ZCacheLineSize); - ZMarkStackSpace _space ATTRIBUTE_ALIGNED(ZCacheLineSize); - - void prime_freelist(); - ZMarkStackMagazine* create_magazine_from_space(uintptr_t addr, size_t size); - -public: - ZMarkStackAllocator(); - - bool is_initialized() const; - - ZMarkStackMagazine* alloc_magazine(); - void free_magazine(ZMarkStackMagazine* magazine); -}; - class ZMarkStripe { private: ZMarkStackList _published ATTRIBUTE_ALIGNED(ZCacheLineSize); @@ -145,6 +106,8 @@ ZMarkStripe* stripe_for_addr(uintptr_t addr); }; +class ZMarkStackAllocator; + class ZMarkThreadLocalStacks { private: ZMarkStackMagazine* _magazine; diff -r 8ed5f86b15aa -r f3cf91d5373f src/hotspot/share/gc/z/zMarkStackAllocator.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/z/zMarkStackAllocator.cpp Mon Aug 13 14:04:43 2018 +0200 @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2016, 2018, 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. + */ + +#include "precompiled.hpp" +#include "gc/z/zLock.inline.hpp" +#include "gc/z/zMarkStack.inline.hpp" +#include "gc/z/zMarkStackAllocator.hpp" +#include "logging/log.hpp" +#include "runtime/atomic.hpp" +#include "runtime/os.hpp" +#include "utilities/debug.hpp" + +uintptr_t ZMarkStackSpaceStart; + +ZMarkStackSpace::ZMarkStackSpace() : + _expand_lock(), + _start(0), + _top(0), + _end(0) { + assert(ZMarkStackSpaceLimit >= ZMarkStackSpaceExpandSize, "ZMarkStackSpaceLimit too small"); + + // Reserve address space + const size_t size = ZMarkStackSpaceLimit; + const size_t alignment = (size_t)os::vm_allocation_granularity(); + const uintptr_t addr = (uintptr_t)os::reserve_memory(size, NULL, alignment, mtGC); + if (addr == 0) { + log_error(gc, marking)("Failed to reserve address space for mark stacks"); + return; + } + + // Successfully initialized + _start = _top = _end = addr; + + // Register mark stack space start + ZMarkStackSpaceStart = _start; +} + +bool ZMarkStackSpace::is_initialized() const { + return _start != 0; +} + +uintptr_t ZMarkStackSpace::alloc_space(size_t size) { + uintptr_t top = Atomic::load(&_top); + + for (;;) { + const uintptr_t end = Atomic::load(&_end); + const uintptr_t new_top = top + size; + if (new_top > end) { + // Not enough space left + return 0; + } + + const uintptr_t prev_top = Atomic::cmpxchg(new_top, &_top, top); + if (prev_top == top) { + // Success + return top; + } + + // Retry + top = prev_top; + } +} + +uintptr_t ZMarkStackSpace::expand_and_alloc_space(size_t size) { + ZLocker locker(&_expand_lock); + + // Retry allocation before expanding + uintptr_t addr = alloc_space(size); + if (addr != 0) { + return addr; + } + + // Check expansion limit + const size_t expand_size = ZMarkStackSpaceExpandSize; + const size_t old_size = _end - _start; + const size_t new_size = old_size + expand_size; + if (new_size > ZMarkStackSpaceLimit) { + // Expansion limit reached. This is a fatal error since we + // currently can't recover from running out of mark stack space. + fatal("Mark stack space exhausted. Use -XX:ZMarkStackSpaceLimit= to increase the " + "maximum number of bytes allocated for mark stacks. Current limit is " SIZE_FORMAT "M.", + ZMarkStackSpaceLimit / M); + } + + log_debug(gc, marking)("Expanding mark stack space: " SIZE_FORMAT "M->" SIZE_FORMAT "M", + old_size / M, new_size / M); + + // Expand + os::commit_memory_or_exit((char*)_end, expand_size, false /* executable */, "Mark stack space"); + + // Increment top before end to make sure another + // thread can't steal out newly expanded space. + addr = Atomic::add(size, &_top) - size; + Atomic::add(expand_size, &_end); + + return addr; +} + +uintptr_t ZMarkStackSpace::alloc(size_t size) { + const uintptr_t addr = alloc_space(size); + if (addr != 0) { + return addr; + } + + return expand_and_alloc_space(size); +} + +ZMarkStackAllocator::ZMarkStackAllocator() : + _freelist(), + _space() { + guarantee(sizeof(ZMarkStack) == ZMarkStackSize, "Size mismatch"); + guarantee(sizeof(ZMarkStackMagazine) <= ZMarkStackSize, "Size mismatch"); + + // Prime free list to avoid an immediate space + // expansion when marking starts. + if (_space.is_initialized()) { + prime_freelist(); + } +} + +bool ZMarkStackAllocator::is_initialized() const { + return _space.is_initialized(); +} + +void ZMarkStackAllocator::prime_freelist() { + for (size_t size = 0; size < ZMarkStackSpaceExpandSize; size += ZMarkStackMagazineSize) { + const uintptr_t addr = _space.alloc(ZMarkStackMagazineSize); + ZMarkStackMagazine* const magazine = create_magazine_from_space(addr, ZMarkStackMagazineSize); + free_magazine(magazine); + } +} + +ZMarkStackMagazine* ZMarkStackAllocator::create_magazine_from_space(uintptr_t addr, size_t size) { + assert(is_aligned(size, ZMarkStackSize), "Invalid size"); + + // Use first stack as magazine + ZMarkStackMagazine* const magazine = new ((void*)addr) ZMarkStackMagazine(); + for (size_t i = ZMarkStackSize; i < size; i += ZMarkStackSize) { + ZMarkStack* const stack = new ((void*)(addr + i)) ZMarkStack(); + const bool success = magazine->push(stack); + assert(success, "Magazine should never get full"); + } + + return magazine; +} + +ZMarkStackMagazine* ZMarkStackAllocator::alloc_magazine() { + // Try allocating from the free list first + ZMarkStackMagazine* const magazine = _freelist.pop_atomic(); + if (magazine != NULL) { + return magazine; + } + + // Allocate new magazine + const uintptr_t addr = _space.alloc(ZMarkStackMagazineSize); + if (addr == 0) { + return NULL; + } + + return create_magazine_from_space(addr, ZMarkStackMagazineSize); +} + +void ZMarkStackAllocator::free_magazine(ZMarkStackMagazine* magazine) { + _freelist.push_atomic(magazine); +} diff -r 8ed5f86b15aa -r f3cf91d5373f src/hotspot/share/gc/z/zMarkStackAllocator.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/z/zMarkStackAllocator.hpp Mon Aug 13 14:04:43 2018 +0200 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016, 2018, 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_Z_ZMARKSTACKALLOCATOR_HPP +#define SHARE_GC_Z_ZMARKSTACKALLOCATOR_HPP + +#include "gc/z/zGlobals.hpp" +#include "gc/z/zLock.hpp" +#include "utilities/globalDefinitions.hpp" + +class ZMarkStackSpace { +private: + ZLock _expand_lock; + uintptr_t _start; + volatile uintptr_t _top; + volatile uintptr_t _end; + + void expand(); + + uintptr_t alloc_space(size_t size); + uintptr_t expand_and_alloc_space(size_t size); + +public: + ZMarkStackSpace(); + + bool is_initialized() const; + + uintptr_t alloc(size_t size); +}; + +class ZMarkStackAllocator { +private: + ZMarkStackMagazineList _freelist ATTRIBUTE_ALIGNED(ZCacheLineSize); + ZMarkStackSpace _space ATTRIBUTE_ALIGNED(ZCacheLineSize); + + void prime_freelist(); + ZMarkStackMagazine* create_magazine_from_space(uintptr_t addr, size_t size); + +public: + ZMarkStackAllocator(); + + bool is_initialized() const; + + ZMarkStackMagazine* alloc_magazine(); + void free_magazine(ZMarkStackMagazine* magazine); +}; + +#endif // SHARE_GC_Z_ZMARKSTACKALLOCATOR_HPP