From 29a5de085a4eb746dcad637ced4cb719a59c3013 Mon Sep 17 00:00:00 2001 From: Joachim Kern Date: Wed, 5 Feb 2025 09:50:20 +0000 Subject: [PATCH] 8334371: [AIX] Beginning with AIX 7.3 TL1 mmap() supports 64K memory pages Reviewed-by: mdoerr, stuefe Backport-of: ced99066354fc6a32c587b9e3c35b07e26d3452e --- src/hotspot/os/aix/os_aix.cpp | 130 ++++++++++++++-------- src/hotspot/os/aix/os_aix.hpp | 1 + src/hotspot/share/memory/virtualspace.cpp | 4 +- 3 files changed, 89 insertions(+), 46 deletions(-) diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 70097b8dd32..27adf36413c 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -74,6 +74,7 @@ #include "services/runtimeService.hpp" #include "signals_posix.hpp" #include "utilities/align.hpp" +#include "utilities/debug.hpp" #include "utilities/decoder.hpp" #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" @@ -100,6 +101,12 @@ #include #include #include +// sys/mman.h defines MAP_ANON_64K beginning with AIX7.3 TL1 +#ifndef MAP_ANON_64K + #define MAP_ANON_64K 0x400 +#else + STATIC_ASSERT(MAP_ANON_64K == 0x400); +#endif #include #include #include @@ -224,21 +231,22 @@ static address g_brk_at_startup = nullptr; // http://publib.boulder.ibm.com/infocenter/aix/v6r1/index.jsp?topic=/com.ibm.aix.prftungd/doc/prftungd/multiple_page_size_app_support.htm // static struct { - size_t pagesize; // sysconf _SC_PAGESIZE (4K) - size_t datapsize; // default data page size (LDR_CNTRL DATAPSIZE) - size_t shmpsize; // default shared memory page size (LDR_CNTRL SHMPSIZE) - size_t pthr_stack_pagesize; // stack page size of pthread threads - size_t textpsize; // default text page size (LDR_CNTRL STACKPSIZE) - bool can_use_64K_pages; // True if we can alloc 64K pages dynamically with Sys V shm. - bool can_use_16M_pages; // True if we can alloc 16M pages dynamically with Sys V shm. - int error; // Error describing if something went wrong at multipage init. + size_t pagesize; // sysconf _SC_PAGESIZE (4K) + size_t datapsize; // default data page size (LDR_CNTRL DATAPSIZE) + size_t shmpsize; // default shared memory page size (LDR_CNTRL SHMPSIZE) + size_t pthr_stack_pagesize; // stack page size of pthread threads + size_t textpsize; // default text page size (LDR_CNTRL STACKPSIZE) + bool can_use_64K_pages; // True if we can alloc 64K pages dynamically with Sys V shm. + bool can_use_16M_pages; // True if we can alloc 16M pages dynamically with Sys V shm. + bool can_use_64K_mmap_pages; // True if we can alloc 64K pages dynamically with mmap. + int error; // Error describing if something went wrong at multipage init. } g_multipage_support = { (size_t) -1, (size_t) -1, (size_t) -1, (size_t) -1, (size_t) -1, - false, false, + false, false, false, 0 }; @@ -393,12 +401,16 @@ static void query_multipage_support() { // our own page size after allocated. { const int shmid = ::shmget(IPC_PRIVATE, 1, IPC_CREAT | S_IRUSR | S_IWUSR); - guarantee(shmid != -1, "shmget failed"); - void* p = ::shmat(shmid, nullptr, 0); - ::shmctl(shmid, IPC_RMID, nullptr); - guarantee(p != (void*) -1, "shmat failed"); - g_multipage_support.shmpsize = os::Aix::query_pagesize(p); - ::shmdt(p); + assert(shmid != -1, "shmget failed"); + if (shmid != -1) { + void* p = ::shmat(shmid, nullptr, 0); + ::shmctl(shmid, IPC_RMID, nullptr); + assert(p != (void*) -1, "shmat failed"); + if (p != (void*) -1) { + g_multipage_support.shmpsize = os::Aix::query_pagesize(p); + ::shmdt(p); + } + } } // Before querying the stack page size, make sure we are not running as primordial @@ -458,26 +470,30 @@ static void query_multipage_support() { trcVerbose("Probing support for %s pages...", describe_pagesize(pagesize)); const int shmid = ::shmget(IPC_PRIVATE, pagesize, IPC_CREAT | S_IRUSR | S_IWUSR); - guarantee0(shmid != -1); // Should always work. - // Try to set pagesize. - struct shmid_ds shm_buf = { }; - shm_buf.shm_pagesize = pagesize; - if (::shmctl(shmid, SHM_PAGESIZE, &shm_buf) != 0) { - const int en = errno; - ::shmctl(shmid, IPC_RMID, nullptr); // As early as possible! - trcVerbose("shmctl(SHM_PAGESIZE) failed with errno=%d", errno); - } else { - // Attach and double check pageisze. - void* p = ::shmat(shmid, nullptr, 0); - ::shmctl(shmid, IPC_RMID, nullptr); // As early as possible! - guarantee0(p != (void*) -1); // Should always work. - const size_t real_pagesize = os::Aix::query_pagesize(p); - if (real_pagesize != pagesize) { - trcVerbose("real page size (" SIZE_FORMAT_X ") differs.", real_pagesize); + assert(shmid != -1, "shmget failed"); + if (shmid != -1) { + // Try to set pagesize. + struct shmid_ds shm_buf = { }; + shm_buf.shm_pagesize = pagesize; + if (::shmctl(shmid, SHM_PAGESIZE, &shm_buf) != 0) { + const int en = errno; + ::shmctl(shmid, IPC_RMID, nullptr); // As early as possible! + trcVerbose("shmctl(SHM_PAGESIZE) failed with errno=%d", errno); } else { - can_use = true; + // Attach and double check pageisze. + void* p = ::shmat(shmid, nullptr, 0); + ::shmctl(shmid, IPC_RMID, nullptr); // As early as possible! + assert(p != (void*) -1, "shmat failed"); + if (p != (void*) -1) { + const size_t real_pagesize = os::Aix::query_pagesize(p); + if (real_pagesize != pagesize) { + log_warning(pagesize)("real page size (" SIZE_FORMAT_X ") differs.", real_pagesize); + } else { + can_use = true; + } + ::shmdt(p); + } } - ::shmdt(p); } trcVerbose("Can use: %s", (can_use ? "yes" : "no")); if (pagesize == 64*K) { @@ -487,6 +503,16 @@ static void query_multipage_support() { } } + // Can we use mmap with 64K pages? (Should be available with AIX7.3 TL1) + { + void* p = mmap(NULL, 64*K, PROT_READ | PROT_WRITE, MAP_ANON_64K | MAP_ANONYMOUS | MAP_SHARED, -1, 0); + assert(p != (void*) -1, "mmap failed"); + if (p != (void*) -1) { + g_multipage_support.can_use_64K_mmap_pages = (64*K == os::Aix::query_pagesize(p)); + munmap(p, 64*K); + } + } + } // end: check which pages can be used for shared memory query_multipage_support_end: @@ -499,6 +525,8 @@ static void query_multipage_support() { describe_pagesize(g_multipage_support.textpsize)); trcVerbose("Thread stack page size (pthread): %s", describe_pagesize(g_multipage_support.pthr_stack_pagesize)); + trcVerbose("Can use 64K pages with mmap memory: %s", + (g_multipage_support.can_use_64K_mmap_pages ? "yes" :"no")); trcVerbose("Default shared memory page size: %s", describe_pagesize(g_multipage_support.shmpsize)); trcVerbose("Can use 64K pages dynamically with shared memory: %s", @@ -1230,6 +1258,8 @@ void os::print_memory_info(outputStream* st) { describe_pagesize(g_multipage_support.textpsize)); st->print_cr(" Thread stack page size (pthread): %s", describe_pagesize(g_multipage_support.pthr_stack_pagesize)); + st->print_cr(" Can use 64K pages with mmap memory: %s", + (g_multipage_support.can_use_64K_mmap_pages ? "yes" :"no")); st->print_cr(" Default shared memory page size: %s", describe_pagesize(g_multipage_support.shmpsize)); st->print_cr(" Can use 64K pages dynamically with shared memory: %s", @@ -1689,6 +1719,10 @@ static char* reserve_mmaped_memory(size_t bytes, char* requested_addr) { // later use msync(MS_INVALIDATE) (see os::uncommit_memory). int flags = MAP_ANONYMOUS | MAP_SHARED; + if (os::vm_page_size() == 64*K && g_multipage_support.can_use_64K_mmap_pages) { + flags |= MAP_ANON_64K; + } + // MAP_FIXED is needed to enforce requested_addr - manpage is vague about what // it means if wishaddress is given but MAP_FIXED is not set. // @@ -1732,7 +1766,11 @@ static char* reserve_mmaped_memory(size_t bytes, char* requested_addr) { p2i(addr), p2i(addr + bytes), bytes); // bookkeeping - vmembk_add(addr, size, 4*K, VMEM_MAPPED); + if (os::vm_page_size() == 64*K && g_multipage_support.can_use_64K_mmap_pages) { + vmembk_add(addr, size, 64*K, VMEM_MAPPED); + } else { + vmembk_add(addr, size, 4*K, VMEM_MAPPED); + } // Test alignment, see above. assert0(is_aligned_to(addr, os::vm_page_size())); @@ -1921,8 +1959,8 @@ char* os::pd_reserve_memory(size_t bytes, bool exec) { bytes = align_up(bytes, os::vm_page_size()); // In 4K mode always use mmap. - // In 64K mode allocate small sizes with mmap, large ones with 64K shmatted. - if (os::vm_page_size() == 4*K) { + // In 64K mode allocate with mmap if it supports 64K pages, otherwise use 64K shmatted. + if (os::vm_page_size() == 4*K || g_multipage_support.can_use_64K_mmap_pages) { return reserve_mmaped_memory(bytes, nullptr /* requested_addr */); } else { if (bytes >= Use64KPagesThreshold) { @@ -2139,8 +2177,8 @@ char* os::pd_attempt_reserve_memory_at(char* requested_addr, size_t bytes, bool bytes = align_up(bytes, os::vm_page_size()); // In 4K mode always use mmap. - // In 64K mode allocate small sizes with mmap, large ones with 64K shmatted. - if (os::vm_page_size() == 4*K) { + // In 64K mode allocate with mmap if it supports 64K pages, otherwise use 64K shmatted. + if (os::vm_page_size() == 4*K || g_multipage_support.can_use_64K_mmap_pages) { return reserve_mmaped_memory(bytes, requested_addr); } else { if (bytes >= Use64KPagesThreshold) { @@ -2277,18 +2315,18 @@ void os::init(void) { // and should be allocated with 64k pages. // // So, we do the following: - // LDR_CNTRL can_use_64K_pages_dynamically what we do remarks - // 4K no 4K old systems (aix 5.2, as/400 v5r4) or new systems with AME activated - // 4k yes 64k (treat 4k stacks as 64k) different loader than java and standard settings + // LDR_CNTRL can_use_64K_pages_dynamically(mmap or shm) what we do remarks + // 4K no 4K old systems (aix 5.2) or new systems with AME activated + // 4k yes 64k (treat 4k stacks as 64k) different loader than java and standard settings // 64k no --- AIX 5.2 ? --- - // 64k yes 64k new systems and standard java loader (we set datapsize=64k when linking) + // 64k yes 64k new systems and standard java loader (we set datapsize=64k when linking) // We explicitly leave no option to change page size, because only upgrading would work, // not downgrading (if stack page size is 64k you cannot pretend its 4k). if (g_multipage_support.datapsize == 4*K) { // datapsize = 4K. Data segment, thread stacks are 4K paged. - if (g_multipage_support.can_use_64K_pages) { + if (g_multipage_support.can_use_64K_pages || g_multipage_support.can_use_64K_mmap_pages) { // .. but we are able to use 64K pages dynamically. // This would be typical for java launchers which are not linked // with datapsize=64K (like, any other launcher but our own). @@ -2318,7 +2356,7 @@ void os::init(void) { // This normally means that we can allocate 64k pages dynamically. // (There is one special case where this may be false: EXTSHM=on. // but we decided to not support that mode). - assert0(g_multipage_support.can_use_64K_pages); + assert0(g_multipage_support.can_use_64K_pages || g_multipage_support.can_use_64K_mmap_pages); set_page_size(64*K); trcVerbose("64K page mode"); FLAG_SET_ERGO(Use64KPages, true); @@ -2919,6 +2957,10 @@ void os::Aix::initialize_libperfstat() { } } +bool os::Aix::supports_64K_mmap_pages() { + return g_multipage_support.can_use_64K_mmap_pages; +} + ///////////////////////////////////////////////////////////////////////////// // thread stack diff --git a/src/hotspot/os/aix/os_aix.hpp b/src/hotspot/os/aix/os_aix.hpp index 22fb5327bf9..8cb49b5fe74 100644 --- a/src/hotspot/os/aix/os_aix.hpp +++ b/src/hotspot/os/aix/os_aix.hpp @@ -82,6 +82,7 @@ class os::Aix { public: static void init_thread_fpu_state(); static pthread_t main_thread(void) { return _main_thread; } + static bool supports_64K_mmap_pages(); // Given an address, returns the size of the page backing that address static size_t query_pagesize(void* p); diff --git a/src/hotspot/share/memory/virtualspace.cpp b/src/hotspot/share/memory/virtualspace.cpp index ae898bec3af..12c89baab7e 100644 --- a/src/hotspot/share/memory/virtualspace.cpp +++ b/src/hotspot/share/memory/virtualspace.cpp @@ -31,7 +31,7 @@ #include "oops/oop.inline.hpp" #include "runtime/globals_extension.hpp" #include "runtime/java.hpp" -#include "runtime/os.hpp" +#include "runtime/os.inline.hpp" #include "services/memTracker.hpp" #include "utilities/align.hpp" #include "utilities/formatBuffer.hpp" @@ -365,7 +365,7 @@ void ReservedHeapSpace::establish_noaccess_prefix() { if (base() && base() + _size > (char *)OopEncodingHeapMax) { if (true WIN64_ONLY(&& !UseLargePages) - AIX_ONLY(&& os::vm_page_size() != 64*K)) { + AIX_ONLY(&& (os::Aix::supports_64K_mmap_pages() || os::vm_page_size() == 4*K))) { // Protect memory at the base of the allocated region. // If special, the page was committed (only matters on windows) if (!os::protect_memory(_base, _noaccess_prefix, os::MEM_PROT_NONE, _special)) {