< prev index next >
src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp
Print this page
*** 20,29 ****
--- 20,30 ----
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "precompiled.hpp"
+ #include "gc/shared/gcLogPrecious.hpp"
#include "gc/z/zArray.inline.hpp"
#include "gc/z/zErrno.hpp"
#include "gc/z/zGlobals.hpp"
#include "gc/z/zLargePages.inline.hpp"
#include "gc/z/zMountPoint_linux.hpp"
*** 128,189 ****
// Get filesystem statistics
struct statfs buf;
if (fstatfs(_fd, &buf) == -1) {
ZErrno err;
! log_error(gc)("Failed to determine filesystem type for backing file (%s)", err.to_string());
return;
}
_filesystem = buf.f_type;
_block_size = buf.f_bsize;
_available = buf.f_bavail * _block_size;
! log_info(gc, init)("Heap Backing Filesystem: %s (0x" UINT64_FORMAT_X ")",
! is_tmpfs() ? ZFILESYSTEM_TMPFS : is_hugetlbfs() ? ZFILESYSTEM_HUGETLBFS : "other", _filesystem);
// Make sure the filesystem type matches requested large page type
if (ZLargePages::is_transparent() && !is_tmpfs()) {
! log_error(gc)("-XX:+UseTransparentHugePages can only be enabled when using a %s filesystem",
! ZFILESYSTEM_TMPFS);
return;
}
if (ZLargePages::is_transparent() && !tmpfs_supports_transparent_huge_pages()) {
! log_error(gc)("-XX:+UseTransparentHugePages on a %s filesystem not supported by kernel",
! ZFILESYSTEM_TMPFS);
return;
}
if (ZLargePages::is_explicit() && !is_hugetlbfs()) {
! log_error(gc)("-XX:+UseLargePages (without -XX:+UseTransparentHugePages) can only be enabled "
! "when using a %s filesystem", ZFILESYSTEM_HUGETLBFS);
return;
}
if (!ZLargePages::is_explicit() && is_hugetlbfs()) {
! log_error(gc)("-XX:+UseLargePages must be enabled when using a %s filesystem",
! ZFILESYSTEM_HUGETLBFS);
return;
}
if (ZLargePages::is_explicit() && os::large_page_size() != ZGranuleSize) {
! log_error(gc)("Incompatible large page size configured " SIZE_FORMAT " (expected " SIZE_FORMAT ")",
! os::large_page_size(), ZGranuleSize);
return;
}
// Make sure the filesystem block size is compatible
if (ZGranuleSize % _block_size != 0) {
! log_error(gc)("Filesystem backing the heap has incompatible block size (" SIZE_FORMAT ")",
! _block_size);
return;
}
if (is_hugetlbfs() && _block_size != ZGranuleSize) {
! log_error(gc)("%s filesystem has unexpected block size " SIZE_FORMAT " (expected " SIZE_FORMAT ")",
! ZFILESYSTEM_HUGETLBFS, _block_size, ZGranuleSize);
return;
}
// Successfully initialized
_initialized = true;
--- 129,190 ----
// Get filesystem statistics
struct statfs buf;
if (fstatfs(_fd, &buf) == -1) {
ZErrno err;
! log_error_p(gc)("Failed to determine filesystem type for backing file (%s)", err.to_string());
return;
}
_filesystem = buf.f_type;
_block_size = buf.f_bsize;
_available = buf.f_bavail * _block_size;
! log_info_p(gc, init)("Heap Backing Filesystem: %s (0x" UINT64_FORMAT_X ")",
! is_tmpfs() ? ZFILESYSTEM_TMPFS : is_hugetlbfs() ? ZFILESYSTEM_HUGETLBFS : "other", _filesystem);
// Make sure the filesystem type matches requested large page type
if (ZLargePages::is_transparent() && !is_tmpfs()) {
! log_error_p(gc)("-XX:+UseTransparentHugePages can only be enabled when using a %s filesystem",
! ZFILESYSTEM_TMPFS);
return;
}
if (ZLargePages::is_transparent() && !tmpfs_supports_transparent_huge_pages()) {
! log_error_p(gc)("-XX:+UseTransparentHugePages on a %s filesystem not supported by kernel",
! ZFILESYSTEM_TMPFS);
return;
}
if (ZLargePages::is_explicit() && !is_hugetlbfs()) {
! log_error_p(gc)("-XX:+UseLargePages (without -XX:+UseTransparentHugePages) can only be enabled "
! "when using a %s filesystem", ZFILESYSTEM_HUGETLBFS);
return;
}
if (!ZLargePages::is_explicit() && is_hugetlbfs()) {
! log_error_p(gc)("-XX:+UseLargePages must be enabled when using a %s filesystem",
! ZFILESYSTEM_HUGETLBFS);
return;
}
if (ZLargePages::is_explicit() && os::large_page_size() != ZGranuleSize) {
! log_error_p(gc)("Incompatible large page size configured " SIZE_FORMAT " (expected " SIZE_FORMAT ")",
! os::large_page_size(), ZGranuleSize);
return;
}
// Make sure the filesystem block size is compatible
if (ZGranuleSize % _block_size != 0) {
! log_error_p(gc)("Filesystem backing the heap has incompatible block size (" SIZE_FORMAT ")",
! _block_size);
return;
}
if (is_hugetlbfs() && _block_size != ZGranuleSize) {
! log_error_p(gc)("%s filesystem has unexpected block size " SIZE_FORMAT " (expected " SIZE_FORMAT ")",
! ZFILESYSTEM_HUGETLBFS, _block_size, ZGranuleSize);
return;
}
// Successfully initialized
_initialized = true;
*** 197,212 ****
// Create file
const int extra_flags = ZLargePages::is_explicit() ? MFD_HUGETLB : 0;
const int fd = ZSyscall::memfd_create(filename, MFD_CLOEXEC | extra_flags);
if (fd == -1) {
ZErrno err;
! log_debug(gc, init)("Failed to create memfd file (%s)",
! ((ZLargePages::is_explicit() && err == EINVAL) ? "Hugepages not supported" : err.to_string()));
return -1;
}
! log_info(gc, init)("Heap Backing File: /memfd:%s", filename);
return fd;
}
int ZPhysicalMemoryBacking::create_file_fd(const char* name) const {
--- 198,213 ----
// Create file
const int extra_flags = ZLargePages::is_explicit() ? MFD_HUGETLB : 0;
const int fd = ZSyscall::memfd_create(filename, MFD_CLOEXEC | extra_flags);
if (fd == -1) {
ZErrno err;
! log_debug_p(gc, init)("Failed to create memfd file (%s)",
! ((ZLargePages::is_explicit() && err == EINVAL) ? "Hugepages not supported" : err.to_string()));
return -1;
}
! log_info_p(gc, init)("Heap Backing File: /memfd:%s", filename);
return fd;
}
int ZPhysicalMemoryBacking::create_file_fd(const char* name) const {
*** 218,274 ****
: z_preferred_tmpfs_mountpoints;
// Find mountpoint
ZMountPoint mountpoint(filesystem, preferred_mountpoints);
if (mountpoint.get() == NULL) {
! log_error(gc)("Use -XX:AllocateHeapAt to specify the path to a %s filesystem", filesystem);
return -1;
}
// Try to create an anonymous file using the O_TMPFILE flag. Note that this
// flag requires kernel >= 3.11. If this fails we fall back to open/unlink.
const int fd_anon = os::open(mountpoint.get(), O_TMPFILE|O_EXCL|O_RDWR|O_CLOEXEC, S_IRUSR|S_IWUSR);
if (fd_anon == -1) {
ZErrno err;
! log_debug(gc, init)("Failed to create anonymous file in %s (%s)", mountpoint.get(),
! (err == EINVAL ? "Not supported" : err.to_string()));
} else {
// Get inode number for anonymous file
struct stat stat_buf;
if (fstat(fd_anon, &stat_buf) == -1) {
ZErrno err;
! log_error(gc)("Failed to determine inode number for anonymous file (%s)", err.to_string());
return -1;
}
! log_info(gc, init)("Heap Backing File: %s/#" UINT64_FORMAT, mountpoint.get(), (uint64_t)stat_buf.st_ino);
return fd_anon;
}
! log_debug(gc, init)("Falling back to open/unlink");
// Create file name
char filename[PATH_MAX];
snprintf(filename, sizeof(filename), "%s/%s.%d", mountpoint.get(), name, os::current_process_id());
// Create file
const int fd = os::open(filename, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC, S_IRUSR|S_IWUSR);
if (fd == -1) {
ZErrno err;
! log_error(gc)("Failed to create file %s (%s)", filename, err.to_string());
return -1;
}
// Unlink file
if (unlink(filename) == -1) {
ZErrno err;
! log_error(gc)("Failed to unlink file %s (%s)", filename, err.to_string());
return -1;
}
! log_info(gc, init)("Heap Backing File: %s", filename);
return fd;
}
int ZPhysicalMemoryBacking::create_fd(const char* name) const {
--- 219,275 ----
: z_preferred_tmpfs_mountpoints;
// Find mountpoint
ZMountPoint mountpoint(filesystem, preferred_mountpoints);
if (mountpoint.get() == NULL) {
! log_error_p(gc)("Use -XX:AllocateHeapAt to specify the path to a %s filesystem", filesystem);
return -1;
}
// Try to create an anonymous file using the O_TMPFILE flag. Note that this
// flag requires kernel >= 3.11. If this fails we fall back to open/unlink.
const int fd_anon = os::open(mountpoint.get(), O_TMPFILE|O_EXCL|O_RDWR|O_CLOEXEC, S_IRUSR|S_IWUSR);
if (fd_anon == -1) {
ZErrno err;
! log_debug_p(gc, init)("Failed to create anonymous file in %s (%s)", mountpoint.get(),
! (err == EINVAL ? "Not supported" : err.to_string()));
} else {
// Get inode number for anonymous file
struct stat stat_buf;
if (fstat(fd_anon, &stat_buf) == -1) {
ZErrno err;
! log_error_p(gc)("Failed to determine inode number for anonymous file (%s)", err.to_string());
return -1;
}
! log_info_p(gc, init)("Heap Backing File: %s/#" UINT64_FORMAT, mountpoint.get(), (uint64_t)stat_buf.st_ino);
return fd_anon;
}
! log_debug_p(gc, init)("Falling back to open/unlink");
// Create file name
char filename[PATH_MAX];
snprintf(filename, sizeof(filename), "%s/%s.%d", mountpoint.get(), name, os::current_process_id());
// Create file
const int fd = os::open(filename, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC, S_IRUSR|S_IWUSR);
if (fd == -1) {
ZErrno err;
! log_error_p(gc)("Failed to create file %s (%s)", filename, err.to_string());
return -1;
}
// Unlink file
if (unlink(filename) == -1) {
ZErrno err;
! log_error_p(gc)("Failed to unlink file %s (%s)", filename, err.to_string());
return -1;
}
! log_info_p(gc, init)("Heap Backing File: %s", filename);
return fd;
}
int ZPhysicalMemoryBacking::create_fd(const char* name) const {
*** 281,291 ****
const int fd = create_mem_fd(name);
if (fd != -1) {
return fd;
}
! log_debug(gc, init)("Falling back to searching for an accessible mount point");
}
return create_file_fd(name);
}
--- 282,292 ----
const int fd = create_mem_fd(name);
if (fd != -1) {
return fd;
}
! log_debug_p(gc)("Falling back to searching for an accessible mount point");
}
return create_file_fd(name);
}
*** 296,357 ****
void ZPhysicalMemoryBacking::warn_available_space(size_t max) const {
// Note that the available space on a tmpfs or a hugetlbfs filesystem
// will be zero if no size limit was specified when it was mounted.
if (_available == 0) {
// No size limit set, skip check
! log_info(gc, init)("Available space on backing filesystem: N/A");
return;
}
! log_info(gc, init)("Available space on backing filesystem: " SIZE_FORMAT "M", _available / M);
// Warn if the filesystem doesn't currently have enough space available to hold
// the max heap size. The max heap size will be capped if we later hit this limit
// when trying to expand the heap.
if (_available < max) {
! log_warning(gc)("***** WARNING! INCORRECT SYSTEM CONFIGURATION DETECTED! *****");
! log_warning(gc)("Not enough space available on the backing filesystem to hold the current max Java heap");
! log_warning(gc)("size (" SIZE_FORMAT "M). Please adjust the size of the backing filesystem accordingly "
"(available", max / M);
! log_warning(gc)("space is currently " SIZE_FORMAT "M). Continuing execution with the current filesystem "
"size could", _available / M);
! log_warning(gc)("lead to a premature OutOfMemoryError being thrown, due to failure to map memory.");
}
}
void ZPhysicalMemoryBacking::warn_max_map_count(size_t max) const {
const char* const filename = ZFILENAME_PROC_MAX_MAP_COUNT;
FILE* const file = fopen(filename, "r");
if (file == NULL) {
// Failed to open file, skip check
! log_debug(gc, init)("Failed to open %s", filename);
return;
}
size_t actual_max_map_count = 0;
const int result = fscanf(file, SIZE_FORMAT, &actual_max_map_count);
fclose(file);
if (result != 1) {
// Failed to read file, skip check
! log_debug(gc, init)("Failed to read %s", filename);
return;
}
// The required max map count is impossible to calculate exactly since subsystems
// other than ZGC are also creating memory mappings, and we have no control over that.
// However, ZGC tends to create the most mappings and dominate the total count.
// In the worst cases, ZGC will map each granule three times, i.e. once per heap view.
// We speculate that we need another 20% to allow for non-ZGC subsystems to map memory.
const size_t required_max_map_count = (max / ZGranuleSize) * 3 * 1.2;
if (actual_max_map_count < required_max_map_count) {
! log_warning(gc)("***** WARNING! INCORRECT SYSTEM CONFIGURATION DETECTED! *****");
! log_warning(gc)("The system limit on number of memory mappings per process might be too low for the given");
! log_warning(gc)("max Java heap size (" SIZE_FORMAT "M). Please adjust %s to allow for at",
max / M, filename);
! log_warning(gc)("least " SIZE_FORMAT " mappings (current limit is " SIZE_FORMAT "). Continuing execution "
"with the current", required_max_map_count, actual_max_map_count);
! log_warning(gc)("limit could lead to a fatal error, due to failure to map memory.");
}
}
void ZPhysicalMemoryBacking::warn_commit_limits(size_t max) const {
// Warn if available space is too low
--- 297,358 ----
void ZPhysicalMemoryBacking::warn_available_space(size_t max) const {
// Note that the available space on a tmpfs or a hugetlbfs filesystem
// will be zero if no size limit was specified when it was mounted.
if (_available == 0) {
// No size limit set, skip check
! log_info_p(gc, init)("Available space on backing filesystem: N/A");
return;
}
! log_info_p(gc, init)("Available space on backing filesystem: " SIZE_FORMAT "M", _available / M);
// Warn if the filesystem doesn't currently have enough space available to hold
// the max heap size. The max heap size will be capped if we later hit this limit
// when trying to expand the heap.
if (_available < max) {
! log_warning_p(gc)("***** WARNING! INCORRECT SYSTEM CONFIGURATION DETECTED! *****");
! log_warning_p(gc)("Not enough space available on the backing filesystem to hold the current max Java heap");
! log_warning_p(gc)("size (" SIZE_FORMAT "M). Please adjust the size of the backing filesystem accordingly "
"(available", max / M);
! log_warning_p(gc)("space is currently " SIZE_FORMAT "M). Continuing execution with the current filesystem "
"size could", _available / M);
! log_warning_p(gc)("lead to a premature OutOfMemoryError being thrown, due to failure to map memory.");
}
}
void ZPhysicalMemoryBacking::warn_max_map_count(size_t max) const {
const char* const filename = ZFILENAME_PROC_MAX_MAP_COUNT;
FILE* const file = fopen(filename, "r");
if (file == NULL) {
// Failed to open file, skip check
! log_debug_p(gc, init)("Failed to open %s", filename);
return;
}
size_t actual_max_map_count = 0;
const int result = fscanf(file, SIZE_FORMAT, &actual_max_map_count);
fclose(file);
if (result != 1) {
// Failed to read file, skip check
! log_debug_p(gc, init)("Failed to read %s", filename);
return;
}
// The required max map count is impossible to calculate exactly since subsystems
// other than ZGC are also creating memory mappings, and we have no control over that.
// However, ZGC tends to create the most mappings and dominate the total count.
// In the worst cases, ZGC will map each granule three times, i.e. once per heap view.
// We speculate that we need another 20% to allow for non-ZGC subsystems to map memory.
const size_t required_max_map_count = (max / ZGranuleSize) * 3 * 1.2;
if (actual_max_map_count < required_max_map_count) {
! log_warning_p(gc)("***** WARNING! INCORRECT SYSTEM CONFIGURATION DETECTED! *****");
! log_warning_p(gc)("The system limit on number of memory mappings per process might be too low for the given");
! log_warning_p(gc)("max Java heap size (" SIZE_FORMAT "M). Please adjust %s to allow for at",
max / M, filename);
! log_warning_p(gc)("least " SIZE_FORMAT " mappings (current limit is " SIZE_FORMAT "). Continuing execution "
"with the current", required_max_map_count, actual_max_map_count);
! log_warning_p(gc)("limit could lead to a fatal error, due to failure to map memory.");
}
}
void ZPhysicalMemoryBacking::warn_commit_limits(size_t max) const {
// Warn if available space is too low
*** 562,572 ****
// Failed
return err;
}
// Not supported
! log_debug(gc)("Falling back to fallocate() compatibility mode");
z_fallocate_supported = false;
}
return fallocate_fill_hole_compat(offset, length);
}
--- 563,573 ----
// Failed
return err;
}
// Not supported
! log_debug_p(gc)("Falling back to fallocate() compatibility mode");
z_fallocate_supported = false;
}
return fallocate_fill_hole_compat(offset, length);
}
*** 643,662 ****
// the hugetlbfs filesystem, then we wait and retry a few times before
// giving up. Otherwise there is a risk that running JVMs back-to-back
// will fail, since there is a delay between process termination and the
// huge pages owned by that process being returned to the huge page pool
// and made available for new allocations.
! log_debug(gc, init)("Failed to commit memory (%s), retrying", err.to_string());
// Wait and retry in one second, in the hope that huge pages will be
// available by then.
sleep(1);
goto retry;
}
// Failed
! log_error(gc)("Failed to commit memory (%s)", err.to_string());
return false;
}
// Success
return true;
--- 644,663 ----
// the hugetlbfs filesystem, then we wait and retry a few times before
// giving up. Otherwise there is a risk that running JVMs back-to-back
// will fail, since there is a delay between process termination and the
// huge pages owned by that process being returned to the huge page pool
// and made available for new allocations.
! log_debug_p(gc, init)("Failed to commit memory (%s), retrying", err.to_string());
// Wait and retry in one second, in the hope that huge pages will be
// available by then.
sleep(1);
goto retry;
}
// Failed
! log_error_p(gc)("Failed to commit memory (%s)", err.to_string());
return false;
}
// Success
return true;
< prev index next >