src/os/linux/vm/os_linux.cpp
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File
hsx-rt.8007074 Cdiff src/os/linux/vm/os_linux.cpp
src/os/linux/vm/os_linux.cpp
Print this page
*** 2718,2757 ****
#define MADV_HUGEPAGE 14
#endif
int os::Linux::commit_memory_impl(char* addr, size_t size,
size_t alignment_hint, bool exec) {
! int err;
! if (UseHugeTLBFS && alignment_hint > (size_t)vm_page_size()) {
! int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE;
! uintptr_t res =
! (uintptr_t) ::mmap(addr, size, prot,
! MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS|MAP_HUGETLB,
! -1, 0);
! if (res != (uintptr_t) MAP_FAILED) {
! if (UseNUMAInterleaving) {
! numa_make_global(addr, size);
! }
! return 0;
! }
!
! err = errno; // save errno from mmap() call above
!
! if (!recoverable_mmap_error(err)) {
! // However, it is not clear that this loss of our reserved mapping
! // happens with large pages on Linux or that we cannot recover
! // from the loss. For now, we just issue a warning and we don't
! // call vm_exit_out_of_memory(). This issue is being tracked by
! // JBS-8007074.
! warn_fail_commit_memory(addr, size, alignment_hint, exec, err);
! // vm_exit_out_of_memory(size, OOM_MMAP_ERROR,
! // "committing reserved memory.");
! }
! // Fall through and try to use small pages
! }
!
! err = os::Linux::commit_memory_impl(addr, size, exec);
if (err == 0) {
realign_memory(addr, size, alignment_hint);
}
return err;
}
--- 2718,2728 ----
#define MADV_HUGEPAGE 14
#endif
int os::Linux::commit_memory_impl(char* addr, size_t size,
size_t alignment_hint, bool exec) {
! int err = os::Linux::commit_memory_impl(addr, size, exec);
if (err == 0) {
realign_memory(addr, size, alignment_hint);
}
return err;
}
*** 2772,2782 ****
vm_exit_out_of_memory(size, OOM_MMAP_ERROR, mesg);
}
}
void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) {
! if (UseHugeTLBFS && alignment_hint > (size_t)vm_page_size()) {
// We don't check the return value: madvise(MADV_HUGEPAGE) may not
// be supported or the memory may already be backed by huge pages.
::madvise(addr, bytes, MADV_HUGEPAGE);
}
}
--- 2743,2753 ----
vm_exit_out_of_memory(size, OOM_MMAP_ERROR, mesg);
}
}
void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) {
! if (UseTransparentHugePages && alignment_hint > (size_t)vm_page_size()) {
// We don't check the return value: madvise(MADV_HUGEPAGE) may not
// be supported or the memory may already be backed by huge pages.
::madvise(addr, bytes, MADV_HUGEPAGE);
}
}
*** 2785,2795 ****
// This method works by doing an mmap over an existing mmaping and effectively discarding
// the existing pages. However it won't work for SHM-based large pages that cannot be
// uncommitted at all. We don't do anything in this case to avoid creating a segment with
// small pages on top of the SHM segment. This method always works for small pages, so we
// allow that in any case.
! if (alignment_hint <= (size_t)os::vm_page_size() || !UseSHM) {
commit_memory(addr, bytes, alignment_hint, !ExecMem);
}
}
void os::numa_make_global(char *addr, size_t bytes) {
--- 2756,2766 ----
// This method works by doing an mmap over an existing mmaping and effectively discarding
// the existing pages. However it won't work for SHM-based large pages that cannot be
// uncommitted at all. We don't do anything in this case to avoid creating a segment with
// small pages on top of the SHM segment. This method always works for small pages, so we
// allow that in any case.
! if (alignment_hint <= (size_t)os::vm_page_size() || can_commit_large_page_memory()) {
commit_memory(addr, bytes, alignment_hint, !ExecMem);
}
}
void os::numa_make_global(char *addr, size_t bytes) {
*** 3155,3167 ****
bool os::unguard_memory(char* addr, size_t size) {
return linux_mprotect(addr, size, PROT_READ|PROT_WRITE);
}
bool os::Linux::hugetlbfs_sanity_check(bool warn, size_t page_size) {
bool result = false;
! void *p = mmap (NULL, page_size, PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB,
-1, 0);
if (p != MAP_FAILED) {
// We don't know if this really is a huge page or not.
--- 3126,3158 ----
bool os::unguard_memory(char* addr, size_t size) {
return linux_mprotect(addr, size, PROT_READ|PROT_WRITE);
}
+ bool os::Linux::transparent_huge_pages_sanity_check(bool warn, size_t page_size) {
+ bool result = false;
+ void *p = mmap(NULL, page_size * 2, PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_PRIVATE,
+ -1, 0);
+ if (p != MAP_FAILED) {
+ void *aligned_p = align_ptr_up(p, page_size);
+
+ result = madvise(aligned_p, page_size, MADV_HUGEPAGE) == 0;
+
+ munmap(p, page_size * 2);
+ }
+
+ if (warn && !result) {
+ warning("TransparentHugePages is not supported by the operating system.");
+ }
+
+ return result;
+ }
+
bool os::Linux::hugetlbfs_sanity_check(bool warn, size_t page_size) {
bool result = false;
! void *p = mmap(NULL, page_size, PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB,
-1, 0);
if (p != MAP_FAILED) {
// We don't know if this really is a huge page or not.
*** 3180,3195 ****
}
}
}
fclose(fp);
}
! munmap (p, page_size);
! if (result)
! return true;
}
! if (warn) {
warning("HugeTLBFS is not supported by the operating system.");
}
return result;
}
--- 3171,3184 ----
}
}
}
fclose(fp);
}
! munmap(p, page_size);
}
! if (warn && !result) {
warning("HugeTLBFS is not supported by the operating system.");
}
return result;
}
*** 3233,3262 ****
// Large page support
static size_t _large_page_size = 0;
! void os::large_page_init() {
! if (!UseLargePages) {
! UseHugeTLBFS = false;
! UseSHM = false;
! return;
! }
!
! if (FLAG_IS_DEFAULT(UseHugeTLBFS) && FLAG_IS_DEFAULT(UseSHM)) {
! // If UseLargePages is specified on the command line try both methods,
! // if it's default, then try only HugeTLBFS.
! if (FLAG_IS_DEFAULT(UseLargePages)) {
! UseHugeTLBFS = true;
! } else {
! UseHugeTLBFS = UseSHM = true;
! }
! }
- if (LargePageSizeInBytes) {
- _large_page_size = LargePageSizeInBytes;
- } else {
// large_page_size on Linux is used to round up heap size. x86 uses either
// 2M or 4M page, depending on whether PAE (Physical Address Extensions)
// mode is enabled. AMD64/EM64T uses 2M page in 64bit mode. IA64 can use
// page as large as 256M.
//
--- 3222,3234 ----
// Large page support
static size_t _large_page_size = 0;
! size_t os::Linux::find_large_page_size() {
! size_t large_page_size = 0;
// large_page_size on Linux is used to round up heap size. x86 uses either
// 2M or 4M page, depending on whether PAE (Physical Address Extensions)
// mode is enabled. AMD64/EM64T uses 2M page in 64bit mode. IA64 can use
// page as large as 256M.
//
*** 3267,3288 ****
// If we can't determine the value (e.g. /proc is not mounted, or the text
// format has been changed), we'll use the largest page size supported by
// the processor.
#ifndef ZERO
! _large_page_size = IA32_ONLY(4 * M) AMD64_ONLY(2 * M) IA64_ONLY(256 * M) SPARC_ONLY(4 * M)
ARM_ONLY(2 * M) PPC_ONLY(4 * M);
#endif // ZERO
FILE *fp = fopen("/proc/meminfo", "r");
if (fp) {
while (!feof(fp)) {
int x = 0;
char buf[16];
if (fscanf(fp, "Hugepagesize: %d", &x) == 1) {
if (x && fgets(buf, sizeof(buf), fp) && strcmp(buf, " kB\n") == 0) {
! _large_page_size = x * K;
break;
}
} else {
// skip to next line
for (;;) {
--- 3239,3260 ----
// If we can't determine the value (e.g. /proc is not mounted, or the text
// format has been changed), we'll use the largest page size supported by
// the processor.
#ifndef ZERO
! large_page_size = IA32_ONLY(4 * M) AMD64_ONLY(2 * M) IA64_ONLY(256 * M) SPARC_ONLY(4 * M)
ARM_ONLY(2 * M) PPC_ONLY(4 * M);
#endif // ZERO
FILE *fp = fopen("/proc/meminfo", "r");
if (fp) {
while (!feof(fp)) {
int x = 0;
char buf[16];
if (fscanf(fp, "Hugepagesize: %d", &x) == 1) {
if (x && fgets(buf, sizeof(buf), fp) && strcmp(buf, " kB\n") == 0) {
! large_page_size = x * K;
break;
}
} else {
// skip to next line
for (;;) {
*** 3291,3336 ****
}
}
}
fclose(fp);
}
}
! // print a warning if any large page related flag is specified on command line
! bool warn_on_failure = !FLAG_IS_DEFAULT(UseHugeTLBFS);
! const size_t default_page_size = (size_t)Linux::page_size();
if (_large_page_size > default_page_size) {
_page_sizes[0] = _large_page_size;
_page_sizes[1] = default_page_size;
_page_sizes[2] = 0;
}
- UseHugeTLBFS = UseHugeTLBFS &&
- Linux::hugetlbfs_sanity_check(warn_on_failure, _large_page_size);
! if (UseHugeTLBFS)
UseSHM = false;
! UseLargePages = UseHugeTLBFS || UseSHM;
set_coredump_filter();
}
#ifndef SHM_HUGETLB
#define SHM_HUGETLB 04000
#endif
! char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) {
// "exec" is passed in but not used. Creating the shared image for
// the code cache doesn't have an SHM_X executable permission to check.
assert(UseLargePages && UseSHM, "only for SHM large pages");
key_t key = IPC_PRIVATE;
char *addr;
bool warn_on_failure = UseLargePages &&
(!FLAG_IS_DEFAULT(UseLargePages) ||
!FLAG_IS_DEFAULT(LargePageSizeInBytes)
);
char msg[128];
// Create a large shared memory region to attach to based on size.
--- 3263,3363 ----
}
}
}
fclose(fp);
}
+
+ if (!FLAG_IS_DEFAULT(LargePageSizeInBytes) && LargePageSizeInBytes != large_page_size) {
+ warning("Setting LargePageSizeInBytes has no effect on this OS. Large page size is "
+ SIZE_FORMAT "%s.", byte_size_in_proper_unit(large_page_size),
+ proper_unit_for_byte_size(large_page_size));
}
! return large_page_size;
! }
! size_t os::Linux::setup_large_page_size() {
! _large_page_size = Linux::find_large_page_size();
! size_t default_page_size = (size_t)Linux::page_size();
if (_large_page_size > default_page_size) {
_page_sizes[0] = _large_page_size;
_page_sizes[1] = default_page_size;
_page_sizes[2] = 0;
}
! return _large_page_size;
! }
!
! bool os::Linux::setup_large_page_type(size_t page_size) {
! if (FLAG_IS_DEFAULT(UseHugeTLBFS) &&
! FLAG_IS_DEFAULT(UseSHM) &&
! FLAG_IS_DEFAULT(UseTransparentHugePages)) {
! // If UseLargePages is specified on the command line try all methods,
! // if it's default, then try only UseTransparentHugePages.
! if (FLAG_IS_DEFAULT(UseLargePages)) {
! UseTransparentHugePages = true;
! } else {
! UseHugeTLBFS = UseTransparentHugePages = UseSHM = true;
! }
! }
!
! if (UseTransparentHugePages) {
! bool warn_on_failure = !FLAG_IS_DEFAULT(UseTransparentHugePages);
! if (transparent_huge_pages_sanity_check(warn_on_failure, page_size)) {
! UseHugeTLBFS = false;
! UseSHM = false;
! return true;
! }
! UseTransparentHugePages = false;
! }
!
! if (UseHugeTLBFS) {
! bool warn_on_failure = !FLAG_IS_DEFAULT(UseHugeTLBFS);
! if (hugetlbfs_sanity_check(warn_on_failure, page_size)) {
! UseSHM = false;
! return true;
! }
! UseHugeTLBFS = false;
! }
!
! return UseSHM;
! }
!
! void os::large_page_init() {
! if (!UseLargePages) {
! UseHugeTLBFS = false;
! UseTransparentHugePages = false;
UseSHM = false;
+ return;
+ }
! size_t large_page_size = Linux::setup_large_page_size();
! UseLargePages = Linux::setup_large_page_type(large_page_size);
set_coredump_filter();
}
#ifndef SHM_HUGETLB
#define SHM_HUGETLB 04000
#endif
! char* os::Linux::reserve_memory_special_shm(size_t bytes, size_t alignment, char* req_addr, bool exec) {
// "exec" is passed in but not used. Creating the shared image for
// the code cache doesn't have an SHM_X executable permission to check.
assert(UseLargePages && UseSHM, "only for SHM large pages");
+ assert(is_ptr_aligned(req_addr, os::large_page_size()), "Unaligned address");
+
+ if (!is_size_aligned(bytes, os::large_page_size()) || alignment > os::large_page_size()) {
+ return NULL; // Fallback to small pages.
+ }
key_t key = IPC_PRIVATE;
char *addr;
bool warn_on_failure = UseLargePages &&
(!FLAG_IS_DEFAULT(UseLargePages) ||
+ !FLAG_IS_DEFAULT(UseSHM) ||
!FLAG_IS_DEFAULT(LargePageSizeInBytes)
);
char msg[128];
// Create a large shared memory region to attach to based on size.
*** 3374,3419 ****
warning(msg);
}
return NULL;
}
! if ((addr != NULL) && UseNUMAInterleaving) {
numa_make_global(addr, bytes);
}
// The memory is committed
MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, mtNone, CALLER_PC);
return addr;
}
bool os::release_memory_special(char* base, size_t bytes) {
MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
! // detaching the SHM segment will also delete it, see reserve_memory_special()
! int rslt = shmdt(base);
! if (rslt == 0) {
tkr.record((address)base, bytes);
- return true;
} else {
tkr.discard();
- return false;
}
}
size_t os::large_page_size() {
return _large_page_size;
}
! // HugeTLBFS allows application to commit large page memory on demand;
! // with SysV SHM the entire memory region must be allocated as shared
// memory.
bool os::can_commit_large_page_memory() {
! return UseHugeTLBFS;
}
bool os::can_execute_large_page_memory() {
! return UseHugeTLBFS;
}
// Reserve memory at an arbitrary address, only if that area is
// available (and not reserved for something else).
--- 3401,3623 ----
warning(msg);
}
return NULL;
}
! return addr;
! }
!
! static void warn_on_large_pages_failure(char* req_addr, size_t bytes, 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 large pages memory req_addr: "
! PTR_FORMAT " bytes: " SIZE_FORMAT " (errno = %d).", req_addr, bytes, error);
! warning(msg);
! }
! }
!
! char* os::Linux::reserve_memory_special_huge_tlbfs_only(size_t bytes, char* req_addr, bool exec) {
! assert(UseLargePages && UseHugeTLBFS, "only for Huge TLBFS large pages");
! assert(is_size_aligned(bytes, os::large_page_size()), "Unaligned size");
! assert(is_ptr_aligned(req_addr, os::large_page_size()), "Unaligned address");
!
! int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE;
! char* addr = (char*)::mmap(req_addr, bytes, prot,
! MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB,
! -1, 0);
!
! if (addr == MAP_FAILED) {
! warn_on_large_pages_failure(req_addr, bytes, errno);
! return NULL;
! }
!
! assert(is_ptr_aligned(addr, os::large_page_size()), "Must be");
!
! return addr;
! }
!
! char* os::Linux::reserve_memory_special_huge_tlbfs_mixed(size_t bytes, size_t alignment, char* req_addr, bool exec) {
! size_t large_page_size = os::large_page_size();
!
! assert(bytes >= large_page_size, "Shouldn't allocate large pages for small sizes");
!
! // Allocate small pages.
!
! char* start;
! if (req_addr != NULL) {
! assert(is_ptr_aligned(req_addr, alignment), "Must be");
! assert(is_size_aligned(bytes, alignment), "Must be");
! start = os::reserve_memory(bytes, req_addr);
! assert(start == NULL || start == req_addr, "Must be");
! } else {
! start = os::reserve_memory_aligned(bytes, alignment);
! }
!
! if (start == NULL) {
! return NULL;
! }
!
! assert(is_ptr_aligned(start, alignment), "Must be");
!
! // os::reserve_memory_special will record this memory area.
! // Need to release it here to prevent overlapping reservations.
! MemTracker::record_virtual_memory_release((address)start, bytes);
!
! char* end = start + bytes;
!
! // Find the regions of the allocated chunk that can be promoted to large pages.
! char* lp_start = (char*)align_ptr_up(start, large_page_size);
! char* lp_end = (char*)align_ptr_down(end, large_page_size);
!
! size_t lp_bytes = lp_end - lp_start;
!
! assert(is_size_aligned(lp_bytes, large_page_size), "Must be");
!
! if (lp_bytes == 0) {
! // The mapped region doesn't even span the start and the end of a large page.
! // Fall back to allocate a non-special area.
! ::munmap(start, end - start);
! return NULL;
! }
!
! int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE;
!
!
! void* result;
!
! if (start != lp_start) {
! result = ::mmap(start, lp_start - start, prot,
! MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,
! -1, 0);
! if (result == MAP_FAILED) {
! ::munmap(lp_start, end - lp_start);
! return NULL;
! }
! }
!
! result = ::mmap(lp_start, lp_bytes, prot,
! MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED|MAP_HUGETLB,
! -1, 0);
! if (result == MAP_FAILED) {
! warn_on_large_pages_failure(req_addr, bytes, errno);
! // If the mmap above fails, the large pages region will be unmapped and we
! // have regions before and after with small pages. Release these regions.
! //
! // | mapped | unmapped | mapped |
! // ^ ^ ^ ^
! // start lp_start lp_end end
! //
! ::munmap(start, lp_start - start);
! ::munmap(lp_end, end - lp_end);
! return NULL;
! }
!
! if (lp_end != end) {
! result = ::mmap(lp_end, end - lp_end, prot,
! MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,
! -1, 0);
! if (result == MAP_FAILED) {
! ::munmap(start, lp_end - start);
! return NULL;
! }
! }
!
! return start;
! }
!
! char* os::Linux::reserve_memory_special_huge_tlbfs(size_t bytes, size_t alignment, char* req_addr, bool exec) {
! assert(UseLargePages && UseHugeTLBFS, "only for Huge TLBFS large pages");
! assert(is_ptr_aligned(req_addr, alignment), "Must be");
! assert(is_power_of_2(alignment), "Must be");
! assert(is_power_of_2(os::large_page_size()), "Must be");
! assert(bytes >= os::large_page_size(), "Shouldn't allocate large pages for small sizes");
!
! if (is_size_aligned(bytes, os::large_page_size()) && alignment <= os::large_page_size()) {
! return reserve_memory_special_huge_tlbfs_only(bytes, req_addr, exec);
! } else {
! return reserve_memory_special_huge_tlbfs_mixed(bytes, alignment, req_addr, exec);
! }
! }
!
! char* os::reserve_memory_special(size_t bytes, size_t alignment, char* req_addr, bool exec) {
! assert(UseLargePages, "only for large pages");
!
! char* addr;
! if (UseSHM) {
! addr = os::Linux::reserve_memory_special_shm(bytes, alignment, req_addr, exec);
! } else {
! assert(UseHugeTLBFS, "must be");
! addr = os::Linux::reserve_memory_special_huge_tlbfs(bytes, alignment, req_addr, exec);
! }
!
! if (addr != NULL) {
! if (UseNUMAInterleaving) {
numa_make_global(addr, bytes);
}
// The memory is committed
MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, mtNone, CALLER_PC);
+ }
return addr;
}
+ bool os::Linux::release_memory_special_shm(char* base, size_t bytes) {
+ // detaching the SHM segment will also delete it, see reserve_memory_special_shm()
+ return shmdt(base) == 0;
+ }
+
+ bool os::Linux::release_memory_special_huge_tlbfs(char* base, size_t bytes) {
+ return pd_release_memory(base, bytes);
+ }
+
bool os::release_memory_special(char* base, size_t bytes) {
+ assert(UseLargePages, "only for large pages");
+
MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
!
! bool res;
! if (UseSHM) {
! res = os::Linux::release_memory_special_shm(base, bytes);
! } else {
! assert(UseHugeTLBFS, "must be");
! res = os::Linux::release_memory_special_huge_tlbfs(base, bytes);
! }
!
! if (res) {
tkr.record((address)base, bytes);
} else {
tkr.discard();
}
+
+ return res;
}
size_t os::large_page_size() {
return _large_page_size;
}
! // With SysV SHM the entire memory region must be allocated as shared
// memory.
+ // HugeTLBFS allows application to commit large page memory on demand.
+ // However, when committing memory with HugeTLBFS fails, the region
+ // that was supposed to be committed will loose the old reservation
+ // and allow other threads to steal that memory region. Because of this
+ // behavior we can't commit HugeTLBFS memory.
bool os::can_commit_large_page_memory() {
! return UseTransparentHugePages;
}
bool os::can_execute_large_page_memory() {
! return UseTransparentHugePages || UseHugeTLBFS;
}
// Reserve memory at an arbitrary address, only if that area is
// available (and not reserved for something else).
*** 4561,4585 ****
if ((Linux::numa_max_node() < 1)) {
// There's only one node(they start from 0), disable NUMA.
UseNUMA = false;
}
}
! // With SHM large pages we cannot uncommit a page, so there's not way
// we can make the adaptive lgrp chunk resizing work. If the user specified
! // both UseNUMA and UseLargePages (or UseSHM) on the command line - warn and
// disable adaptive resizing.
! if (UseNUMA && UseLargePages && UseSHM) {
! if (!FLAG_IS_DEFAULT(UseNUMA)) {
! if (FLAG_IS_DEFAULT(UseLargePages) && FLAG_IS_DEFAULT(UseSHM)) {
UseLargePages = false;
} else {
! warning("UseNUMA is not fully compatible with SHM large pages, disabling adaptive resizing");
UseAdaptiveSizePolicy = false;
UseAdaptiveNUMAChunkSizing = false;
}
- } else {
- UseNUMA = false;
}
}
if (!UseNUMA && ForceNUMA) {
UseNUMA = true;
}
--- 4765,4791 ----
if ((Linux::numa_max_node() < 1)) {
// There's only one node(they start from 0), disable NUMA.
UseNUMA = false;
}
}
! // With SHM and HugeTLBFS large pages we cannot uncommit a page, so there's no way
// we can make the adaptive lgrp chunk resizing work. If the user specified
! // both UseNUMA and UseLargePages (or UseSHM/UseHugeTLBFS) on the command line - warn and
// disable adaptive resizing.
! if (UseNUMA && UseLargePages && !can_commit_large_page_memory()) {
! if (FLAG_IS_DEFAULT(UseNUMA)) {
! UseNUMA = false;
! } else {
! if (FLAG_IS_DEFAULT(UseLargePages) &&
! FLAG_IS_DEFAULT(UseSHM) &&
! FLAG_IS_DEFAULT(UseHugeTLBFS)) {
UseLargePages = false;
} else {
! warning("UseNUMA is not fully compatible with SHM/HugeTLBFS large pages, disabling adaptive resizing");
UseAdaptiveSizePolicy = false;
UseAdaptiveNUMAChunkSizing = false;
}
}
}
if (!UseNUMA && ForceNUMA) {
UseNUMA = true;
}
*** 5846,5850 ****
--- 6052,6202 ----
new MemNotifyThread(fd);
}
}
#endif // JAVASE_EMBEDDED
+
+
+ /////////////// Unit tests ///////////////
+
+ #ifndef PRODUCT
+
+ #define test_log(...) \
+ do {\
+ if (VerboseInternalVMTests) { \
+ tty->print_cr(__VA_ARGS__); \
+ tty->flush(); \
+ }\
+ } while (false)
+
+ class TestReserveMemorySpecial : AllStatic {
+ public:
+ static void small_page_write(void* addr, size_t size) {
+ size_t page_size = os::vm_page_size();
+
+ char* end = (char*)addr + size;
+ for (char* p = (char*)addr; p < end; p += page_size) {
+ *p = 1;
+ }
+ }
+
+ static void test_reserve_memory_special_huge_tlbfs_only(size_t size) {
+ if (!UseHugeTLBFS) {
+ return;
+ }
+
+ test_log("test_reserve_memory_special_huge_tlbfs_only(" SIZE_FORMAT ")", size);
+
+ char* addr = os::Linux::reserve_memory_special_huge_tlbfs_only(size, NULL, false);
+
+ if (addr != NULL) {
+ small_page_write(addr, size);
+
+ os::Linux::release_memory_special_huge_tlbfs(addr, size);
+ }
+ }
+
+ static void test_reserve_memory_special_huge_tlbfs_only() {
+ if (!UseHugeTLBFS) {
+ return;
+ }
+
+ size_t lp = os::large_page_size();
+
+ for (size_t size = lp; size <= lp * 10; size += lp) {
+ test_reserve_memory_special_huge_tlbfs_only(size);
+ }
+ }
+
+ static void test_reserve_memory_special_huge_tlbfs_mixed(size_t size, size_t alignment) {
+ if (!UseHugeTLBFS) {
+ return;
+ }
+
+ test_log("test_reserve_memory_special_huge_tlbfs_mixed(" SIZE_FORMAT ", " SIZE_FORMAT ")",
+ size, alignment);
+
+ assert(size >= os::large_page_size(), "Incorrect input to test");
+
+ char* addr = os::Linux::reserve_memory_special_huge_tlbfs_mixed(size, alignment, NULL, false);
+
+ if (addr != NULL) {
+ small_page_write(addr, size);
+
+ os::Linux::release_memory_special_huge_tlbfs(addr, size);
+ }
+ }
+
+ static void test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(size_t size) {
+ size_t lp = os::large_page_size();
+ size_t ag = os::vm_allocation_granularity();
+
+ for (size_t alignment = ag; is_size_aligned(size, alignment); alignment *= 2) {
+ test_reserve_memory_special_huge_tlbfs_mixed(size, alignment);
+ }
+ }
+
+ static void test_reserve_memory_special_huge_tlbfs_mixed() {
+ size_t lp = os::large_page_size();
+ size_t ag = os::vm_allocation_granularity();
+
+ test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp);
+ test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp + ag);
+ test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp + lp / 2);
+ test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2);
+ test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2 + ag);
+ test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2 - ag);
+ test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2 + lp / 2);
+ test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 10);
+ test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 10 + lp / 2);
+ }
+
+ static void test_reserve_memory_special_huge_tlbfs() {
+ if (!UseHugeTLBFS) {
+ return;
+ }
+
+ test_reserve_memory_special_huge_tlbfs_only();
+ test_reserve_memory_special_huge_tlbfs_mixed();
+ }
+
+ static void test_reserve_memory_special_shm(size_t size, size_t alignment) {
+ if (!UseSHM) {
+ return;
+ }
+
+ test_log("test_reserve_memory_special_shm(" SIZE_FORMAT ", " SIZE_FORMAT ")", size, alignment);
+
+ char* addr = os::Linux::reserve_memory_special_shm(size, alignment, NULL, false);
+
+ if (addr != NULL) {
+ assert(is_ptr_aligned(addr, alignment), "Check");
+ assert(is_ptr_aligned(addr, os::large_page_size()), "Check");
+
+ small_page_write(addr, size);
+
+ os::Linux::release_memory_special_shm(addr, size);
+ }
+ }
+
+ static void test_reserve_memory_special_shm() {
+ size_t lp = os::large_page_size();
+ size_t ag = os::vm_allocation_granularity();
+
+ for (size_t size = ag; size < lp * 3; size += ag) {
+ for (size_t alignment = ag; is_size_aligned(size, alignment); alignment *= 2) {
+ test_reserve_memory_special_shm(size, alignment);
+ }
+ }
+ }
+
+ static void test() {
+ test_reserve_memory_special_huge_tlbfs();
+ test_reserve_memory_special_shm();
+ }
+ };
+
+ void TestReserveMemorySpecial_test() {
+ TestReserveMemorySpecial::test();
+ }
+
+ #endif
src/os/linux/vm/os_linux.cpp
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File