Skip to content

Commit

Permalink
8334371: [AIX] Beginning with AIX 7.3 TL1 mmap() supports 64K memory …
Browse files Browse the repository at this point in the history
…pages

Reviewed-by: mdoerr, stuefe
Backport-of: ced9906
  • Loading branch information
Joachim Kern committed Feb 5, 2025
1 parent 981ec16 commit 29a5de0
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 46 deletions.
130 changes: 86 additions & 44 deletions src/hotspot/os/aix/os_aix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -100,6 +101,12 @@
#include <sys/ioctl.h>
#include <sys/ipc.h>
#include <sys/mman.h>
// 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 <sys/resource.h>
#include <sys/select.h>
#include <sys/shm.h>
Expand Down Expand Up @@ -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
};

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand All @@ -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:
Expand All @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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.
//
Expand Down Expand Up @@ -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()));
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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).
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions src/hotspot/os/aix/os_aix.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/share/memory/virtualspace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)) {
Expand Down

0 comments on commit 29a5de0

Please sign in to comment.