Skip to content

Commit ced9906

Browse files
author
Joachim Kern
committed
8334371: [AIX] Beginning with AIX 7.3 TL1 mmap() supports 64K memory pages
Reviewed-by: stuefe, mbaesken, mdoerr
1 parent 916db07 commit ced9906

File tree

6 files changed

+135
-59
lines changed

6 files changed

+135
-59
lines changed

src/hotspot/os/aix/os_aix.cpp

Lines changed: 86 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
#include "signals_posix.hpp"
7070
#include "utilities/align.hpp"
7171
#include "utilities/checkedCast.hpp"
72+
#include "utilities/debug.hpp"
7273
#include "utilities/decoder.hpp"
7374
#include "utilities/defaultStream.hpp"
7475
#include "utilities/events.hpp"
@@ -96,6 +97,12 @@
9697
#include <sys/ioctl.h>
9798
#include <sys/ipc.h>
9899
#include <sys/mman.h>
100+
// sys/mman.h defines MAP_ANON_64K beginning with AIX7.3 TL1
101+
#ifndef MAP_ANON_64K
102+
#define MAP_ANON_64K 0x400
103+
#else
104+
STATIC_ASSERT(MAP_ANON_64K == 0x400);
105+
#endif
99106
#include <sys/resource.h>
100107
#include <sys/select.h>
101108
#include <sys/shm.h>
@@ -217,21 +224,22 @@ static address g_brk_at_startup = nullptr;
217224
// http://publib.boulder.ibm.com/infocenter/aix/v6r1/index.jsp?topic=/com.ibm.aix.prftungd/doc/prftungd/multiple_page_size_app_support.htm
218225
//
219226
static struct {
220-
size_t pagesize; // sysconf _SC_PAGESIZE (4K)
221-
size_t datapsize; // default data page size (LDR_CNTRL DATAPSIZE)
222-
size_t shmpsize; // default shared memory page size (LDR_CNTRL SHMPSIZE)
223-
size_t pthr_stack_pagesize; // stack page size of pthread threads
224-
size_t textpsize; // default text page size (LDR_CNTRL STACKPSIZE)
225-
bool can_use_64K_pages; // True if we can alloc 64K pages dynamically with Sys V shm.
226-
bool can_use_16M_pages; // True if we can alloc 16M pages dynamically with Sys V shm.
227-
int error; // Error describing if something went wrong at multipage init.
227+
size_t pagesize; // sysconf _SC_PAGESIZE (4K)
228+
size_t datapsize; // default data page size (LDR_CNTRL DATAPSIZE)
229+
size_t shmpsize; // default shared memory page size (LDR_CNTRL SHMPSIZE)
230+
size_t pthr_stack_pagesize; // stack page size of pthread threads
231+
size_t textpsize; // default text page size (LDR_CNTRL STACKPSIZE)
232+
bool can_use_64K_pages; // True if we can alloc 64K pages dynamically with Sys V shm.
233+
bool can_use_16M_pages; // True if we can alloc 16M pages dynamically with Sys V shm.
234+
bool can_use_64K_mmap_pages; // True if we can alloc 64K pages dynamically with mmap.
235+
int error; // Error describing if something went wrong at multipage init.
228236
} g_multipage_support = {
229237
(size_t) -1,
230238
(size_t) -1,
231239
(size_t) -1,
232240
(size_t) -1,
233241
(size_t) -1,
234-
false, false,
242+
false, false, false,
235243
0
236244
};
237245

