Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/hotspot/share/gc/z/zPageAllocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1936,7 +1936,7 @@ void ZPageAllocator::cleanup_failed_commit_multi_partition(ZMultiPartitionAlloca
}

const size_t committed = allocation->committed_capacity();
const ZVirtualMemory non_harvested_vmem = vmem.last_part(allocation->harvested());
const ZVirtualMemory non_harvested_vmem = partial_vmem.last_part(allocation->harvested());
const ZVirtualMemory committed_vmem = non_harvested_vmem.first_part(committed);
const ZVirtualMemory non_committed_vmem = non_harvested_vmem.last_part(committed);

Expand Down
13 changes: 12 additions & 1 deletion src/hotspot/share/gc/z/zPhysicalMemoryManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,20 @@ void ZPhysicalMemoryManager::free(const ZVirtualMemory& vmem, uint32_t numa_id)
});
}

static size_t inject_commit_limit(const ZVirtualMemory& vmem) {
// To facilitate easier interoperability with multi partition allocations we
// divide by ZNUMA::count(). Users of ZFailLargerCommits need to be aware of
// this when writing tests. In the future we could probe the VirtualMemoryManager
// and condition this division on whether the vmem is in the multi partition
// address space.
return align_up(MIN2(ZFailLargerCommits / ZNUMA::count(), vmem.size()), ZGranuleSize);
}

size_t ZPhysicalMemoryManager::commit(const ZVirtualMemory& vmem, uint32_t numa_id) {
zbacking_index* const pmem = _physical_mappings.addr(vmem.start());
const size_t size = vmem.size();
const size_t size = ZFailLargerCommits > 0
? inject_commit_limit(vmem)
: vmem.size();

size_t total_committed = 0;

Expand Down
5 changes: 5 additions & 0 deletions src/hotspot/share/gc/z/z_globals.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@
develop(bool, ZVerifyOops, false, \
"Verify accessed oops") \
\
develop(size_t, ZFailLargerCommits, 0, \
"Commits larger than ZFailLargerCommits will be truncated, " \
"used to stress page allocation commit failure paths " \
"(0: Disabled)") \
\
develop(uint, ZFakeNUMA, 1, \
"ZFakeNUMA is used to test the internal NUMA memory support " \
"without the need for UseNUMA") \
Expand Down
103 changes: 103 additions & 0 deletions test/hotspot/jtreg/gc/z/TestCommitFailure.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* 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.
*/

package gc.z;

/*
* @test id=ZFakeNUMA
* @requires vm.gc.Z & vm.debug
* @library / /test/lib
* @summary Test ZGC graceful failure when a commit fails (with ZFakeNUMA)
* @run driver gc.z.TestCommitFailure -XX:ZFakeNUMA=16
*/

import jdk.test.lib.process.ProcessTools;

import static gc.testlibrary.Allocation.blackHole;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class TestCommitFailure {
static final int K = 1024;
static final int M = 1024 * K;

static final int XMS = 128 * M;
static final int XMX = 512 * M;

static class Test {
static final int LARGE_ALLOC = 256 * M;
static final int SMALL_GARBAGE = 256 * M;
static final int SMALL_LIVE = 128 * M;

// Allocates at least totalLive bytes of objects and add them to list.
static void allocLive(List<Object> list, int totalLive) {
final int largePageAllocationSize = 6 * M;
for (int live = 0; live < totalLive; live += largePageAllocationSize) {
list.add(new byte[largePageAllocationSize - K]);
}
}

// Allocates at least totalGarbage bytes of garbage large pages.
static void allocGarbage(int totalGarbage) {
final int largePageAllocationSize = 6 * M;
for (int garbage = 0; garbage < totalGarbage; garbage += largePageAllocationSize) {
blackHole(new byte[largePageAllocationSize - K]);
}
}

public static void main(String[] args) {
final var list = new ArrayList<Object>();
try {
// Fill heap with small live objects
allocLive(list, SMALL_LIVE);
// Fill with small garbage objects
allocGarbage(SMALL_GARBAGE);
// Allocate large objects where commit fails until an OOME is thrown
while (true) {
list.add(new byte[LARGE_ALLOC - K]);
}
} catch (OutOfMemoryError oome) {}
blackHole(list);
}
}

public static void main(String[] args) throws Exception {
final int xmxInM = XMX / M;
final int xmsInM = XMS / M;
final var arguments = new ArrayList(Arrays.asList(args));
arguments.addAll(List.of(
"-XX:+UseZGC",
"-Xlog:gc+init",
"-XX:ZFailLargerCommits=" + XMS,
"-Xms" + xmsInM + "M",
"-Xmx" + xmxInM + "M",
Test.class.getName()));

ProcessTools.executeTestJava(arguments)
.outputTo(System.out)
.errorTo(System.out)
.shouldHaveExitValue(0);
}
}