From 57c25426e61920cb31eb7c4baafbd7ca396a67d3 Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Wed, 9 Apr 2025 08:41:46 +0200 Subject: [PATCH 01/14] Max tlab size should be reported in words --- src/hotspot/share/gc/z/zCollectedHeap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/z/zCollectedHeap.cpp b/src/hotspot/share/gc/z/zCollectedHeap.cpp index 642ad42a1d7bb..172dfaf680c6b 100644 --- a/src/hotspot/share/gc/z/zCollectedHeap.cpp +++ b/src/hotspot/share/gc/z/zCollectedHeap.cpp @@ -238,7 +238,7 @@ size_t ZCollectedHeap::tlab_used(Thread* ignored) const { } size_t ZCollectedHeap::max_tlab_size() const { - return _heap.max_tlab_size(); + return _heap.max_tlab_size() / HeapWordSize; } size_t ZCollectedHeap::unsafe_max_tlab_alloc(Thread* ignored) const { From 554a0dee37c8f1b3047fd576928e3818706cec78 Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Thu, 17 Apr 2025 12:57:19 +0200 Subject: [PATCH 02/14] Add class to keep track of TLAB usage --- src/hotspot/share/gc/z/zGeneration.cpp | 3 ++ src/hotspot/share/gc/z/zHeap.cpp | 17 +++++++++-- src/hotspot/share/gc/z/zHeap.hpp | 3 ++ src/hotspot/share/gc/z/zTLABUsage.cpp | 39 +++++++++++++++++++++++++ src/hotspot/share/gc/z/zTLABUsage.hpp | 40 ++++++++++++++++++++++++++ 5 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 src/hotspot/share/gc/z/zTLABUsage.cpp create mode 100644 src/hotspot/share/gc/z/zTLABUsage.hpp diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index e74d7a8e9f3e0..ad4e59057702f 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -837,6 +837,9 @@ void ZGenerationYoung::mark_start() { // Change good colors flip_mark_start(); + // Update TLAB usage + ZHeap::heap()->update_tlab_usage(ZAllocator::eden()->tlab_used()); + // Retire allocating pages ZAllocator::eden()->retire_pages(); for (ZPageAge i = ZPageAge::survivor1; i <= ZPageAge::survivor14; i = static_cast(static_cast(i) + 1)) { diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index 90f8a86713532..1e072fb6ac43c 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -62,6 +62,7 @@ ZHeap::ZHeap() _serviceability(InitialHeapSize, min_capacity(), max_capacity()), _old(&_page_table, &_page_allocator), _young(&_page_table, _old.forwarding_table(), &_page_allocator), + _tlab_usage(), _initialized(false) { // Install global heap instance @@ -131,11 +132,11 @@ size_t ZHeap::unused() const { } size_t ZHeap::tlab_capacity() const { - return capacity(); + return _tlab_usage.capacity(); } size_t ZHeap::tlab_used() const { - return _allocator_eden.tlab_used(); + return _tlab_usage.used(); } size_t ZHeap::max_tlab_size() const { @@ -157,6 +158,18 @@ size_t ZHeap::unsafe_max_tlab_alloc() const { return MIN2(size, max_tlab_size()); } +void ZHeap::update_tlab_usage(size_t current_used) { + const size_t old_used = _tlab_usage.used(); + const size_t old_capacity = _tlab_usage.capacity(); + + _tlab_usage.update(current_used); + log_debug(gc, tlab)("TLAB Usage update: used %zuM -> %zuM, capacity: %zuM -> %zuM", + old_used / M, + _tlab_usage.used() / M, + old_capacity / M, + _tlab_usage.capacity() / M); +} + bool ZHeap::is_in(uintptr_t addr) const { if (addr == 0) { // Null isn't in the heap. diff --git a/src/hotspot/share/gc/z/zHeap.hpp b/src/hotspot/share/gc/z/zHeap.hpp index 823fc009b2ca0..8dbc53f0ac506 100644 --- a/src/hotspot/share/gc/z/zHeap.hpp +++ b/src/hotspot/share/gc/z/zHeap.hpp @@ -33,6 +33,7 @@ #include "gc/z/zPageTable.hpp" #include "gc/z/zPageType.hpp" #include "gc/z/zServiceability.hpp" +#include "gc/z/zTLABUsage.hpp" class OopFieldClosure; @@ -54,6 +55,7 @@ class ZHeap { ZGenerationOld _old; ZGenerationYoung _young; + ZTLABUsage _tlab_usage; bool _initialized; @@ -81,6 +83,7 @@ class ZHeap { size_t tlab_used() const; size_t max_tlab_size() const; size_t unsafe_max_tlab_alloc() const; + void update_tlab_usage(size_t current_used); bool is_in(uintptr_t addr) const; bool is_in_page_relaxed(const ZPage* page, zaddress addr) const; diff --git a/src/hotspot/share/gc/z/zTLABUsage.cpp b/src/hotspot/share/gc/z/zTLABUsage.cpp new file mode 100644 index 0000000000000..5f2b8184fa679 --- /dev/null +++ b/src/hotspot/share/gc/z/zTLABUsage.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025, 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 "gc/z/zTLABUsage.hpp" + +ZTLABUsage::ZTLABUsage() + : _used_history() { } + +void ZTLABUsage::update(size_t used) { + _used_history.add(used); +} + +size_t ZTLABUsage::used() const { + return _used_history.last(); +} + +size_t ZTLABUsage::capacity() const { + return _used_history.avg(); +} diff --git a/src/hotspot/share/gc/z/zTLABUsage.hpp b/src/hotspot/share/gc/z/zTLABUsage.hpp new file mode 100644 index 0000000000000..82ea5c3879934 --- /dev/null +++ b/src/hotspot/share/gc/z/zTLABUsage.hpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025, 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_ZTLABUSAGE_HPP +#define SHARE_GC_Z_ZTLABUSAGE_HPP + +#include "utilities/numberSeq.hpp" + +class ZTLABUsage { +private: + TruncatedSeq _used_history; + +public: + ZTLABUsage(); + void update(size_t used); + size_t used() const; + size_t capacity() const; +}; + +#endif // SHARE_GC_Z_ZTLABUSAGE_HPP From 92769517d89eb9c2d83dec1126cdbb0e2f36c28c Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Thu, 10 Apr 2025 10:33:02 +0200 Subject: [PATCH 03/14] Track eden-usage in page allocator --- src/hotspot/share/gc/z/zAllocator.cpp | 4 --- src/hotspot/share/gc/z/zAllocator.hpp | 1 - src/hotspot/share/gc/z/zGeneration.cpp | 2 +- src/hotspot/share/gc/z/zHeap.cpp | 3 +- src/hotspot/share/gc/z/zObjectAllocator.cpp | 34 +-------------------- src/hotspot/share/gc/z/zObjectAllocator.hpp | 3 -- src/hotspot/share/gc/z/zPageAllocator.cpp | 18 +++++++++++ src/hotspot/share/gc/z/zPageAllocator.hpp | 4 +++ src/hotspot/share/gc/z/zTLABUsage.cpp | 2 +- src/hotspot/share/gc/z/zTLABUsage.hpp | 11 +++++++ 10 files changed, 38 insertions(+), 44 deletions(-) diff --git a/src/hotspot/share/gc/z/zAllocator.cpp b/src/hotspot/share/gc/z/zAllocator.cpp index 87e1f6f76f941..22f3b6ba11232 100644 --- a/src/hotspot/share/gc/z/zAllocator.cpp +++ b/src/hotspot/share/gc/z/zAllocator.cpp @@ -39,10 +39,6 @@ ZAllocatorEden::ZAllocatorEden() ZAllocator::_eden = this; } -size_t ZAllocatorEden::tlab_used() const { - return _object_allocator.used(); -} - size_t ZAllocatorEden::remaining() const { return _object_allocator.remaining(); } diff --git a/src/hotspot/share/gc/z/zAllocator.hpp b/src/hotspot/share/gc/z/zAllocator.hpp index 21702800e6b03..45a70888f9d73 100644 --- a/src/hotspot/share/gc/z/zAllocator.hpp +++ b/src/hotspot/share/gc/z/zAllocator.hpp @@ -62,7 +62,6 @@ class ZAllocatorEden : public ZAllocator { zaddress alloc_object(size_t size); // Statistics - size_t tlab_used() const; size_t remaining() const; }; diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index ad4e59057702f..0ae8ec07e7dd3 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -838,7 +838,7 @@ void ZGenerationYoung::mark_start() { flip_mark_start(); // Update TLAB usage - ZHeap::heap()->update_tlab_usage(ZAllocator::eden()->tlab_used()); + ZHeap::heap()->update_tlab_usage(_page_allocator->used_eden()); // Retire allocating pages ZAllocator::eden()->retire_pages(); diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index 1e072fb6ac43c..9eefdd3d56c01 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -163,7 +163,8 @@ void ZHeap::update_tlab_usage(size_t current_used) { const size_t old_capacity = _tlab_usage.capacity(); _tlab_usage.update(current_used); - log_debug(gc, tlab)("TLAB Usage update: used %zuM -> %zuM, capacity: %zuM -> %zuM", + + log_debug(gc, tlab)("TLAB usage update: used %zuM -> %zuM, capacity: %zuM -> %zuM", old_used / M, _tlab_usage.used() / M, old_capacity / M, diff --git a/src/hotspot/share/gc/z/zObjectAllocator.cpp b/src/hotspot/share/gc/z/zObjectAllocator.cpp index 54724c1b48ed4..b92828e24a683 100644 --- a/src/hotspot/share/gc/z/zObjectAllocator.cpp +++ b/src/hotspot/share/gc/z/zObjectAllocator.cpp @@ -43,8 +43,6 @@ static const ZStatCounter ZCounterUndoObjectAllocationFailed("Memory", "Undo Obj ZObjectAllocator::ZObjectAllocator(ZPageAge age) : _age(age), _use_per_cpu_shared_small_pages(ZHeuristics::use_per_cpu_shared_small_pages()), - _used(0), - _undone(0), _shared_small_page(nullptr), _shared_medium_page(nullptr), _medium_page_alloc_lock() {} @@ -58,13 +56,7 @@ ZPage* const* ZObjectAllocator::shared_small_page_addr() const { } ZPage* ZObjectAllocator::alloc_page(ZPageType type, size_t size, ZAllocationFlags flags) { - ZPage* const page = ZHeap::heap()->alloc_page(type, size, flags, _age); - if (page != nullptr) { - // Increment used bytes - Atomic::add(_used.addr(), size); - } - - return page; + return ZHeap::heap()->alloc_page(type, size, flags, _age); } ZPage* ZObjectAllocator::alloc_page_for_relocation(ZPageType type, size_t size, ZAllocationFlags flags) { @@ -72,9 +64,6 @@ ZPage* ZObjectAllocator::alloc_page_for_relocation(ZPageType type, size_t size, } void ZObjectAllocator::undo_alloc_page(ZPage* page) { - // Increment undone bytes - Atomic::add(_undone.addr(), page->size()); - ZHeap::heap()->undo_alloc_page(page); } @@ -229,23 +218,6 @@ ZPageAge ZObjectAllocator::age() const { return _age; } -size_t ZObjectAllocator::used() const { - size_t total_used = 0; - size_t total_undone = 0; - - ZPerCPUConstIterator iter_used(&_used); - for (const size_t* cpu_used; iter_used.next(&cpu_used);) { - total_used += *cpu_used; - } - - ZPerCPUConstIterator iter_undone(&_undone); - for (const size_t* cpu_undone; iter_undone.next(&cpu_undone);) { - total_undone += *cpu_undone; - } - - return total_used - total_undone; -} - size_t ZObjectAllocator::remaining() const { assert(Thread::current()->is_Java_thread(), "Should be a Java thread"); @@ -260,10 +232,6 @@ size_t ZObjectAllocator::remaining() const { void ZObjectAllocator::retire_pages() { assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); - // Reset used and undone bytes - _used.set_all(0); - _undone.set_all(0); - // Reset allocation pages _shared_medium_page.set(nullptr); _shared_small_page.set_all(nullptr); diff --git a/src/hotspot/share/gc/z/zObjectAllocator.hpp b/src/hotspot/share/gc/z/zObjectAllocator.hpp index a350c4f876a7d..3a747afecbe7f 100644 --- a/src/hotspot/share/gc/z/zObjectAllocator.hpp +++ b/src/hotspot/share/gc/z/zObjectAllocator.hpp @@ -38,8 +38,6 @@ class ZObjectAllocator { private: ZPageAge _age; const bool _use_per_cpu_shared_small_pages; - ZPerCPU _used; - ZPerCPU _undone; ZPerCPU _shared_small_page; ZContended _shared_medium_page; ZLock _medium_page_alloc_lock; @@ -80,7 +78,6 @@ class ZObjectAllocator { ZPageAge age() const; - size_t used() const; size_t remaining() const; void retire_pages(); diff --git a/src/hotspot/share/gc/z/zPageAllocator.cpp b/src/hotspot/share/gc/z/zPageAllocator.cpp index 7bb1dcdcf81d4..c051f0816ec39 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.cpp +++ b/src/hotspot/share/gc/z/zPageAllocator.cpp @@ -1264,6 +1264,7 @@ ZPageAllocator::ZPageAllocator(size_t min_capacity, _min_capacity(min_capacity), _max_capacity(max_capacity), _used(0), + _used_eden(0), _used_generations{0,0}, _collection_stats{{0, 0},{0, 0}}, _partitions(ZValueIdTagType{}, this), @@ -1354,6 +1355,10 @@ size_t ZPageAllocator::used() const { return Atomic::load(&_used); } +size_t ZPageAllocator::used_eden() const { + return Atomic::load(&_used_eden); +} + size_t ZPageAllocator::used_generation(ZGenerationId id) const { return Atomic::load(&_used_generations[(int)id]); } @@ -1415,6 +1420,7 @@ ZPageAllocatorStats ZPageAllocator::update_and_stats(ZGeneration* generation) { ZLocker locker(&_lock); update_collection_stats(generation->id()); + reset_used_eden(); return stats_inner(generation); } @@ -1570,6 +1576,7 @@ bool ZPageAllocator::claim_capacity_or_stall(ZPageAllocation* allocation) { if (claim_capacity(allocation)) { // Keep track of usage increase_used(allocation->size()); + increase_used_eden(allocation); return true; } @@ -2202,6 +2209,7 @@ void ZPageAllocator::satisfy_stalled() { // Keep track of usage increase_used(allocation->size()); + increase_used_eden(allocation); // Allocation succeeded, dequeue and satisfy allocation request. // Note that we must dequeue the allocation request first, since @@ -2262,6 +2270,16 @@ void ZPageAllocator::decrease_used(size_t size) { } } +void ZPageAllocator::increase_used_eden(ZPageAllocation* allocation) { + if (allocation->age() == ZPageAge::eden) { + Atomic::add(&_used_eden, allocation->size()); + } +} + +void ZPageAllocator::reset_used_eden() { + Atomic::store(&_used_eden, (size_t) 0); +} + void ZPageAllocator::safe_destroy_page(ZPage* page) { // Destroy page safely _safe_destroy.schedule_delete(page); diff --git a/src/hotspot/share/gc/z/zPageAllocator.hpp b/src/hotspot/share/gc/z/zPageAllocator.hpp index 5cd08aee94cda..79f316b26807d 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.hpp +++ b/src/hotspot/share/gc/z/zPageAllocator.hpp @@ -159,6 +159,7 @@ class ZPageAllocator { const size_t _min_capacity; const size_t _max_capacity; volatile size_t _used; + volatile size_t _used_eden; volatile size_t _used_generations[2]; struct { size_t _used_high; @@ -231,6 +232,8 @@ class ZPageAllocator { void increase_used(size_t size); void decrease_used(size_t size); + void increase_used_eden(ZPageAllocation* allocation); + void reset_used_eden(); void notify_out_of_memory(); void restart_gc() const; @@ -256,6 +259,7 @@ class ZPageAllocator { size_t current_max_capacity() const; size_t capacity() const; size_t used() const; + size_t used_eden() const; size_t used_generation(ZGenerationId id) const; size_t unused() const; diff --git a/src/hotspot/share/gc/z/zTLABUsage.cpp b/src/hotspot/share/gc/z/zTLABUsage.cpp index 5f2b8184fa679..60e324d4700ac 100644 --- a/src/hotspot/share/gc/z/zTLABUsage.cpp +++ b/src/hotspot/share/gc/z/zTLABUsage.cpp @@ -35,5 +35,5 @@ size_t ZTLABUsage::used() const { } size_t ZTLABUsage::capacity() const { - return _used_history.avg(); + return _used_history.davg(); } diff --git a/src/hotspot/share/gc/z/zTLABUsage.hpp b/src/hotspot/share/gc/z/zTLABUsage.hpp index 82ea5c3879934..b049725a501cd 100644 --- a/src/hotspot/share/gc/z/zTLABUsage.hpp +++ b/src/hotspot/share/gc/z/zTLABUsage.hpp @@ -26,6 +26,17 @@ #include "utilities/numberSeq.hpp" +// ZGC is retiring TLABs concurrently with the application running when +// processing the stack watermarks. For the common TLAB heuristic to work we +// need to return consistent TLAB usage information when a TLAB is retired. +// We snapshot the TLAB usage in the mark start pause for the young generation +// and use this information until the next garbage collection cycle. +// +// ZGC does not have set generation sizes like most other GCs and because of +// this there is no fixed TLAB capacity. For the common TLAB sizing heuristic +// to work properly ZGC estimates the current capacity by using a weighted +// average of the last 10 used values. + class ZTLABUsage { private: TruncatedSeq _used_history; From 7421569b8d2e2d4c9a063e30de9a4a3df69d5b1b Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Tue, 22 Apr 2025 15:53:33 +0200 Subject: [PATCH 04/14] Fixes for TLABUsage --- src/hotspot/share/gc/z/zHeap.cpp | 4 ++-- src/hotspot/share/gc/z/zHeap.hpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index 9eefdd3d56c01..f8cd36289f1ab 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -158,11 +158,11 @@ size_t ZHeap::unsafe_max_tlab_alloc() const { return MIN2(size, max_tlab_size()); } -void ZHeap::update_tlab_usage(size_t current_used) { +void ZHeap::update_tlab_usage(size_t used) { const size_t old_used = _tlab_usage.used(); const size_t old_capacity = _tlab_usage.capacity(); - _tlab_usage.update(current_used); + _tlab_usage.update(used); log_debug(gc, tlab)("TLAB usage update: used %zuM -> %zuM, capacity: %zuM -> %zuM", old_used / M, diff --git a/src/hotspot/share/gc/z/zHeap.hpp b/src/hotspot/share/gc/z/zHeap.hpp index 8dbc53f0ac506..4f2f15c52425c 100644 --- a/src/hotspot/share/gc/z/zHeap.hpp +++ b/src/hotspot/share/gc/z/zHeap.hpp @@ -55,6 +55,7 @@ class ZHeap { ZGenerationOld _old; ZGenerationYoung _young; + ZTLABUsage _tlab_usage; bool _initialized; @@ -83,7 +84,7 @@ class ZHeap { size_t tlab_used() const; size_t max_tlab_size() const; size_t unsafe_max_tlab_alloc() const; - void update_tlab_usage(size_t current_used); + void update_tlab_usage(size_t used); bool is_in(uintptr_t addr) const; bool is_in_page_relaxed(const ZPage* page, zaddress addr) const; From 1b132bfc18e1ef3d9b023aad25688c659b211ae9 Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Tue, 22 Apr 2025 16:10:39 +0200 Subject: [PATCH 05/14] Fixes for eden tracking --- src/hotspot/share/gc/z/zPageAllocator.cpp | 31 ++++++++++++++--------- src/hotspot/share/gc/z/zPageAllocator.hpp | 3 ++- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/gc/z/zPageAllocator.cpp b/src/hotspot/share/gc/z/zPageAllocator.cpp index c051f0816ec39..93161a0ba2760 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.cpp +++ b/src/hotspot/share/gc/z/zPageAllocator.cpp @@ -1419,8 +1419,13 @@ ZPageAllocatorStats ZPageAllocator::stats(ZGeneration* generation) const { ZPageAllocatorStats ZPageAllocator::update_and_stats(ZGeneration* generation) { ZLocker locker(&_lock); + // Update per-collection statistics update_collection_stats(generation->id()); + + // Clear eden statistics reset_used_eden(); + + // Return the collected statistics return stats_inner(generation); } @@ -1576,7 +1581,6 @@ bool ZPageAllocator::claim_capacity_or_stall(ZPageAllocation* allocation) { if (claim_capacity(allocation)) { // Keep track of usage increase_used(allocation->size()); - increase_used_eden(allocation); return true; } @@ -2084,18 +2088,22 @@ void ZPageAllocator::free_memory_alloc_failed(ZMemoryAllocation* allocation) { } ZPage* ZPageAllocator::create_page(ZPageAllocation* allocation, const ZVirtualMemory& vmem) { + const size_t size = allocation->size(); + const ZPageType type = allocation->type(); + const ZPageAge age = allocation->age(); + const ZGenerationId id = age == ZPageAge::old ? ZGenerationId::old : ZGenerationId::young; + // We don't track generation usage when claiming capacity, because this page // could have been allocated by a thread that satisfies a stalling allocation. // The stalled thread can wake up and potentially realize that the page alloc // should be undone. If the alloc and the undo gets separated by a safepoint, - // the generation statistics could se a decreasing used value between mark + // the generation statistics could see a decreasing used value between mark // start and mark end. At this point an allocation will be successful, so we // update the generation usage. - const ZGenerationId id = allocation->age() == ZPageAge::old ? ZGenerationId::old : ZGenerationId::young; - increase_used_generation(id, allocation->size()); - - const ZPageType type = allocation->type(); - const ZPageAge age = allocation->age(); + increase_used_generation(id, size); + if (age == ZPageAge::eden) { + increase_used_eden(size); + } if (allocation->is_multi_partition()) { const ZMultiPartitionAllocation* const multi_partition_allocation = allocation->multi_partition_allocation(); @@ -2209,7 +2217,6 @@ void ZPageAllocator::satisfy_stalled() { // Keep track of usage increase_used(allocation->size()); - increase_used_eden(allocation); // Allocation succeeded, dequeue and satisfy allocation request. // Note that we must dequeue the allocation request first, since @@ -2270,13 +2277,13 @@ void ZPageAllocator::decrease_used(size_t size) { } } -void ZPageAllocator::increase_used_eden(ZPageAllocation* allocation) { - if (allocation->age() == ZPageAge::eden) { - Atomic::add(&_used_eden, allocation->size()); - } +void ZPageAllocator::increase_used_eden(size_t size) { + // Update atomically since we have concurrent readers and writers + Atomic::add(&_used_eden, size); } void ZPageAllocator::reset_used_eden() { + // Reset atomically since we have concurrent readers and writers Atomic::store(&_used_eden, (size_t) 0); } diff --git a/src/hotspot/share/gc/z/zPageAllocator.hpp b/src/hotspot/share/gc/z/zPageAllocator.hpp index 79f316b26807d..fa03da01d76df 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.hpp +++ b/src/hotspot/share/gc/z/zPageAllocator.hpp @@ -232,7 +232,8 @@ class ZPageAllocator { void increase_used(size_t size); void decrease_used(size_t size); - void increase_used_eden(ZPageAllocation* allocation); + + void increase_used_eden(size_t size); void reset_used_eden(); void notify_out_of_memory(); From 4e7ea16a220a3e38a0af7b72352770d71e827738 Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Tue, 22 Apr 2025 16:59:33 +0200 Subject: [PATCH 06/14] Junba-space --- src/hotspot/share/gc/z/zTLABUsage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/z/zTLABUsage.cpp b/src/hotspot/share/gc/z/zTLABUsage.cpp index 60e324d4700ac..663dd18301dec 100644 --- a/src/hotspot/share/gc/z/zTLABUsage.cpp +++ b/src/hotspot/share/gc/z/zTLABUsage.cpp @@ -21,7 +21,7 @@ * questions. */ - #include "gc/z/zTLABUsage.hpp" +#include "gc/z/zTLABUsage.hpp" ZTLABUsage::ZTLABUsage() : _used_history() { } From c96c5a83e775258a217b8f9737de0d47f3333fd0 Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Tue, 22 Apr 2025 21:53:22 +0200 Subject: [PATCH 07/14] More TLABUsage fixes --- src/hotspot/share/gc/z/zTLABUsage.cpp | 2 +- src/hotspot/share/gc/z/zTLABUsage.hpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/z/zTLABUsage.cpp b/src/hotspot/share/gc/z/zTLABUsage.cpp index 663dd18301dec..c2a0758d75ea8 100644 --- a/src/hotspot/share/gc/z/zTLABUsage.cpp +++ b/src/hotspot/share/gc/z/zTLABUsage.cpp @@ -24,7 +24,7 @@ #include "gc/z/zTLABUsage.hpp" ZTLABUsage::ZTLABUsage() - : _used_history() { } + : _used_history() {} void ZTLABUsage::update(size_t used) { _used_history.add(used); diff --git a/src/hotspot/share/gc/z/zTLABUsage.hpp b/src/hotspot/share/gc/z/zTLABUsage.hpp index b049725a501cd..5b4480345fe66 100644 --- a/src/hotspot/share/gc/z/zTLABUsage.hpp +++ b/src/hotspot/share/gc/z/zTLABUsage.hpp @@ -24,6 +24,7 @@ #ifndef SHARE_GC_Z_ZTLABUSAGE_HPP #define SHARE_GC_Z_ZTLABUSAGE_HPP +#include "utilities/globalDefinitions.hpp" #include "utilities/numberSeq.hpp" // ZGC is retiring TLABs concurrently with the application running when @@ -32,7 +33,7 @@ // We snapshot the TLAB usage in the mark start pause for the young generation // and use this information until the next garbage collection cycle. // -// ZGC does not have set generation sizes like most other GCs and because of +// ZGC does not have set generation sizes unlike most other GCs and because of // this there is no fixed TLAB capacity. For the common TLAB sizing heuristic // to work properly ZGC estimates the current capacity by using a weighted // average of the last 10 used values. @@ -43,7 +44,9 @@ class ZTLABUsage { public: ZTLABUsage(); + void update(size_t used); + size_t used() const; size_t capacity() const; }; From 0c1f6eed32903f87ff8a73d2ed22d52ff044866b Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Wed, 23 Apr 2025 09:02:51 +0200 Subject: [PATCH 08/14] Change memory order to relaxed --- src/hotspot/share/gc/z/zPageAllocator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/z/zPageAllocator.cpp b/src/hotspot/share/gc/z/zPageAllocator.cpp index 93161a0ba2760..58e707eafc465 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.cpp +++ b/src/hotspot/share/gc/z/zPageAllocator.cpp @@ -2279,7 +2279,7 @@ void ZPageAllocator::decrease_used(size_t size) { void ZPageAllocator::increase_used_eden(size_t size) { // Update atomically since we have concurrent readers and writers - Atomic::add(&_used_eden, size); + Atomic::add(&_used_eden, size, memory_order_relaxed); } void ZPageAllocator::reset_used_eden() { From 76c79f5c7da260300473fa518c4183d6da727409 Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Wed, 23 Apr 2025 15:53:33 +0200 Subject: [PATCH 09/14] Default TLAB size of 8k, avoid 0 updates and reasonable starting values --- src/hotspot/share/gc/z/zArguments.cpp | 5 +++++ src/hotspot/share/gc/z/zHeap.cpp | 2 +- src/hotspot/share/gc/z/zTLABUsage.cpp | 12 ++++++++++-- src/hotspot/share/gc/z/zTLABUsage.hpp | 2 +- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/z/zArguments.cpp b/src/hotspot/share/gc/z/zArguments.cpp index 67b9f6f0bb918..b54fb503d2e11 100644 --- a/src/hotspot/share/gc/z/zArguments.cpp +++ b/src/hotspot/share/gc/z/zArguments.cpp @@ -133,6 +133,11 @@ void ZArguments::initialize() { FLAG_SET_ERGO_IF_DEFAULT(ZCollectionIntervalMajor, ZCollectionInterval); } + // Set a small initial TLAB size to avoid depending on the current capacity + if (FLAG_IS_DEFAULT(TLABSize)) { + FLAG_SET_DEFAULT(TLABSize, 8*K); + } + // Set medium page size here because MaxTenuringThreshold may use it. ZHeuristics::set_medium_page_size(); diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index f8cd36289f1ab..56cff7bae2e17 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -62,7 +62,7 @@ ZHeap::ZHeap() _serviceability(InitialHeapSize, min_capacity(), max_capacity()), _old(&_page_table, &_page_allocator), _young(&_page_table, _old.forwarding_table(), &_page_allocator), - _tlab_usage(), + _tlab_usage(InitialHeapSize), _initialized(false) { // Install global heap instance diff --git a/src/hotspot/share/gc/z/zTLABUsage.cpp b/src/hotspot/share/gc/z/zTLABUsage.cpp index c2a0758d75ea8..bee4be4e38bd0 100644 --- a/src/hotspot/share/gc/z/zTLABUsage.cpp +++ b/src/hotspot/share/gc/z/zTLABUsage.cpp @@ -23,10 +23,18 @@ #include "gc/z/zTLABUsage.hpp" -ZTLABUsage::ZTLABUsage() - : _used_history() {} +ZTLABUsage::ZTLABUsage(size_t initial_heap_size) + : _used_history() { + // To get reasonable values for used and capacity until the first GC + // we populate the used history with the initial heap size. + _used_history.add(initial_heap_size); + } void ZTLABUsage::update(size_t used) { + if (used == 0) { + // Avoid updates for the second young generation collection of a SystemGC + return; + } _used_history.add(used); } diff --git a/src/hotspot/share/gc/z/zTLABUsage.hpp b/src/hotspot/share/gc/z/zTLABUsage.hpp index 5b4480345fe66..92ee319afd0f5 100644 --- a/src/hotspot/share/gc/z/zTLABUsage.hpp +++ b/src/hotspot/share/gc/z/zTLABUsage.hpp @@ -43,7 +43,7 @@ class ZTLABUsage { TruncatedSeq _used_history; public: - ZTLABUsage(); + ZTLABUsage(size_t initial_heap_size); void update(size_t used); From 4889af76064c39ea5a967817a3f388392f97d333 Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Tue, 6 May 2025 12:44:17 +0200 Subject: [PATCH 10/14] Revert initial value for TLABUsage --- src/hotspot/share/gc/z/zHeap.cpp | 2 +- src/hotspot/share/gc/z/zTLABUsage.cpp | 8 ++------ src/hotspot/share/gc/z/zTLABUsage.hpp | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index 56cff7bae2e17..f8cd36289f1ab 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -62,7 +62,7 @@ ZHeap::ZHeap() _serviceability(InitialHeapSize, min_capacity(), max_capacity()), _old(&_page_table, &_page_allocator), _young(&_page_table, _old.forwarding_table(), &_page_allocator), - _tlab_usage(InitialHeapSize), + _tlab_usage(), _initialized(false) { // Install global heap instance diff --git a/src/hotspot/share/gc/z/zTLABUsage.cpp b/src/hotspot/share/gc/z/zTLABUsage.cpp index bee4be4e38bd0..569f46a4352eb 100644 --- a/src/hotspot/share/gc/z/zTLABUsage.cpp +++ b/src/hotspot/share/gc/z/zTLABUsage.cpp @@ -23,12 +23,8 @@ #include "gc/z/zTLABUsage.hpp" -ZTLABUsage::ZTLABUsage(size_t initial_heap_size) - : _used_history() { - // To get reasonable values for used and capacity until the first GC - // we populate the used history with the initial heap size. - _used_history.add(initial_heap_size); - } +ZTLABUsage::ZTLABUsage() + : _used_history() {} void ZTLABUsage::update(size_t used) { if (used == 0) { diff --git a/src/hotspot/share/gc/z/zTLABUsage.hpp b/src/hotspot/share/gc/z/zTLABUsage.hpp index 92ee319afd0f5..5b4480345fe66 100644 --- a/src/hotspot/share/gc/z/zTLABUsage.hpp +++ b/src/hotspot/share/gc/z/zTLABUsage.hpp @@ -43,7 +43,7 @@ class ZTLABUsage { TruncatedSeq _used_history; public: - ZTLABUsage(size_t initial_heap_size); + ZTLABUsage(); void update(size_t used); From 10d455f21b3ffcacff90bdf984d327bca8df672b Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Wed, 7 May 2025 09:11:07 +0200 Subject: [PATCH 11/14] Keep all TLAB tracking in TLABUsage --- src/hotspot/share/gc/z/zGeneration.cpp | 4 +-- src/hotspot/share/gc/z/zHeap.cpp | 15 +++------ src/hotspot/share/gc/z/zHeap.hpp | 4 ++- src/hotspot/share/gc/z/zObjectAllocator.cpp | 6 ++++ src/hotspot/share/gc/z/zPageAllocator.cpp | 37 ++++----------------- src/hotspot/share/gc/z/zPageAllocator.hpp | 5 --- src/hotspot/share/gc/z/zTLABUsage.cpp | 34 +++++++++++++++---- src/hotspot/share/gc/z/zTLABUsage.hpp | 6 ++-- 8 files changed, 54 insertions(+), 57 deletions(-) diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index 0ae8ec07e7dd3..78860bbe4cb36 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -837,8 +837,8 @@ void ZGenerationYoung::mark_start() { // Change good colors flip_mark_start(); - // Update TLAB usage - ZHeap::heap()->update_tlab_usage(_page_allocator->used_eden()); + // Reset TLAB usage + ZHeap::heap()->reset_tlab_used(); // Retire allocating pages ZAllocator::eden()->retire_pages(); diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index f8cd36289f1ab..90f151a6039f7 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -158,17 +158,12 @@ size_t ZHeap::unsafe_max_tlab_alloc() const { return MIN2(size, max_tlab_size()); } -void ZHeap::update_tlab_usage(size_t used) { - const size_t old_used = _tlab_usage.used(); - const size_t old_capacity = _tlab_usage.capacity(); - - _tlab_usage.update(used); +void ZHeap::increment_tlab_used() { + _tlab_usage.add(ZPageSizeSmall); +} - log_debug(gc, tlab)("TLAB usage update: used %zuM -> %zuM, capacity: %zuM -> %zuM", - old_used / M, - _tlab_usage.used() / M, - old_capacity / M, - _tlab_usage.capacity() / M); +void ZHeap::reset_tlab_used() { + _tlab_usage.reset(); } bool ZHeap::is_in(uintptr_t addr) const { diff --git a/src/hotspot/share/gc/z/zHeap.hpp b/src/hotspot/share/gc/z/zHeap.hpp index 4f2f15c52425c..cee8b0d301190 100644 --- a/src/hotspot/share/gc/z/zHeap.hpp +++ b/src/hotspot/share/gc/z/zHeap.hpp @@ -84,7 +84,9 @@ class ZHeap { size_t tlab_used() const; size_t max_tlab_size() const; size_t unsafe_max_tlab_alloc() const; - void update_tlab_usage(size_t used); + + void increment_tlab_used(); + void reset_tlab_used(); bool is_in(uintptr_t addr) const; bool is_in_page_relaxed(const ZPage* page, zaddress addr) const; diff --git a/src/hotspot/share/gc/z/zObjectAllocator.cpp b/src/hotspot/share/gc/z/zObjectAllocator.cpp index b92828e24a683..fc04057ba9223 100644 --- a/src/hotspot/share/gc/z/zObjectAllocator.cpp +++ b/src/hotspot/share/gc/z/zObjectAllocator.cpp @@ -109,6 +109,12 @@ zaddress ZObjectAllocator::alloc_object_in_shared_page(ZPage** shared_page, // Undo new page allocation undo_alloc_page(new_page); + } else { + // Page successfully installed + if (_age == ZPageAge::eden && page_type == ZPageType::small) { + // Increment TLAB usage for small eden pages + ZHeap::heap()->increment_tlab_used(); + } } } } diff --git a/src/hotspot/share/gc/z/zPageAllocator.cpp b/src/hotspot/share/gc/z/zPageAllocator.cpp index 58e707eafc465..7bb1dcdcf81d4 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.cpp +++ b/src/hotspot/share/gc/z/zPageAllocator.cpp @@ -1264,7 +1264,6 @@ ZPageAllocator::ZPageAllocator(size_t min_capacity, _min_capacity(min_capacity), _max_capacity(max_capacity), _used(0), - _used_eden(0), _used_generations{0,0}, _collection_stats{{0, 0},{0, 0}}, _partitions(ZValueIdTagType{}, this), @@ -1355,10 +1354,6 @@ size_t ZPageAllocator::used() const { return Atomic::load(&_used); } -size_t ZPageAllocator::used_eden() const { - return Atomic::load(&_used_eden); -} - size_t ZPageAllocator::used_generation(ZGenerationId id) const { return Atomic::load(&_used_generations[(int)id]); } @@ -1419,13 +1414,7 @@ ZPageAllocatorStats ZPageAllocator::stats(ZGeneration* generation) const { ZPageAllocatorStats ZPageAllocator::update_and_stats(ZGeneration* generation) { ZLocker locker(&_lock); - // Update per-collection statistics update_collection_stats(generation->id()); - - // Clear eden statistics - reset_used_eden(); - - // Return the collected statistics return stats_inner(generation); } @@ -2088,22 +2077,18 @@ void ZPageAllocator::free_memory_alloc_failed(ZMemoryAllocation* allocation) { } ZPage* ZPageAllocator::create_page(ZPageAllocation* allocation, const ZVirtualMemory& vmem) { - const size_t size = allocation->size(); - const ZPageType type = allocation->type(); - const ZPageAge age = allocation->age(); - const ZGenerationId id = age == ZPageAge::old ? ZGenerationId::old : ZGenerationId::young; - // We don't track generation usage when claiming capacity, because this page // could have been allocated by a thread that satisfies a stalling allocation. // The stalled thread can wake up and potentially realize that the page alloc // should be undone. If the alloc and the undo gets separated by a safepoint, - // the generation statistics could see a decreasing used value between mark + // the generation statistics could se a decreasing used value between mark // start and mark end. At this point an allocation will be successful, so we // update the generation usage. - increase_used_generation(id, size); - if (age == ZPageAge::eden) { - increase_used_eden(size); - } + const ZGenerationId id = allocation->age() == ZPageAge::old ? ZGenerationId::old : ZGenerationId::young; + increase_used_generation(id, allocation->size()); + + const ZPageType type = allocation->type(); + const ZPageAge age = allocation->age(); if (allocation->is_multi_partition()) { const ZMultiPartitionAllocation* const multi_partition_allocation = allocation->multi_partition_allocation(); @@ -2277,16 +2262,6 @@ void ZPageAllocator::decrease_used(size_t size) { } } -void ZPageAllocator::increase_used_eden(size_t size) { - // Update atomically since we have concurrent readers and writers - Atomic::add(&_used_eden, size, memory_order_relaxed); -} - -void ZPageAllocator::reset_used_eden() { - // Reset atomically since we have concurrent readers and writers - Atomic::store(&_used_eden, (size_t) 0); -} - void ZPageAllocator::safe_destroy_page(ZPage* page) { // Destroy page safely _safe_destroy.schedule_delete(page); diff --git a/src/hotspot/share/gc/z/zPageAllocator.hpp b/src/hotspot/share/gc/z/zPageAllocator.hpp index fa03da01d76df..5cd08aee94cda 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.hpp +++ b/src/hotspot/share/gc/z/zPageAllocator.hpp @@ -159,7 +159,6 @@ class ZPageAllocator { const size_t _min_capacity; const size_t _max_capacity; volatile size_t _used; - volatile size_t _used_eden; volatile size_t _used_generations[2]; struct { size_t _used_high; @@ -233,9 +232,6 @@ class ZPageAllocator { void increase_used(size_t size); void decrease_used(size_t size); - void increase_used_eden(size_t size); - void reset_used_eden(); - void notify_out_of_memory(); void restart_gc() const; @@ -260,7 +256,6 @@ class ZPageAllocator { size_t current_max_capacity() const; size_t capacity() const; size_t used() const; - size_t used_eden() const; size_t used_generation(ZGenerationId id) const; size_t unused() const; diff --git a/src/hotspot/share/gc/z/zTLABUsage.cpp b/src/hotspot/share/gc/z/zTLABUsage.cpp index 569f46a4352eb..9c042360c5318 100644 --- a/src/hotspot/share/gc/z/zTLABUsage.cpp +++ b/src/hotspot/share/gc/z/zTLABUsage.cpp @@ -22,17 +22,39 @@ */ #include "gc/z/zTLABUsage.hpp" +#include "logging/log.hpp" +#include "runtime/atomic.hpp" ZTLABUsage::ZTLABUsage() - : _used_history() {} + : _used(0), + _used_history() {} -void ZTLABUsage::update(size_t used) { - if (used == 0) { - // Avoid updates for the second young generation collection of a SystemGC + +void ZTLABUsage::add(size_t size) { + Atomic::add(&_used, size, memory_order_relaxed); +} + +void ZTLABUsage::reset() { + size_t current_used = Atomic::xchg(&_used, (size_t) 0); + + // Avoid updates for the second young generation collection of a SystemGC + if (current_used == 0) { return; } - _used_history.add(used); -} + + // Save the old values for logging + size_t old_used = used(); + size_t old_capacity = capacity(); + + // Update the usage history with the current value + _used_history.add(current_used); + + log_debug(gc, tlab)("TLAB usage update: used %zuM -> %zuM, capacity: %zuM -> %zuM", + old_used / M, + used() / M, + old_capacity / M, + capacity() / M); + } size_t ZTLABUsage::used() const { return _used_history.last(); diff --git a/src/hotspot/share/gc/z/zTLABUsage.hpp b/src/hotspot/share/gc/z/zTLABUsage.hpp index 5b4480345fe66..3b6635809b3f3 100644 --- a/src/hotspot/share/gc/z/zTLABUsage.hpp +++ b/src/hotspot/share/gc/z/zTLABUsage.hpp @@ -40,12 +40,14 @@ class ZTLABUsage { private: - TruncatedSeq _used_history; + volatile size_t _used; + TruncatedSeq _used_history; public: ZTLABUsage(); - void update(size_t used); + void add(size_t size); + void reset(); size_t used() const; size_t capacity() const; From f361fc5d4588090652c8daa5ef3dc54657b2a873 Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Tue, 6 May 2025 21:45:55 +0200 Subject: [PATCH 12/14] Problemlist heap sampling test --- test/hotspot/jtreg/ProblemList-zgc.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList-zgc.txt b/test/hotspot/jtreg/ProblemList-zgc.txt index 9571c717641a1..2706e1a3e63be 100644 --- a/test/hotspot/jtreg/ProblemList-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-zgc.txt @@ -116,6 +116,9 @@ serviceability/sa/sadebugd/PmapOnDebugdTest.java 8307393 generic- serviceability/sa/sadebugd/RunCommandOnServerTest.java 8307393 generic-all serviceability/sa/sadebugd/SADebugDTest.java 8307393 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorInterpreterObjectTest.java 8356372 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorStatObjectCorrectnessTest.java 8356372 generic-all + vmTestbase/gc/gctests/MemoryEaterMT/MemoryEaterMT.java 8289582 windows-x64 compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DataPatchTest.java 8343233 generic-all From ba7cb6735ded9c6dd6f1ba0b3be0ce357b808f5a Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Thu, 8 May 2025 09:07:42 +0200 Subject: [PATCH 13/14] Handle inc and dec in alloc/undo --- src/hotspot/share/gc/z/zArguments.cpp | 4 +-- src/hotspot/share/gc/z/zHeap.cpp | 37 ++++++++++++++++----- src/hotspot/share/gc/z/zHeap.hpp | 6 ++-- src/hotspot/share/gc/z/zObjectAllocator.cpp | 6 ---- src/hotspot/share/gc/z/zTLABUsage.cpp | 13 +++++--- src/hotspot/share/gc/z/zTLABUsage.hpp | 3 +- 6 files changed, 46 insertions(+), 23 deletions(-) diff --git a/src/hotspot/share/gc/z/zArguments.cpp b/src/hotspot/share/gc/z/zArguments.cpp index b54fb503d2e11..0de80765dd5d1 100644 --- a/src/hotspot/share/gc/z/zArguments.cpp +++ b/src/hotspot/share/gc/z/zArguments.cpp @@ -133,9 +133,9 @@ void ZArguments::initialize() { FLAG_SET_ERGO_IF_DEFAULT(ZCollectionIntervalMajor, ZCollectionInterval); } - // Set a small initial TLAB size to avoid depending on the current capacity + // Set an initial TLAB size to avoid depending on the current capacity if (FLAG_IS_DEFAULT(TLABSize)) { - FLAG_SET_DEFAULT(TLABSize, 8*K); + FLAG_SET_DEFAULT(TLABSize, 256*K); } // Set medium page size here because MaxTenuringThreshold may use it. diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index 90f151a6039f7..e99e32db8a51b 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -157,11 +157,6 @@ size_t ZHeap::unsafe_max_tlab_alloc() const { return MIN2(size, max_tlab_size()); } - -void ZHeap::increment_tlab_used() { - _tlab_usage.add(ZPageSizeSmall); -} - void ZHeap::reset_tlab_used() { _tlab_usage.reset(); } @@ -228,11 +223,38 @@ void ZHeap::out_of_memory() { log_info(gc)("Out Of Memory (%s)", Thread::current()->name()); } +static bool is_small_eden_page(ZPage* page) { + return page->type() == ZPageType::small && page->age() == ZPageAge::eden; +} + +void ZHeap::account_alloc_page(ZPage* page) { + // Do TLAB accounting for small eden pages + if (is_small_eden_page(page)) { + _tlab_usage.increase_used(page->size()); + } +} + +void ZHeap::account_undo_alloc_page(ZPage* page) { + // Increase the undo counter + ZStatInc(ZCounterUndoPageAllocation); + + // Undo TLAB accounting for small eden pages + if (is_small_eden_page(page)) { + _tlab_usage.decrease_used(page->size()); + } + + log_trace(gc)("Undo page allocation, thread: " PTR_FORMAT " (%s), page: " PTR_FORMAT ", size: %zu", + p2i(Thread::current()), ZUtils::thread_name(), p2i(page), page->size()); +} + ZPage* ZHeap::alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age) { ZPage* const page = _page_allocator.alloc_page(type, size, flags, age); if (page != nullptr) { // Insert page table entry _page_table.insert(page); + + // Do accounting for the allocated page + account_alloc_page(page); } return page; @@ -241,9 +263,8 @@ ZPage* ZHeap::alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZP void ZHeap::undo_alloc_page(ZPage* page) { assert(page->is_allocating(), "Invalid page state"); - ZStatInc(ZCounterUndoPageAllocation); - log_trace(gc)("Undo page allocation, thread: " PTR_FORMAT " (%s), page: " PTR_FORMAT ", size: %zu", - p2i(Thread::current()), ZUtils::thread_name(), p2i(page), page->size()); + // Undo accounting for the page being freed + account_undo_alloc_page(page); free_page(page); } diff --git a/src/hotspot/share/gc/z/zHeap.hpp b/src/hotspot/share/gc/z/zHeap.hpp index cee8b0d301190..60a40d5722ed9 100644 --- a/src/hotspot/share/gc/z/zHeap.hpp +++ b/src/hotspot/share/gc/z/zHeap.hpp @@ -60,6 +60,10 @@ class ZHeap { bool _initialized; + // Page allocation accounting + void account_alloc_page(ZPage* page); + void account_undo_alloc_page(ZPage* page); + public: static ZHeap* heap(); @@ -84,8 +88,6 @@ class ZHeap { size_t tlab_used() const; size_t max_tlab_size() const; size_t unsafe_max_tlab_alloc() const; - - void increment_tlab_used(); void reset_tlab_used(); bool is_in(uintptr_t addr) const; diff --git a/src/hotspot/share/gc/z/zObjectAllocator.cpp b/src/hotspot/share/gc/z/zObjectAllocator.cpp index fc04057ba9223..b92828e24a683 100644 --- a/src/hotspot/share/gc/z/zObjectAllocator.cpp +++ b/src/hotspot/share/gc/z/zObjectAllocator.cpp @@ -109,12 +109,6 @@ zaddress ZObjectAllocator::alloc_object_in_shared_page(ZPage** shared_page, // Undo new page allocation undo_alloc_page(new_page); - } else { - // Page successfully installed - if (_age == ZPageAge::eden && page_type == ZPageType::small) { - // Increment TLAB usage for small eden pages - ZHeap::heap()->increment_tlab_used(); - } } } } diff --git a/src/hotspot/share/gc/z/zTLABUsage.cpp b/src/hotspot/share/gc/z/zTLABUsage.cpp index 9c042360c5318..30f2851fb1380 100644 --- a/src/hotspot/share/gc/z/zTLABUsage.cpp +++ b/src/hotspot/share/gc/z/zTLABUsage.cpp @@ -30,12 +30,17 @@ ZTLABUsage::ZTLABUsage() _used_history() {} -void ZTLABUsage::add(size_t size) { +void ZTLABUsage::increase_used(size_t size) { Atomic::add(&_used, size, memory_order_relaxed); } +void ZTLABUsage::decrease_used(size_t size) { + precond(size <= _used); + Atomic::sub(&_used, size, memory_order_relaxed); +} + void ZTLABUsage::reset() { - size_t current_used = Atomic::xchg(&_used, (size_t) 0); + const size_t current_used = Atomic::xchg(&_used, (size_t) 0); // Avoid updates for the second young generation collection of a SystemGC if (current_used == 0) { @@ -43,8 +48,8 @@ void ZTLABUsage::reset() { } // Save the old values for logging - size_t old_used = used(); - size_t old_capacity = capacity(); + const size_t old_used = used(); + const size_t old_capacity = capacity(); // Update the usage history with the current value _used_history.add(current_used); diff --git a/src/hotspot/share/gc/z/zTLABUsage.hpp b/src/hotspot/share/gc/z/zTLABUsage.hpp index 3b6635809b3f3..bdfb8c4ef7d20 100644 --- a/src/hotspot/share/gc/z/zTLABUsage.hpp +++ b/src/hotspot/share/gc/z/zTLABUsage.hpp @@ -46,7 +46,8 @@ class ZTLABUsage { public: ZTLABUsage(); - void add(size_t size); + void increase_used(size_t size); + void decrease_used(size_t size); void reset(); size_t used() const; From 2f5742fce16673a8da90ebab8681c0c37d943bca Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Fri, 9 May 2025 09:36:02 +0200 Subject: [PATCH 14/14] StefanK review --- src/hotspot/share/gc/z/zHeap.cpp | 4 ++-- src/hotspot/share/gc/z/zTLABUsage.cpp | 26 +++++++++++++------------- src/hotspot/share/gc/z/zTLABUsage.hpp | 9 ++++++--- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index e99e32db8a51b..96679d0723b6c 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -132,11 +132,11 @@ size_t ZHeap::unused() const { } size_t ZHeap::tlab_capacity() const { - return _tlab_usage.capacity(); + return _tlab_usage.tlab_capacity(); } size_t ZHeap::tlab_used() const { - return _tlab_usage.used(); + return _tlab_usage.tlab_used(); } size_t ZHeap::max_tlab_size() const { diff --git a/src/hotspot/share/gc/z/zTLABUsage.cpp b/src/hotspot/share/gc/z/zTLABUsage.cpp index 30f2851fb1380..cd8141e47ffbb 100644 --- a/src/hotspot/share/gc/z/zTLABUsage.cpp +++ b/src/hotspot/share/gc/z/zTLABUsage.cpp @@ -29,42 +29,42 @@ ZTLABUsage::ZTLABUsage() : _used(0), _used_history() {} - void ZTLABUsage::increase_used(size_t size) { Atomic::add(&_used, size, memory_order_relaxed); } void ZTLABUsage::decrease_used(size_t size) { precond(size <= _used); + Atomic::sub(&_used, size, memory_order_relaxed); } void ZTLABUsage::reset() { - const size_t current_used = Atomic::xchg(&_used, (size_t) 0); + const size_t used = Atomic::xchg(&_used, (size_t) 0); - // Avoid updates for the second young generation collection of a SystemGC - if (current_used == 0) { + // Avoid updates when nothing has been allocated since the last YC + if (used == 0) { return; } // Save the old values for logging - const size_t old_used = used(); - const size_t old_capacity = capacity(); + const size_t old_tlab_used = tlab_used(); + const size_t old_tlab_capacity = tlab_capacity(); // Update the usage history with the current value - _used_history.add(current_used); + _used_history.add(used); log_debug(gc, tlab)("TLAB usage update: used %zuM -> %zuM, capacity: %zuM -> %zuM", - old_used / M, - used() / M, - old_capacity / M, - capacity() / M); + old_tlab_used / M, + tlab_used() / M, + old_tlab_capacity / M, + tlab_capacity() / M); } -size_t ZTLABUsage::used() const { +size_t ZTLABUsage::tlab_used() const { return _used_history.last(); } -size_t ZTLABUsage::capacity() const { +size_t ZTLABUsage::tlab_capacity() const { return _used_history.davg(); } diff --git a/src/hotspot/share/gc/z/zTLABUsage.hpp b/src/hotspot/share/gc/z/zTLABUsage.hpp index bdfb8c4ef7d20..3d1b084fe161c 100644 --- a/src/hotspot/share/gc/z/zTLABUsage.hpp +++ b/src/hotspot/share/gc/z/zTLABUsage.hpp @@ -36,11 +36,14 @@ // ZGC does not have set generation sizes unlike most other GCs and because of // this there is no fixed TLAB capacity. For the common TLAB sizing heuristic // to work properly ZGC estimates the current capacity by using a weighted -// average of the last 10 used values. +// average of the last 10 used values. ZGC uses the last snapshotted value as +// the value returned as tlab_used(). class ZTLABUsage { private: + // Accounting TLAB used until the next GC cycle volatile size_t _used; + // Sequence of historic used values TruncatedSeq _used_history; public: @@ -50,8 +53,8 @@ class ZTLABUsage { void decrease_used(size_t size); void reset(); - size_t used() const; - size_t capacity() const; + size_t tlab_used() const; + size_t tlab_capacity() const; }; #endif // SHARE_GC_Z_ZTLABUSAGE_HPP