8319969: os::large_page_init() turns off THPs for ZGC
Reviewed-by: stuefe, aboldtch
This commit is contained in:
parent
3edc24a71d
commit
f4822605af
@ -23,16 +23,24 @@
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/z/zLargePages.hpp"
|
||||
#include "hugepages.hpp"
|
||||
#include "os_linux.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
|
||||
void ZLargePages::pd_initialize() {
|
||||
if (UseLargePages) {
|
||||
if (UseTransparentHugePages) {
|
||||
_state = Transparent;
|
||||
} else {
|
||||
_state = Explicit;
|
||||
}
|
||||
} else {
|
||||
_state = Disabled;
|
||||
if (os::Linux::thp_requested()) {
|
||||
// Check if the OS config turned off transparent huge pages for shmem.
|
||||
_os_enforced_transparent_mode = HugePages::shmem_thp_info().is_disabled();
|
||||
_state = _os_enforced_transparent_mode ? Disabled : Transparent;
|
||||
return;
|
||||
}
|
||||
|
||||
if (UseLargePages) {
|
||||
_state = Explicit;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the OS config turned on transparent huge pages for shmem.
|
||||
_os_enforced_transparent_mode = HugePages::shmem_thp_info().is_forced();
|
||||
_state = _os_enforced_transparent_mode ? Transparent : Disabled;
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "gc/z/zNUMA.inline.hpp"
|
||||
#include "gc/z/zPhysicalMemoryBacking_linux.hpp"
|
||||
#include "gc/z/zSyscall_linux.hpp"
|
||||
#include "hugepages.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "os_linux.hpp"
|
||||
#include "runtime/init.hpp"
|
||||
@ -446,8 +447,10 @@ ZErrno ZPhysicalMemoryBacking::fallocate_compat_mmap_tmpfs(zoffset offset, size_
|
||||
return errno;
|
||||
}
|
||||
|
||||
// Advise mapping to use transparent huge pages
|
||||
os::realign_memory((char*)addr, length, ZGranuleSize);
|
||||
// Maybe madvise the mapping to use transparent huge pages
|
||||
if (os::Linux::should_madvise_shmem_thps()) {
|
||||
os::Linux::madvise_transparent_huge_pages(addr, length);
|
||||
}
|
||||
|
||||
// Touch the mapping (safely) to make sure it's backed by memory
|
||||
const bool backed = safe_touch_mapping(addr, length, _block_size);
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
#include "runtime/globals_extension.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
@ -227,15 +228,97 @@ void THPSupport::print_on(outputStream* os) {
|
||||
}
|
||||
}
|
||||
|
||||
ShmemTHPSupport::ShmemTHPSupport() :
|
||||
_initialized(false), _mode(ShmemTHPMode::unknown) {}
|
||||
|
||||
ShmemTHPMode ShmemTHPSupport::mode() const {
|
||||
assert(_initialized, "Not initialized");
|
||||
return _mode;
|
||||
}
|
||||
|
||||
bool ShmemTHPSupport::is_forced() const {
|
||||
return _mode == ShmemTHPMode::always || _mode == ShmemTHPMode::force || _mode == ShmemTHPMode::within_size;
|
||||
}
|
||||
|
||||
bool ShmemTHPSupport::is_enabled() const {
|
||||
return is_forced() || _mode == ShmemTHPMode::advise;
|
||||
}
|
||||
|
||||
bool ShmemTHPSupport::is_disabled() const {
|
||||
return _mode == ShmemTHPMode::never || _mode == ShmemTHPMode::deny || _mode == ShmemTHPMode::unknown;
|
||||
}
|
||||
|
||||
void ShmemTHPSupport::scan_os() {
|
||||
// Scan /sys/kernel/mm/transparent_hugepage/shmem_enabled
|
||||
// see mm/huge_memory.c
|
||||
_mode = ShmemTHPMode::unknown;
|
||||
const char* filename = "/sys/kernel/mm/transparent_hugepage/shmem_enabled";
|
||||
FILE* f = ::fopen(filename, "r");
|
||||
if (f != nullptr) {
|
||||
char buf[64];
|
||||
char* s = fgets(buf, sizeof(buf), f);
|
||||
assert(s == buf, "Should have worked");
|
||||
if (::strstr(buf, "[always]") != nullptr) {
|
||||
_mode = ShmemTHPMode::always;
|
||||
} else if (::strstr(buf, "[within_size]") != nullptr) {
|
||||
_mode = ShmemTHPMode::within_size;
|
||||
} else if (::strstr(buf, "[advise]") != nullptr) {
|
||||
_mode = ShmemTHPMode::advise;
|
||||
} else if (::strstr(buf, "[never]") != nullptr) {
|
||||
_mode = ShmemTHPMode::never;
|
||||
} else if (::strstr(buf, "[deny]") != nullptr) {
|
||||
_mode = ShmemTHPMode::deny;
|
||||
} else if (::strstr(buf, "[force]") != nullptr) {
|
||||
_mode = ShmemTHPMode::force;
|
||||
} else {
|
||||
assert(false, "Weird content of %s: %s", filename, buf);
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
_initialized = true;
|
||||
|
||||
LogTarget(Info, pagesize) lt;
|
||||
if (lt.is_enabled()) {
|
||||
LogStream ls(lt);
|
||||
print_on(&ls);
|
||||
}
|
||||
}
|
||||
|
||||
const char* ShmemTHPSupport::mode_to_string(ShmemTHPMode mode) {
|
||||
switch (mode) {
|
||||
case ShmemTHPMode::always: return "always";
|
||||
case ShmemTHPMode::advise: return "advise";
|
||||
case ShmemTHPMode::within_size: return "within_size";
|
||||
case ShmemTHPMode::never: return "never";
|
||||
case ShmemTHPMode::deny: return "deny";
|
||||
case ShmemTHPMode::force: return "force";
|
||||
case ShmemTHPMode::unknown: // Fallthrough
|
||||
default: return "unknown";
|
||||
};
|
||||
}
|
||||
|
||||
void ShmemTHPSupport::print_on(outputStream* os) {
|
||||
if (_initialized) {
|
||||
os->print_cr("Shared memory transparent hugepage (THP) support:");
|
||||
os->print_cr(" Shared memory THP mode: %s", mode_to_string(_mode));
|
||||
} else {
|
||||
os->print_cr(" unknown.");
|
||||
}
|
||||
}
|
||||
|
||||
StaticHugePageSupport HugePages::_static_hugepage_support;
|
||||
THPSupport HugePages::_thp_support;
|
||||
ShmemTHPSupport HugePages::_shmem_thp_support;
|
||||
|
||||
void HugePages::initialize() {
|
||||
_static_hugepage_support.scan_os();
|
||||
_thp_support.scan_os();
|
||||
_shmem_thp_support.scan_os();
|
||||
}
|
||||
|
||||
void HugePages::print_on(outputStream* os) {
|
||||
_static_hugepage_support.print_on(os);
|
||||
_thp_support.print_on(os);
|
||||
_shmem_thp_support.print_on(os);
|
||||
}
|
||||
|
@ -91,23 +91,58 @@ public:
|
||||
void print_on(outputStream* os);
|
||||
};
|
||||
|
||||
enum class ShmemTHPMode { always, within_size, advise, never, deny, force, unknown };
|
||||
|
||||
// for transparent shmem hugepages
|
||||
class ShmemTHPSupport {
|
||||
bool _initialized;
|
||||
|
||||
// See /sys/kernel/mm/transparent_hugepage/shmem_enabled
|
||||
ShmemTHPMode _mode;
|
||||
|
||||
static const char* mode_to_string(ShmemTHPMode mode);
|
||||
|
||||
public:
|
||||
|
||||
ShmemTHPSupport();
|
||||
|
||||
// Queries the OS, fills in object
|
||||
void scan_os();
|
||||
|
||||
ShmemTHPMode mode() const;
|
||||
|
||||
bool is_forced() const;
|
||||
bool is_enabled() const;
|
||||
bool is_disabled() const;
|
||||
|
||||
// Printing
|
||||
void print_on(outputStream* os);
|
||||
};
|
||||
|
||||
// Umbrella static interface
|
||||
class HugePages : public AllStatic {
|
||||
|
||||
static StaticHugePageSupport _static_hugepage_support;
|
||||
static THPSupport _thp_support;
|
||||
static ShmemTHPSupport _shmem_thp_support;
|
||||
|
||||
public:
|
||||
|
||||
static const StaticHugePageSupport& static_info() { return _static_hugepage_support; }
|
||||
static const THPSupport& thp_info() { return _thp_support; }
|
||||
static const ShmemTHPSupport& shmem_thp_info() { return _shmem_thp_support; }
|
||||
|
||||
static size_t default_static_hugepage_size() { return _static_hugepage_support.default_hugepage_size(); }
|
||||
static bool supports_static_hugepages() { return default_static_hugepage_size() > 0 && !_static_hugepage_support.inconsistent(); }
|
||||
static THPMode thp_mode() { return _thp_support.mode(); }
|
||||
|
||||
static bool supports_thp() { return thp_mode() == THPMode::madvise || thp_mode() == THPMode::always; }
|
||||
static THPMode thp_mode() { return _thp_support.mode(); }
|
||||
static size_t thp_pagesize() { return _thp_support.pagesize(); }
|
||||
|
||||
static bool supports_shmem_thp() { return _shmem_thp_support.is_enabled(); }
|
||||
static ShmemTHPMode shmem_thp_mode() { return _shmem_thp_support.mode(); }
|
||||
static bool forced_shmem_thp() { return _shmem_thp_support.is_forced(); }
|
||||
|
||||
static void initialize();
|
||||
static void print_on(outputStream* os);
|
||||
};
|
||||
|
@ -176,6 +176,8 @@ bool os::Linux::_supports_fast_thread_cpu_time = false;
|
||||
const char * os::Linux::_libc_version = nullptr;
|
||||
const char * os::Linux::_libpthread_version = nullptr;
|
||||
|
||||
bool os::Linux::_thp_requested{false};
|
||||
|
||||
#ifdef __GLIBC__
|
||||
// We want to be buildable and runnable on older and newer glibcs, so resolve both
|
||||
// mallinfo and mallinfo2 dynamically.
|
||||
@ -2213,6 +2215,8 @@ void os::Linux::print_system_memory_info(outputStream* st) {
|
||||
// https://www.kernel.org/doc/Documentation/vm/transhuge.txt
|
||||
_print_ascii_file_h("/sys/kernel/mm/transparent_hugepage/enabled",
|
||||
"/sys/kernel/mm/transparent_hugepage/enabled", st);
|
||||
_print_ascii_file_h("/sys/kernel/mm/transparent_hugepage/shmem_enabled",
|
||||
"/sys/kernel/mm/transparent_hugepage/shmem_enabled", st);
|
||||
_print_ascii_file_h("/sys/kernel/mm/transparent_hugepage/defrag (defrag/compaction efforts parameter)",
|
||||
"/sys/kernel/mm/transparent_hugepage/defrag", st);
|
||||
}
|
||||
@ -2909,11 +2913,15 @@ void os::pd_commit_memory_or_exit(char* addr, size_t size,
|
||||
}
|
||||
}
|
||||
|
||||
void os::Linux::madvise_transparent_huge_pages(void* addr, size_t bytes) {
|
||||
// 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);
|
||||
}
|
||||
|
||||
void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) {
|
||||
if (UseTransparentHugePages && alignment_hint > 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);
|
||||
if (Linux::should_madvise_anonymous_thps() && alignment_hint > vm_page_size()) {
|
||||
Linux::madvise_transparent_huge_pages(addr, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3730,7 +3738,7 @@ static void set_coredump_filter(CoredumpFilterBit bit) {
|
||||
|
||||
static size_t _large_page_size = 0;
|
||||
|
||||
void warn_no_large_pages_configured() {
|
||||
static void warn_no_large_pages_configured() {
|
||||
if (!FLAG_IS_DEFAULT(UseLargePages)) {
|
||||
log_warning(pagesize)("UseLargePages disabled, no large pages configured and available on the system.");
|
||||
}
|
||||
@ -3747,15 +3755,56 @@ struct LargePageInitializationLoggerMark {
|
||||
os::page_sizes().print_on(&ls);
|
||||
ls.print_cr(". Default large page size: " EXACTFMT ".", EXACTFMTARGS(os::large_page_size()));
|
||||
} else {
|
||||
ls.print("Large page support disabled.");
|
||||
ls.print("Large page support %sdisabled.", uses_zgc_shmem_thp() ? "partially " : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool uses_zgc_shmem_thp() {
|
||||
return UseZGC &&
|
||||
// If user requested THP
|
||||
((os::Linux::thp_requested() && HugePages::supports_shmem_thp()) ||
|
||||
// If OS forced THP
|
||||
HugePages::forced_shmem_thp());
|
||||
}
|
||||
};
|
||||
|
||||
static bool validate_thps_configured() {
|
||||
assert(UseTransparentHugePages, "Sanity");
|
||||
assert(os::Linux::thp_requested(), "Sanity");
|
||||
|
||||
if (UseZGC) {
|
||||
if (!HugePages::supports_shmem_thp()) {
|
||||
log_warning(pagesize)("Shared memory transparent huge pages are not enabled in the OS. "
|
||||
"Set /sys/kernel/mm/transparent_hugepage/shmem_enabled to 'advise' to enable them.");
|
||||
// UseTransparentHugePages has historically been tightly coupled with
|
||||
// anonymous THPs. Fall through here and let the validity be determined
|
||||
// by the OS configuration for anonymous THPs. ZGC doesn't use the flag
|
||||
// but instead checks os::Linux::thp_requested().
|
||||
}
|
||||
}
|
||||
|
||||
if (!HugePages::supports_thp()) {
|
||||
log_warning(pagesize)("Anonymous transparent huge pages are not enabled in the OS. "
|
||||
"Set /sys/kernel/mm/transparent_hugepage/enabled to 'madvise' to enable them.");
|
||||
log_warning(pagesize)("UseTransparentHugePages disabled, transparent huge pages are not supported by the operating system.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void os::large_page_init() {
|
||||
Linux::large_page_init();
|
||||
}
|
||||
|
||||
void os::Linux::large_page_init() {
|
||||
LargePageInitializationLoggerMark logger;
|
||||
|
||||
// Decide if the user asked for THPs before we update UseTransparentHugePages.
|
||||
const bool large_pages_turned_off = !FLAG_IS_DEFAULT(UseLargePages) && !UseLargePages;
|
||||
_thp_requested = UseTransparentHugePages && !large_pages_turned_off;
|
||||
|
||||
// Query OS information first.
|
||||
HugePages::initialize();
|
||||
|
||||
@ -3774,7 +3823,7 @@ void os::large_page_init() {
|
||||
FLAG_SET_ERGO(THPStackMitigation, false); // Mitigation not needed
|
||||
}
|
||||
|
||||
// 1) Handle the case where we do not want to use huge pages
|
||||
// Handle the case where we do not want to use huge pages
|
||||
if (!UseLargePages &&
|
||||
!UseTransparentHugePages) {
|
||||
// Not using large pages.
|
||||
@ -3787,17 +3836,16 @@ void os::large_page_init() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 2) check if the OS supports THPs resp. static hugepages.
|
||||
if (UseTransparentHugePages && !HugePages::supports_thp()) {
|
||||
if (!FLAG_IS_DEFAULT(UseTransparentHugePages)) {
|
||||
log_warning(pagesize)("UseTransparentHugePages disabled, transparent huge pages are not supported by the operating system.");
|
||||
}
|
||||
// Check if the OS supports THPs
|
||||
if (UseTransparentHugePages && !validate_thps_configured()) {
|
||||
UseLargePages = UseTransparentHugePages = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the OS supports static hugepages.
|
||||
if (!UseTransparentHugePages && !HugePages::supports_static_hugepages()) {
|
||||
warn_no_large_pages_configured();
|
||||
UseLargePages = UseTransparentHugePages = false;
|
||||
UseLargePages = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3805,7 +3853,7 @@ void os::large_page_init() {
|
||||
// In THP mode:
|
||||
// - os::large_page_size() is the *THP page size*
|
||||
// - os::pagesizes() has two members, the THP page size and the system page size
|
||||
assert(HugePages::supports_thp() && HugePages::thp_pagesize() > 0, "Missing OS info");
|
||||
assert(HugePages::thp_pagesize() > 0, "Missing OS info");
|
||||
_large_page_size = HugePages::thp_pagesize();
|
||||
_page_sizes.add(_large_page_size);
|
||||
_page_sizes.add(os::vm_page_size());
|
||||
@ -3830,12 +3878,12 @@ void os::large_page_init() {
|
||||
// doesn't match an available page size set _large_page_size to default_large_page_size
|
||||
// and use it as the maximum.
|
||||
if (FLAG_IS_DEFAULT(LargePageSizeInBytes) ||
|
||||
LargePageSizeInBytes == 0 ||
|
||||
LargePageSizeInBytes == default_large_page_size) {
|
||||
large_page_size = default_large_page_size;
|
||||
log_info(pagesize)("Using the default large page size: " SIZE_FORMAT "%s",
|
||||
byte_size_in_exact_unit(large_page_size),
|
||||
exact_unit_for_byte_size(large_page_size));
|
||||
LargePageSizeInBytes == 0 ||
|
||||
LargePageSizeInBytes == default_large_page_size) {
|
||||
large_page_size = default_large_page_size;
|
||||
log_info(pagesize)("Using the default large page size: " SIZE_FORMAT "%s",
|
||||
byte_size_in_exact_unit(large_page_size),
|
||||
exact_unit_for_byte_size(large_page_size));
|
||||
} else {
|
||||
if (all_large_pages.contains(LargePageSizeInBytes)) {
|
||||
large_page_size = LargePageSizeInBytes;
|
||||
@ -3860,7 +3908,6 @@ void os::large_page_init() {
|
||||
if (!hugetlbfs_sanity_check(large_page_size)) {
|
||||
warn_no_large_pages_configured();
|
||||
UseLargePages = false;
|
||||
UseTransparentHugePages = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3877,6 +3924,18 @@ void os::large_page_init() {
|
||||
set_coredump_filter(LARGEPAGES_BIT);
|
||||
}
|
||||
|
||||
bool os::Linux::thp_requested() {
|
||||
return _thp_requested;
|
||||
}
|
||||
|
||||
bool os::Linux::should_madvise_anonymous_thps() {
|
||||
return _thp_requested && HugePages::thp_mode() == THPMode::madvise;
|
||||
}
|
||||
|
||||
bool os::Linux::should_madvise_shmem_thps() {
|
||||
return _thp_requested && HugePages::shmem_thp_mode() == ShmemTHPMode::advise;
|
||||
}
|
||||
|
||||
static void log_on_commit_special_failure(char* req_addr, size_t bytes,
|
||||
size_t page_size, int error) {
|
||||
assert(error == ENOMEM, "Only expect to fail if no memory is available");
|
||||
@ -3891,7 +3950,8 @@ static bool commit_memory_special(size_t bytes,
|
||||
size_t page_size,
|
||||
char* req_addr,
|
||||
bool exec) {
|
||||
assert(UseLargePages && !UseTransparentHugePages, "Should only get here for static hugepage mode (+UseLargePages)");
|
||||
assert(UseLargePages, "Should only get here for huge pages");
|
||||
assert(!UseTransparentHugePages, "Should only get here for static hugepage mode");
|
||||
assert(is_aligned(bytes, page_size), "Unaligned size");
|
||||
assert(is_aligned(req_addr, page_size), "Unaligned address");
|
||||
assert(req_addr != nullptr, "Must have a requested address for special mappings");
|
||||
|
@ -175,6 +175,17 @@ class os::Linux {
|
||||
// fields will contain -1.
|
||||
static bool query_process_memory_info(meminfo_t* info);
|
||||
|
||||
// Tells if the user asked for transparent huge pages.
|
||||
static bool _thp_requested;
|
||||
|
||||
static void large_page_init();
|
||||
|
||||
static bool thp_requested();
|
||||
static bool should_madvise_anonymous_thps();
|
||||
static bool should_madvise_shmem_thps();
|
||||
|
||||
static void madvise_transparent_huge_pages(void* addr, size_t bytes);
|
||||
|
||||
// Stack repair handling
|
||||
|
||||
// none present
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "runtime/os.hpp"
|
||||
|
||||
ZLargePages::State ZLargePages::_state;
|
||||
bool ZLargePages::_os_enforced_transparent_mode;
|
||||
|
||||
void ZLargePages::initialize() {
|
||||
pd_initialize();
|
||||
@ -41,9 +42,17 @@ const char* ZLargePages::to_string() {
|
||||
return "Enabled (Explicit)";
|
||||
|
||||
case Transparent:
|
||||
return "Enabled (Transparent)";
|
||||
if (_os_enforced_transparent_mode) {
|
||||
return "Enabled (Transparent, OS enforced)";
|
||||
} else {
|
||||
return "Enabled (Transparent)";
|
||||
}
|
||||
|
||||
default:
|
||||
return "Disabled";
|
||||
if (_os_enforced_transparent_mode) {
|
||||
return "Disabled (OS enforced)";
|
||||
} else {
|
||||
return "Disabled";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ private:
|
||||
};
|
||||
|
||||
static State _state;
|
||||
static bool _os_enforced_transparent_mode;
|
||||
|
||||
static void pd_initialize();
|
||||
|
||||
|
@ -25,7 +25,6 @@
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@ -68,6 +67,9 @@ class HugePageConfiguration {
|
||||
THPMode _thpMode;
|
||||
long _thpPageSize;
|
||||
|
||||
enum ShmemTHPMode {always, within_size, advise, never, deny, force, unknown}
|
||||
ShmemTHPMode _shmemThpMode;
|
||||
|
||||
public Set<StaticHugePageConfig> getStaticHugePageConfigurations() {
|
||||
return _staticHugePageConfigurations;
|
||||
}
|
||||
@ -89,16 +91,21 @@ class HugePageConfiguration {
|
||||
return _thpMode == THPMode.always || _thpMode == THPMode.madvise;
|
||||
}
|
||||
|
||||
public ShmemTHPMode getShmemThpMode() {
|
||||
return _shmemThpMode;
|
||||
}
|
||||
|
||||
// Returns true if static huge pages are supported (whether or not we have configured the pools)
|
||||
public boolean supportsStaticHugePages() {
|
||||
return _staticDefaultHugePageSize > 0 && _staticHugePageConfigurations.size() > 0;
|
||||
}
|
||||
|
||||
public HugePageConfiguration(Set<StaticHugePageConfig> _staticHugePageConfigurations, long _staticDefaultHugePageSize, THPMode _thpMode, long _thpPageSize) {
|
||||
public HugePageConfiguration(Set<StaticHugePageConfig> _staticHugePageConfigurations, long _staticDefaultHugePageSize, THPMode _thpMode, long _thpPageSize, ShmemTHPMode _shmemThpMode) {
|
||||
this._staticHugePageConfigurations = _staticHugePageConfigurations;
|
||||
this._staticDefaultHugePageSize = _staticDefaultHugePageSize;
|
||||
this._thpMode = _thpMode;
|
||||
this._thpPageSize = _thpPageSize;
|
||||
this._shmemThpMode = _shmemThpMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -108,6 +115,7 @@ class HugePageConfiguration {
|
||||
", _staticDefaultHugePageSize=" + _staticDefaultHugePageSize +
|
||||
", _thpMode=" + _thpMode +
|
||||
", _thpPageSize=" + _thpPageSize +
|
||||
", _shmemThpMode=" + _shmemThpMode +
|
||||
'}';
|
||||
}
|
||||
|
||||
@ -117,12 +125,12 @@ class HugePageConfiguration {
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
HugePageConfiguration that = (HugePageConfiguration) o;
|
||||
return _staticDefaultHugePageSize == that._staticDefaultHugePageSize && _thpPageSize == that._thpPageSize &&
|
||||
Objects.equals(_staticHugePageConfigurations, that._staticHugePageConfigurations) && _thpMode == that._thpMode;
|
||||
Objects.equals(_staticHugePageConfigurations, that._staticHugePageConfigurations) && _thpMode == that._thpMode &&
|
||||
_shmemThpMode == that._shmemThpMode;
|
||||
}
|
||||
|
||||
private static long readDefaultHugePageSizeFromOS() {
|
||||
Pattern pat = Pattern.compile("Hugepagesize: *(\\d+) +kB");
|
||||
long result = 0;
|
||||
try (Scanner scanner = new Scanner(new File("/proc/meminfo"))) {
|
||||
while (scanner.hasNextLine()) {
|
||||
Matcher mat = pat.matcher(scanner.nextLine());
|
||||
@ -199,12 +207,41 @@ class HugePageConfiguration {
|
||||
return pagesize;
|
||||
}
|
||||
|
||||
private static ShmemTHPMode readShmemTHPModeFromOS() {
|
||||
ShmemTHPMode mode = ShmemTHPMode.unknown;
|
||||
String file = "/sys/kernel/mm/transparent_hugepage/shmem_enabled";
|
||||
try (FileReader fr = new FileReader(file);
|
||||
BufferedReader reader = new BufferedReader(fr)) {
|
||||
String s = reader.readLine();
|
||||
if (s.contains("[always]")) {
|
||||
mode = ShmemTHPMode.always;
|
||||
} else if (s.contains("[within_size]")) {
|
||||
mode = ShmemTHPMode.within_size;
|
||||
} else if (s.contains("[advise]")) {
|
||||
mode = ShmemTHPMode.advise;
|
||||
} else if (s.contains("[never]")) {
|
||||
mode = ShmemTHPMode.never;
|
||||
} else if (s.contains("[deny]")) {
|
||||
mode = ShmemTHPMode.deny;
|
||||
} else if (s.contains("[force]")) {
|
||||
mode = ShmemTHPMode.force;
|
||||
} else {
|
||||
throw new RuntimeException("Unexpected content of " + file + ": " + s);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.out.println("Failed to read " + file);
|
||||
// Happens when the kernel is not built to support THPs.
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
// Fill object with info read from proc file system
|
||||
public static HugePageConfiguration readFromOS() throws IOException {
|
||||
return new HugePageConfiguration(readSupportedHugePagesFromOS(),
|
||||
readDefaultHugePageSizeFromOS(),
|
||||
readTHPModeFromOS(),
|
||||
readTHPPageSizeFromOS());
|
||||
readTHPPageSizeFromOS(),
|
||||
readShmemTHPModeFromOS());
|
||||
}
|
||||
|
||||
public static long parseSIUnit(String num, String unit) {
|
||||
@ -227,14 +264,18 @@ class HugePageConfiguration {
|
||||
// [0.001s][info][pagesize] Transparent hugepage (THP) support:
|
||||
// [0.001s][info][pagesize] THP mode: madvise
|
||||
// [0.001s][info][pagesize] THP pagesize: 2M
|
||||
// [0.001s][info][pagesize] Shared memory transparent hugepage (THP) support:
|
||||
// [0.001s][info][pagesize] Shared memory THP mode: always
|
||||
TreeSet<StaticHugePageConfig> staticHugePageConfigs = new TreeSet<>();
|
||||
long defaultHugepageSize = 0;
|
||||
THPMode thpMode = THPMode.never;
|
||||
ShmemTHPMode shmemThpMode = ShmemTHPMode.unknown;
|
||||
long thpPageSize = 0;
|
||||
Pattern patternHugepageSize = Pattern.compile(".*\\[pagesize] *hugepage size: (\\d+)([KMG])");
|
||||
Pattern patternDefaultHugepageSize = Pattern.compile(".*\\[pagesize] *default hugepage size: (\\d+)([KMG]) *");
|
||||
Pattern patternTHPPageSize = Pattern.compile(".*\\[pagesize] *THP pagesize: (\\d+)([KMG])");
|
||||
Pattern patternTHPMode = Pattern.compile(".*\\[pagesize] *THP mode: (\\S+)");
|
||||
Pattern patternTHPPageSize = Pattern.compile(".*\\[pagesize] * THP pagesize: (\\d+)([KMG])");
|
||||
Pattern patternTHPMode = Pattern.compile(".*\\[pagesize] * THP mode: (\\S+)");
|
||||
Pattern patternShmemTHPMode = Pattern.compile(".*\\[pagesize] *Shared memory THP mode: (\\S+)");
|
||||
List<String> lines = output.asLines();
|
||||
for (String s : lines) {
|
||||
Matcher mat = patternHugepageSize.matcher(s);
|
||||
@ -262,9 +303,13 @@ class HugePageConfiguration {
|
||||
if (mat.matches()) {
|
||||
thpMode = THPMode.valueOf(mat.group(1));
|
||||
}
|
||||
mat = patternShmemTHPMode.matcher(s);
|
||||
if (mat.matches()) {
|
||||
shmemThpMode = ShmemTHPMode.valueOf(mat.group(1));
|
||||
}
|
||||
}
|
||||
|
||||
return new HugePageConfiguration(staticHugePageConfigs, defaultHugepageSize, thpMode, thpPageSize);
|
||||
return new HugePageConfiguration(staticHugePageConfigs, defaultHugepageSize, thpMode, thpPageSize, shmemThpMode);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -143,10 +143,12 @@ public class TestTracePageSizes {
|
||||
// or the end of file is encountered.
|
||||
static final Pattern SECTION_START_PATT = Pattern.compile("^([a-f0-9]+)-([a-f0-9]+) [\\-rwpsx]{4}.*");
|
||||
static final Pattern KERNEL_PAGESIZE_PATT = Pattern.compile("^KernelPageSize:\\s*(\\d*) kB");
|
||||
static final Pattern THP_ELIGIBLE_PATT = Pattern.compile("^THPeligible:\\s+(\\d*)");
|
||||
static final Pattern VMFLAGS_PATT = Pattern.compile("^VmFlags: ([\\w\\? ]*)");
|
||||
String start;
|
||||
String end;
|
||||
String ps;
|
||||
String thpEligible;
|
||||
String vmFlags;
|
||||
int lineno;
|
||||
|
||||
@ -154,12 +156,13 @@ public class TestTracePageSizes {
|
||||
start = null;
|
||||
end = null;
|
||||
ps = null;
|
||||
thpEligible = null;
|
||||
vmFlags = null;
|
||||
}
|
||||
|
||||
public void finish() {
|
||||
if (start != null) {
|
||||
RangeWithPageSize range = new RangeWithPageSize(start, end, ps, vmFlags);
|
||||
RangeWithPageSize range = new RangeWithPageSize(start, end, ps, thpEligible, vmFlags);
|
||||
ranges.add(range);
|
||||
debug("Added range: " + range);
|
||||
reset();
|
||||
@ -167,10 +170,15 @@ public class TestTracePageSizes {
|
||||
}
|
||||
|
||||
void eatNext(String line) {
|
||||
debug("" + (lineno++) + " " + line);
|
||||
// For better debugging experience call finish here before the debug() call.
|
||||
Matcher matSectionStart = SECTION_START_PATT.matcher(line);
|
||||
if (matSectionStart.matches()) {
|
||||
finish();
|
||||
}
|
||||
|
||||
debug("" + (lineno++) + " " + line);
|
||||
|
||||
if (matSectionStart.matches()) {
|
||||
start = matSectionStart.group(1);
|
||||
end = matSectionStart.group(2);
|
||||
ps = null;
|
||||
@ -182,6 +190,11 @@ public class TestTracePageSizes {
|
||||
ps = matKernelPageSize.group(1);
|
||||
return;
|
||||
}
|
||||
Matcher matTHPEligible = THP_ELIGIBLE_PATT.matcher(line);
|
||||
if (matTHPEligible.matches()) {
|
||||
thpEligible = matTHPEligible.group(1);
|
||||
return;
|
||||
}
|
||||
Matcher matVmFlags = VMFLAGS_PATT.matcher(line);
|
||||
if (matVmFlags.matches()) {
|
||||
vmFlags = matVmFlags.group(1);
|
||||
@ -326,15 +339,18 @@ class RangeWithPageSize {
|
||||
private long start;
|
||||
private long end;
|
||||
private long pageSize;
|
||||
private boolean thpEligible;
|
||||
private boolean vmFlagHG;
|
||||
private boolean vmFlagHT;
|
||||
private boolean isTHP;
|
||||
|
||||
public RangeWithPageSize(String start, String end, String pageSize, String vmFlags) {
|
||||
public RangeWithPageSize(String start, String end, String pageSize, String thpEligible, String vmFlags) {
|
||||
// Note: since we insist on kernels >= 3.8, all the following information should be present
|
||||
// (none of the input strings be null).
|
||||
this.start = Long.parseUnsignedLong(start, 16);
|
||||
this.end = Long.parseUnsignedLong(end, 16);
|
||||
this.pageSize = Long.parseLong(pageSize);
|
||||
this.thpEligible = Integer.parseInt(thpEligible) == 1;
|
||||
|
||||
vmFlagHG = false;
|
||||
vmFlagHT = false;
|
||||
@ -348,6 +364,13 @@ class RangeWithPageSize {
|
||||
vmFlagHG = true;
|
||||
}
|
||||
}
|
||||
|
||||
// When the THP policy is 'always' instead of 'madvise, the vmFlagHG property is false.
|
||||
// Check the THPeligible property instead.
|
||||
isTHP = !vmFlagHT && this.thpEligible;
|
||||
|
||||
// vmFlagHG should imply isTHP
|
||||
assert !vmFlagHG || isTHP;
|
||||
}
|
||||
|
||||
public long getPageSize() {
|
||||
@ -355,7 +378,7 @@ class RangeWithPageSize {
|
||||
}
|
||||
|
||||
public boolean isTransparentHuge() {
|
||||
return vmFlagHG;
|
||||
return isTHP;
|
||||
}
|
||||
|
||||
public boolean isExplicitHuge() {
|
||||
@ -368,6 +391,6 @@ class RangeWithPageSize {
|
||||
|
||||
public String toString() {
|
||||
return "[" + Long.toHexString(start) + ", " + Long.toHexString(end) + ") " +
|
||||
"pageSize=" + pageSize + "KB isTHP=" + vmFlagHG + " isHUGETLB=" + vmFlagHT;
|
||||
"pageSize=" + pageSize + "KB isTHP=" + isTHP + " isHUGETLB=" + vmFlagHT;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user