8271195: Use largest available large page size smaller than LargePageSizeInBytes when available

Co-authored-by: Jatin Bhateja <jbhateja@openjdk.org>
Reviewed-by: ayang, tschatzl
This commit is contained in:
Swati Sharma 2022-03-16 09:48:09 +00:00 committed by Jatin Bhateja
parent de4f04cb71
commit 08cadb4754
3 changed files with 95 additions and 22 deletions
src/hotspot
os/linux
share/memory
test/micro/org/openjdk/bench/vm/gc

@ -3972,23 +3972,14 @@ char* os::Linux::reserve_memory_special_shm(size_t bytes, size_t alignment,
return addr;
}
static void warn_on_commit_special_failure(char* req_addr, size_t bytes,
static void log_on_commit_special_failure(char* req_addr, size_t bytes,
size_t page_size, int error) {
assert(error == ENOMEM, "Only expect to fail if no memory is available");
bool warn_on_failure = UseLargePages &&
(!FLAG_IS_DEFAULT(UseLargePages) ||
!FLAG_IS_DEFAULT(UseHugeTLBFS) ||
!FLAG_IS_DEFAULT(LargePageSizeInBytes));
if (warn_on_failure) {
char msg[128];
jio_snprintf(msg, sizeof(msg), "Failed to reserve and commit memory. req_addr: "
PTR_FORMAT " bytes: " SIZE_FORMAT " page size: "
SIZE_FORMAT " (errno = %d).",
req_addr, bytes, page_size, error);
warning("%s", msg);
}
log_info(pagesize)("Failed to reserve and commit memory with given page size. req_addr: " PTR_FORMAT
" size: " SIZE_FORMAT "%s, page size: " SIZE_FORMAT "%s, (errno = %d)",
p2i(req_addr), byte_size_in_exact_unit(bytes), exact_unit_for_byte_size(bytes),
byte_size_in_exact_unit(page_size), exact_unit_for_byte_size(page_size), error);
}
bool os::Linux::commit_memory_special(size_t bytes,
@ -4010,7 +4001,7 @@ bool os::Linux::commit_memory_special(size_t bytes,
char* addr = (char*)::mmap(req_addr, bytes, prot, flags, -1, 0);
if (addr == MAP_FAILED) {
warn_on_commit_special_failure(req_addr, bytes, page_size, errno);
log_on_commit_special_failure(req_addr, bytes, page_size, errno);
return false;
}

@ -139,6 +139,19 @@ static bool large_pages_requested() {
(!FLAG_IS_DEFAULT(UseLargePages) || !FLAG_IS_DEFAULT(LargePageSizeInBytes));
}
static void log_on_large_pages_failure(char* req_addr, size_t bytes) {
if (large_pages_requested()) {
// Compressed oops logging.
log_debug(gc, heap, coops)("Reserve regular memory without large pages");
// JVM style warning that we did not succeed in using large pages.
char msg[128];
jio_snprintf(msg, sizeof(msg), "Failed to reserve and commit memory using large pages. "
"req_addr: " PTR_FORMAT " bytes: " SIZE_FORMAT,
req_addr, bytes);
warning("%s", msg);
}
}
static char* reserve_memory(char* requested_address, const size_t size,
const size_t alignment, int fd, bool exec) {
char* base;
@ -183,10 +196,6 @@ static char* reserve_memory_special(char* requested_address, const size_t size,
"reserve_memory_special() returned an unaligned address, base: " PTR_FORMAT
" alignment: " SIZE_FORMAT_HEX,
p2i(base), alignment);
} else {
if (large_pages_requested()) {
log_debug(gc, heap, coops)("Reserve regular memory without large pages");
}
}
return base;
}
@ -235,14 +244,25 @@ void ReservedSpace::reserve(size_t size,
// the caller requested large pages. To satisfy this request we use
// explicit large pages and these have to be committed up front to ensure
// no reservations are lost.
size_t used_page_size = page_size;
char* base = NULL;
do {
base = reserve_memory_special(requested_address, size, alignment, used_page_size, executable);
if (base != NULL) {
break;
}
used_page_size = os::page_sizes().next_smaller(used_page_size);
} while (used_page_size > (size_t) os::vm_page_size());
char* base = reserve_memory_special(requested_address, size, alignment, page_size, executable);
if (base != NULL) {
// Successful reservation using large pages.
initialize_members(base, size, alignment, page_size, true, executable);
initialize_members(base, size, alignment, used_page_size, true, executable);
return;
}
// Failed to reserve explicit large pages, fall back to normal reservation.
// Failed to reserve explicit large pages, do proper logging.
log_on_large_pages_failure(requested_address, size);
// Now fall back to normal reservation.
page_size = os::vm_page_size();
}

@ -0,0 +1,62 @@
//
// Copyright (c) 2022, 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 org.openjdk.bench.vm.gc;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.*;
@OutputTimeUnit(TimeUnit.MINUTES)
@State(Scope.Thread)
@Fork(jvmArgsAppend = {"-Xmx256m", "-XX:+UseLargePages", "-XX:LargePageSizeInBytes=1g", "-Xlog:pagesize"}, value = 5)
public class MicroLargePages {
@Param({"2097152"})
public int ARRAYSIZE;
@Param({"1", "2", "4"})
public int NUM;
public long[][] INP;
public long[][] OUT;
@Setup(Level.Trial)
public void BmSetup() {
INP = new long[NUM][ARRAYSIZE];
OUT = new long[NUM][ARRAYSIZE];
for (int i = 0; i < NUM; i++) {
Arrays.fill(INP[i], 10);
}
}
@Benchmark
public void micro_HOP_DIST_4KB() {
for (int i = 0; i < NUM; i += 1) {
for (int j = 0; j < ARRAYSIZE; j += 512) {
OUT[i][j] = INP[i][j];
}
}
}
}