@@ -366,12 +374,16 @@ static void query_multipage_support() {
366374
// our own page size after allocated.
367375
{
368376
const int shmid = ::shmget(IPC_PRIVATE, 1, IPC_CREAT | S_IRUSR | S_IWUSR);
369-
guarantee(shmid != -1, "shmget failed");
370-
void* p = ::shmat(shmid, nullptr, 0);
371-
::shmctl(shmid, IPC_RMID, nullptr);
372-
guarantee(p != (void*) -1, "shmat failed");
373-
g_multipage_support.shmpsize = os::Aix::query_pagesize(p);
374-
::shmdt(p);
377+
assert(shmid != -1, "shmget failed");
378+
if (shmid != -1) {
379+
void* p = ::shmat(shmid, nullptr, 0);
380+
::shmctl(shmid, IPC_RMID, nullptr);
381+
assert(p != (void*) -1, "shmat failed");
382+
if (p != (void*) -1) {
383+
g_multipage_support.shmpsize = os::Aix::query_pagesize(p);
384+
::shmdt(p);
385+
}
386+
}
375387
}
376388

377389
// Before querying the stack page size, make sure we are not running as primordial
@@ -421,26 +433,30 @@ static void query_multipage_support() {
421433
trcVerbose("Probing support for %s pages...", describe_pagesize(pagesize));
422434
const int shmid = ::shmget(IPC_PRIVATE, pagesize,
423435
IPC_CREAT | S_IRUSR | S_IWUSR);
424-
guarantee0(shmid != -1); // Should always work.
425-
// Try to set pagesize.
426-
struct shmid_ds shm_buf = { };
427-
shm_buf.shm_pagesize = pagesize;
428-
if (::shmctl(shmid, SHM_PAGESIZE, &shm_buf) != 0) {
429-
const int en = errno;
430-
::shmctl(shmid, IPC_RMID, nullptr); // As early as possible!
431-
log_warning(pagesize)("shmctl(SHM_PAGESIZE) failed with errno=%d", errno);
432-
} else {
433-
// Attach and double check pageisze.
434-
void* p = ::shmat(shmid, nullptr, 0);
435-
::shmctl(shmid, IPC_RMID, nullptr); // As early as possible!
436-
guarantee0(p != (void*) -1); // Should always work.
437-
const size_t real_pagesize = os::Aix::query_pagesize(p);
438-
if (real_pagesize != pagesize) {
439-
log_warning(pagesize)("real page size (" SIZE_FORMAT_X ") differs.", real_pagesize);
436+
assert(shmid != -1, "shmget failed");
437+
if (shmid != -1) {
438+
// Try to set pagesize.
439+
struct shmid_ds shm_buf = { };
440+
shm_buf.shm_pagesize = pagesize;
441+
if (::shmctl(shmid, SHM_PAGESIZE, &shm_buf) != 0) {
442+
const int en = errno;
443+
::shmctl(shmid, IPC_RMID, nullptr); // As early as possible!
444+
log_warning(pagesize)("shmctl(SHM_PAGESIZE) failed with errno=%d", errno);
440445
} else {
441-
can_use = true;
446+
// Attach and double check pageisze.
447+
void* p = ::shmat(shmid, nullptr, 0);
448+
::shmctl(shmid, IPC_RMID, nullptr); // As early as possible!
449+
assert(p != (void*) -1, "shmat failed");
450+
if (p != (void*) -1) {
451+
const size_t real_pagesize = os::Aix::query_pagesize(p);
452+
if (real_pagesize != pagesize) {
453+
log_warning(pagesize)("real page size (" SIZE_FORMAT_X ") differs.", real_pagesize);
454+
} else {
455+
can_use = true;
456+
}
457+
::shmdt(p);
458+
}
442459
}
443-
::shmdt(p);
444460
}
445461
trcVerbose("Can use: %s", (can_use ? "yes" : "no"));
446462
if (pagesize == 64*K) {
@@ -450,6 +466,16 @@ static void query_multipage_support() {
450466
}
451467
}
452468

469+
// Can we use mmap with 64K pages? (Should be available with AIX7.3 TL1)
470+
{
471+
void* p = mmap(NULL, 64*K, PROT_READ | PROT_WRITE, MAP_ANON_64K | MAP_ANONYMOUS | MAP_SHARED, -1, 0);
472+
assert(p != (void*) -1, "mmap failed");
473+
if (p != (void*) -1) {
474+
g_multipage_support.can_use_64K_mmap_pages = (64*K == os::Aix::query_pagesize(p));
475+
munmap(p, 64*K);
476+
}
477+
}
478+
453479
} // end: check which pages can be used for shared memory
454480

455481
query_multipage_support_end:
@@ -462,6 +488,8 @@ static void query_multipage_support() {
462488
describe_pagesize(g_multipage_support.textpsize));
463489
trcVerbose("Thread stack page size (pthread): %s",
464490
describe_pagesize(g_multipage_support.pthr_stack_pagesize));
491+
trcVerbose("Can use 64K pages with mmap memory: %s",
492+
(g_multipage_support.can_use_64K_mmap_pages ? "yes" :"no"));
465493
trcVerbose("Default shared memory page size: %s",
466494
describe_pagesize(g_multipage_support.shmpsize));
467495
trcVerbose("Can use 64K pages dynamically with shared memory: %s",
@@ -1133,6 +1161,8 @@ void os::print_memory_info(outputStream* st) {
11331161
describe_pagesize(g_multipage_support.textpsize));
11341162
st->print_cr(" Thread stack page size (pthread): %s",
11351163
describe_pagesize(g_multipage_support.pthr_stack_pagesize));
1164+
st->print_cr(" Can use 64K pages with mmap memory: %s",
1165+
(g_multipage_support.can_use_64K_mmap_pages ? "yes" :"no"));
11361166
st->print_cr(" Default shared memory page size: %s",
11371167
describe_pagesize(g_multipage_support.shmpsize));
11381168
st->print_cr(" Can use 64K pages dynamically with shared memory: %s",
@@ -1612,6 +1642,10 @@ static char* reserve_mmaped_memory(size_t bytes, char* requested_addr) {
16121642
// later use msync(MS_INVALIDATE) (see os::uncommit_memory).
16131643
int flags = MAP_ANONYMOUS | MAP_SHARED;
16141644

1645+
if (os::vm_page_size() == 64*K && g_multipage_support.can_use_64K_mmap_pages) {
1646+
flags |= MAP_ANON_64K;
1647+
}
1648+
16151649
// MAP_FIXED is needed to enforce requested_addr - manpage is vague about what
16161650
// it means if wishaddress is given but MAP_FIXED is not set.
16171651
//
@@ -1661,7 +1695,11 @@ static char* reserve_mmaped_memory(size_t bytes, char* requested_addr) {
16611695
p2i(addr), p2i(addr + bytes), bytes);
16621696

16631697
// bookkeeping
1664-
vmembk_add(addr, size, 4*K, VMEM_MAPPED);
1698+
if (os::vm_page_size() == 64*K && g_multipage_support.can_use_64K_mmap_pages) {
1699+
vmembk_add(addr, size, 64*K, VMEM_MAPPED);
1700+
} else {
1701+
vmembk_add(addr, size, 4*K, VMEM_MAPPED);
1702+
}
16651703

16661704
// Test alignment, see above.
16671705
assert0(is_aligned_to(addr, os::vm_page_size()));
@@ -1854,8 +1892,8 @@ char* os::pd_reserve_memory(size_t bytes, bool exec) {
18541892
bytes = align_up(bytes, os::vm_page_size());
18551893

18561894
// In 4K mode always use mmap.
1857-
// In 64K mode allocate small sizes with mmap, large ones with 64K shmatted.
1858-
if (os::vm_page_size() == 4*K) {
1895+
// In 64K mode allocate with mmap if it supports 64K pages, otherwise use 64K shmatted.
1896+
if (os::vm_page_size() == 4*K || g_multipage_support.can_use_64K_mmap_pages) {
18591897
return reserve_mmaped_memory(bytes, nullptr /* requested_addr */);
18601898
} else {
18611899
return reserve_shmated_memory(bytes, nullptr /* requested_addr */);
@@ -2042,8 +2080,8 @@ char* os::pd_attempt_reserve_memory_at(char* requested_addr, size_t bytes, bool
20422080
bytes = align_up(bytes, os::vm_page_size());
20432081

20442082
// In 4K mode always use mmap.
2045-
// In 64K mode allocate small sizes with mmap, large ones with 64K shmatted.
2046-
if (os::vm_page_size() == 4*K) {
2083+
// In 64K mode allocate with mmap if it supports 64K pages, otherwise use 64K shmatted.
2084+
if (os::vm_page_size() == 4*K || g_multipage_support.can_use_64K_mmap_pages) {
20472085
return reserve_mmaped_memory(bytes, requested_addr);
20482086
} else {
20492087
return reserve_shmated_memory(bytes, requested_addr);
@@ -2183,18 +2221,18 @@ void os::init(void) {
21832221
// and should be allocated with 64k pages.
21842222
//
21852223
// So, we do the following:
2186-
// LDR_CNTRL can_use_64K_pages_dynamically what we do remarks
2187-
// 4K no 4K old systems (aix 5.2) or new systems with AME activated
2188-
// 4k yes 64k (treat 4k stacks as 64k) different loader than java and standard settings
2224+
// LDR_CNTRL can_use_64K_pages_dynamically(mmap or shm) what we do remarks
2225+
// 4K no 4K old systems (aix 5.2) or new systems with AME activated
2226+
// 4k yes 64k (treat 4k stacks as 64k) different loader than java and standard settings
21892227
// 64k no --- AIX 5.2 ? ---
2190-
// 64k yes 64k new systems and standard java loader (we set datapsize=64k when linking)
2228+
// 64k yes 64k new systems and standard java loader (we set datapsize=64k when linking)
21912229

21922230
// We explicitly leave no option to change page size, because only upgrading would work,
21932231
// not downgrading (if stack page size is 64k you cannot pretend its 4k).
21942232

21952233
if (g_multipage_support.datapsize == 4*K) {
21962234
// datapsize = 4K. Data segment, thread stacks are 4K paged.
2197-
if (g_multipage_support.can_use_64K_pages) {
2235+
if (g_multipage_support.can_use_64K_pages || g_multipage_support.can_use_64K_mmap_pages) {
21982236
// .. but we are able to use 64K pages dynamically.
21992237
// This would be typical for java launchers which are not linked
22002238
// with datapsize=64K (like, any other launcher but our own).
@@ -2224,7 +2262,7 @@ void os::init(void) {
22242262
// This normally means that we can allocate 64k pages dynamically.
22252263
// (There is one special case where this may be false: EXTSHM=on.
22262264
// but we decided to not support that mode).
2227-
assert0(g_multipage_support.can_use_64K_pages);
2265+
assert0(g_multipage_support.can_use_64K_pages || g_multipage_support.can_use_64K_mmap_pages);
22282266
set_page_size(64*K);
22292267
trcVerbose("64K page mode");
22302268
FLAG_SET_ERGO(Use64KPages, true);
@@ -2709,6 +2747,10 @@ void os::Aix::initialize_libperfstat() {
27092747
}
27102748
}
27112749

2750+
bool os::Aix::supports_64K_mmap_pages() {
2751+
return g_multipage_support.can_use_64K_mmap_pages;
2752+
}
2753+
27122754
/////////////////////////////////////////////////////////////////////////////
27132755
// thread stack
27142756

src/hotspot/os/aix/os_aix.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class os::Aix {
7676
public:
7777
static void init_thread_fpu_state();
7878
static pthread_t main_thread(void) { return _main_thread; }
79+
static bool supports_64K_mmap_pages();
7980

8081
// Given an address, returns the size of the page backing that address
8182
static size_t query_pagesize(void* p);

src/hotspot/share/memory/virtualspace.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ void ReservedHeapSpace::establish_noaccess_prefix() {
380380
if (base() && base() + _size > (char *)OopEncodingHeapMax) {
381381
if (true
382382
WIN64_ONLY(&& !UseLargePages)
383-
AIX_ONLY(&& os::vm_page_size() != 64*K)) {
383+
AIX_ONLY(&& (os::Aix::supports_64K_mmap_pages() || os::vm_page_size() == 4*K))) {
384384
// Protect memory at the base of the allocated region.
385385
// If special, the page was committed (only matters on windows)
386386
if (!os::protect_memory(_base, _noaccess_prefix, os::MEM_PROT_NONE, _special)) {

src/hotspot/share/runtime/os.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1958,8 +1958,7 @@ char* os::attempt_reserve_memory_between(char* min, char* max, size_t bytes, siz
19581958
// This is not reflected by os_allocation_granularity().
19591959
// The logic here is dual to the one in pd_reserve_memory in os_aix.cpp
19601960
const size_t system_allocation_granularity =
1961-
AIX_ONLY(os::vm_page_size() == 4*K ? 4*K : 256*M)
1962-
NOT_AIX(os::vm_allocation_granularity());
1961+
AIX_ONLY((!os::Aix::supports_64K_mmap_pages() && os::vm_page_size() == 64*K) ? 256*M : ) os::vm_allocation_granularity();
19631962

19641963
const size_t alignment_adjusted = MAX2(alignment, system_allocation_granularity);
19651964

test/hotspot/gtest/runtime/test_os.cpp

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -967,18 +967,6 @@ TEST_VM(os, reserve_at_wish_address_shall_not_replace_mappings_largepages) {
967967
}
968968
}
969969

970-
#ifdef AIX
971-
// On Aix, we should fail attach attempts not aligned to segment boundaries (256m)
972-
TEST_VM(os, aix_reserve_at_non_shmlba_aligned_address) {
973-
if (Use64KPages) {
974-
char* p = os::attempt_reserve_memory_at((char*)0x1f00000, M);
975-
ASSERT_EQ(p, nullptr); // should have failed
976-
p = os::attempt_reserve_memory_at((char*)((64 * G) + M), M);
977-
ASSERT_EQ(p, nullptr); // should have failed
978-
}
979-
}
980-
#endif // AIX
981-
982970
TEST_VM(os, vm_min_address) {
983971
size_t s = os::vm_min_address();
984972
ASSERT_GE(s, M);
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
#include "precompiled.hpp"
25+
26+
#ifdef AIX
27+
28+
#include "runtime/os.inline.hpp"
29+
#include "utilities/debug.hpp"
30+
#include "utilities/globalDefinitions.hpp"
31+
#include "unittest.hpp"
32+
33+
// On Aix, when using shmget() in os::attempt_reserve_memory_at() we should fail with attach
34+
// attempts not aligned to shmget() segment boundaries (256m)
35+
// But shmget() is only used in cases we want to have 64K pages and mmap() does not provide it.
36+
TEST_VM(os_aix, aix_reserve_at_non_shmlba_aligned_address) {
37+
if (os::vm_page_size() != 4*K && !os::Aix::supports_64K_mmap_pages()) {
38+
// With this condition true shmget() is used inside
39+
char* p = os::attempt_reserve_memory_at((char*)0x1f00000, M);
40+
ASSERT_EQ(p, nullptr); // should have failed
41+
p = os::attempt_reserve_memory_at((char*)((64 * G) + M), M);
42+
ASSERT_EQ(p, nullptr); // should have failed
43+
}
44+
}
45+
46+
#endif // AIX

0 commit comments

Comments
 (0)