8252500: ZGC on aarch64: Unable to allocate heap for certain Linux kernel configurations
Reviewed-by: stefank, eosterlund, pliden
This commit is contained in:
parent
5dd1eaded7
commit
73ba3ae1f5
@ -22,11 +22,17 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/gcLogPrecious.hpp"
|
||||
#include "gc/z/zGlobals.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/powerOfTwo.hpp"
|
||||
|
||||
#ifdef LINUX
|
||||
#include <sys/mman.h>
|
||||
#endif // LINUX
|
||||
|
||||
//
|
||||
// The heap can have three different layouts, depending on the max heap size.
|
||||
//
|
||||
@ -135,9 +141,64 @@
|
||||
// * 63-48 Fixed (16-bits, always zero)
|
||||
//
|
||||
|
||||
// Default value if probing is not implemented for a certain platform: 128TB
|
||||
static const size_t DEFAULT_MAX_ADDRESS_BIT = 47;
|
||||
// Minimum value returned, if probing fails: 64GB
|
||||
static const size_t MINIMUM_MAX_ADDRESS_BIT = 36;
|
||||
|
||||
static size_t probe_valid_max_address_bit() {
|
||||
#ifdef LINUX
|
||||
size_t max_address_bit = 0;
|
||||
const size_t page_size = os::vm_page_size();
|
||||
for (size_t i = DEFAULT_MAX_ADDRESS_BIT; i > MINIMUM_MAX_ADDRESS_BIT; --i) {
|
||||
const uintptr_t base_addr = ((uintptr_t) 1U) << i;
|
||||
if (msync((void*)base_addr, page_size, MS_ASYNC) == 0) {
|
||||
// msync suceeded, the address is valid, and maybe even already mapped.
|
||||
max_address_bit = i;
|
||||
break;
|
||||
}
|
||||
if (errno != ENOMEM) {
|
||||
// Some error occured. This should never happen, but msync
|
||||
// has some undefined behavior, hence ignore this bit.
|
||||
#ifdef ASSERT
|
||||
fatal("Received '%s' while probing the address space for the highest valid bit", os::errno_name(errno));
|
||||
#else // ASSERT
|
||||
log_warning_p(gc)("Received '%s' while probing the address space for the highest valid bit", os::errno_name(errno));
|
||||
#endif // ASSERT
|
||||
continue;
|
||||
}
|
||||
// Since msync failed with ENOMEM, the page might not be mapped.
|
||||
// Try to map it, to see if the address is valid.
|
||||
void* const result_addr = mmap((void*) base_addr, page_size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0);
|
||||
if (result_addr != MAP_FAILED) {
|
||||
munmap(result_addr, page_size);
|
||||
}
|
||||
if ((uintptr_t) result_addr == base_addr) {
|
||||
// address is valid
|
||||
max_address_bit = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (max_address_bit == 0) {
|
||||
// probing failed, allocate a very high page and take that bit as the maximum
|
||||
const uintptr_t high_addr = ((uintptr_t) 1U) << DEFAULT_MAX_ADDRESS_BIT;
|
||||
void* const result_addr = mmap((void*) high_addr, page_size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0);
|
||||
if (result_addr != MAP_FAILED) {
|
||||
max_address_bit = BitsPerSize_t - count_leading_zeros((size_t) result_addr) - 1;
|
||||
munmap(result_addr, page_size);
|
||||
}
|
||||
}
|
||||
log_info_p(gc, init)("Probing address space for the highest valid bit: " SIZE_FORMAT, max_address_bit);
|
||||
return MAX2(max_address_bit, MINIMUM_MAX_ADDRESS_BIT);
|
||||
#else // LINUX
|
||||
return DEFAULT_MAX_ADDRESS_BIT;
|
||||
#endif // LINUX
|
||||
}
|
||||
|
||||
size_t ZPlatformAddressOffsetBits() {
|
||||
const size_t min_address_offset_bits = 42; // 4TB
|
||||
const size_t max_address_offset_bits = 44; // 16TB
|
||||
const static size_t valid_max_address_offset_bits = probe_valid_max_address_bit() + 1;
|
||||
const size_t max_address_offset_bits = valid_max_address_offset_bits - 3;
|
||||
const size_t min_address_offset_bits = max_address_offset_bits - 2;
|
||||
const size_t address_offset = round_up_power_of_2(MaxHeapSize * ZVirtualToPhysicalRatio);
|
||||
const size_t address_offset_bits = log2_intptr(address_offset);
|
||||
return clamp(address_offset_bits, min_address_offset_bits, max_address_offset_bits);
|
||||
|
Loading…
x
Reference in New Issue
Block a user