diff --git a/runtime/compiler/control/J9Options.cpp b/runtime/compiler/control/J9Options.cpp index b90cabefb66..8f7c5987aed 100644 --- a/runtime/compiler/control/J9Options.cpp +++ b/runtime/compiler/control/J9Options.cpp @@ -1448,11 +1448,11 @@ J9::Options::fePreProcess(void * base) // fePreProcess is called twice - for AOT and JIT options parsing, which is redundant in terms of // processing the -Xlp:codecache options. // We should parse the -Xlp:codecache options only once though to avoid duplicate NLS messages. - static bool parsedXlpCodeCacheOptions = false; + static bool parsedCodeCacheOptions = false; - if (!parsedXlpCodeCacheOptions) + if (!parsedCodeCacheOptions) { - parsedXlpCodeCacheOptions = true; + parsedCodeCacheOptions = true; UDATA requestedLargeCodePageSize = 0; UDATA requestedLargeCodePageFlags = J9PORT_VMEM_PAGE_FLAG_NOT_USED; @@ -1460,9 +1460,11 @@ J9::Options::fePreProcess(void * base) UDATA largePageFlags = 0; int32_t xlpCodeCacheIndex = FIND_ARG_IN_VMARGS(STARTSWITH_MATCH, "-Xlp:codecache:", NULL); int32_t xlpIndex = FIND_ARG_IN_VMARGS(EXACT_MEMORY_MATCH, "-Xlp", NULL); + J9LargePageCompatibilityOptions *largePageOptionConfig = &(vm->largePageOption); + int32_t largePageArgIndex = largePageOptionConfig->optionIndex; // Parse -Xlp:codecache:pagesize= as the right most option - if (xlpCodeCacheIndex > xlpIndex) + if ((xlpCodeCacheIndex > xlpIndex) && (xlpCodeCacheIndex > largePageArgIndex)) { TR_XlpCodeCacheOptions parsingState = XLPCC_PARSING_FIRST_OPTION; UDATA optionNumber = 1; @@ -1685,12 +1687,17 @@ J9::Options::fePreProcess(void * base) j9nls_printf(PORTLIB, J9NLS_INFO, J9NLS_JIT_OPTIONS_XLP_EXTRA_COMMA); } // Parse Size -Xlp - else if (xlpIndex >= 0) + else if (xlpIndex > largePageArgIndex) { // GET_MEMORY_VALUE macro casts it's second parameter to (char**)&, so a pointer to the option string is passed rather than the string literal. char *lpOption = "-Xlp"; GET_MEMORY_VALUE(xlpIndex, lpOption, requestedLargeCodePageSize); } + // Parse -XX:LargePageSizeInBytes= + else if ((largePageArgIndex >= 0) && (largePageOptionConfig->pageSizeRequested != -1)) + { + requestedLargeCodePageSize = largePageOptionConfig->pageSizeRequested; + } if (requestedLargeCodePageSize != 0) { @@ -1739,6 +1746,12 @@ J9::Options::fePreProcess(void * base) } } } + // Handle -XX:+UseLargePages + else if (largePageArgIndex >= 0) + { + // Requesting the preferred large page configured on the system. + j9vmem_default_large_page_size_ex(J9PORT_VMEM_MEMORY_MODE_EXECUTE, &largePageSize, &largePageFlags); + } // When no -Xlp arguments are passed, we should use preferred page sizes else { diff --git a/runtime/gc_modron_startup/mmparse.cpp b/runtime/gc_modron_startup/mmparse.cpp index 56073aec4dd..36760901cb5 100644 --- a/runtime/gc_modron_startup/mmparse.cpp +++ b/runtime/gc_modron_startup/mmparse.cpp @@ -559,18 +559,148 @@ xlpSubOptionsParser(J9JavaVM *vm, IDATA xlpIndex, XlpError *xlpError, UDATA *req return xlpErrorState; } +/** + * Given the requested size of the large pages to be used, the method will verify that value is supported by the system. + * If the value is not supported, the system will set preffered Large Page size if configured on the system. + * The user will also be notified of the altered value being used. + */ +void +verifyLargePageSize(J9JavaVM *vm, UDATA requestedPageSize, UDATA requestedPageFlags) +{ + UDATA pageSize = requestedPageSize; + UDATA pageFlags = requestedPageFlags; + MM_GCExtensions *extensions = MM_GCExtensions::getExtensions(vm); + BOOLEAN isRequestedSizeSupported = FALSE; + PORT_ACCESS_FROM_JAVAVM(vm); + + IDATA result = j9vmem_find_valid_page_size(0, &pageSize, &pageFlags, &isRequestedSizeSupported); + + /* + * j9vmem_find_valid_page_size happened to be changed to always return 0 + * However formally the function type still be IDATA so assert if it returns anything else + */ + Assert_MM_true(0 == result); + + extensions->requestedPageSize = pageSize; + extensions->requestedPageFlags = pageFlags; + + if (!isRequestedSizeSupported) { + /* Print a message indicating requested page size is not supported and a different page size will be used */ + const char *oldQualifier, *newQualifier; + const char *oldPageType = NULL; + const char *newPageType = NULL; + UDATA oldSize = requestedPageSize; + UDATA newSize = pageSize; + qualifiedSize(&oldSize, &oldQualifier); + qualifiedSize(&newSize, &newQualifier); + if (0 == (J9PORT_VMEM_PAGE_FLAG_NOT_USED & requestedPageFlags)) { + oldPageType = getPageTypeString(requestedPageFlags); + } + if (0 == (J9PORT_VMEM_PAGE_FLAG_NOT_USED & pageFlags)) { + newPageType = getPageTypeString(pageFlags); + } + if (NULL == oldPageType) { + if (NULL == newPageType) { + j9nls_printf(PORTLIB, J9NLS_INFO, J9NLS_GC_OPTIONS_LARGE_PAGE_SIZE_NOT_SUPPORTED, oldSize, oldQualifier, newSize, newQualifier); + } else { + j9nls_printf(PORTLIB, J9NLS_INFO, J9NLS_GC_OPTIONS_LARGE_PAGE_SIZE_NOT_SUPPORTED_WITH_NEW_PAGETYPE, oldSize, oldQualifier, newSize, newQualifier, newPageType); + } + } else { + if (NULL == newPageType) { + j9nls_printf(PORTLIB, J9NLS_INFO, J9NLS_GC_OPTIONS_LARGE_PAGE_SIZE_NOT_SUPPORTED_WITH_REQUESTED_PAGETYPE, oldSize, oldQualifier, oldPageType, newSize, newQualifier); + } else { + j9nls_printf(PORTLIB, J9NLS_INFO, J9NLS_GC_OPTIONS_LARGE_PAGE_SIZE_NOT_SUPPORTED_WITH_PAGETYPE, oldSize, oldQualifier, oldPageType, newSize, newQualifier, newPageType); + } + } + } +} + +/** + * + * Obtains and sets the preferred page size available on the system. + * Returns true if the operation was successful. + * + */ +bool +gcSetPreferredPageSize(J9JavaVM *vm) +{ + UDATA defaultLargePageSize = 0; + UDATA defaultLargePageFlags = J9PORT_VMEM_PAGE_FLAG_NOT_USED; + MM_GCExtensions *extensions = MM_GCExtensions::getExtensions(vm); + PORT_ACCESS_FROM_JAVAVM(vm); + + /* Get the default large page size of non pageable */ + j9vmem_default_large_page_size_ex(0, &defaultLargePageSize, &defaultLargePageFlags); + + if (0 != defaultLargePageSize) { + extensions->requestedPageSize = defaultLargePageSize; + extensions->requestedPageFlags = defaultLargePageFlags; + } else { + return false; + } + + return true; +} + +/** + * + * Sets the large page size used within the objectheap when the options -XX:+UseLargePages or -XX:LargePageSizeInBytes= are used. + * The value of the large page size will only be overwritten when these arguments are located in the right most index. + * This is compared to the indices of -Xlp, -Xlp, and -Xlp:objectheap:pagesize= + * + */ +static bool +gcProcessXXLargePageObjectHeapArguments(J9JavaVM *vm) +{ + PORT_ACCESS_FROM_JAVAVM(vm); + MM_GCExtensions *extensions = MM_GCExtensions::getExtensions(vm); + J9LargePageCompatibilityOptions *optionConfig = &(vm->largePageOption); + + if (-1 == optionConfig->pageSizeRequested) { + + UDATA defaultLargePageSize = 0; +#if defined(J9ZOS390) + UDATA defaultLargePageFlags = J9PORT_VMEM_PAGE_FLAG_PAGEABLE_PREFERABLE; +#else /* J9ZOS390 */ + UDATA defaultLargePageFlags = J9PORT_VMEM_PAGE_FLAG_NOT_USED; +#endif + + j9vmem_default_large_page_size_ex(0, &defaultLargePageSize, &defaultLargePageFlags); + + if (0 != defaultLargePageSize) { + extensions->requestedPageSize = defaultLargePageSize; + extensions->requestedPageFlags = defaultLargePageFlags; + } else { + j9nls_printf(PORTLIB, J9NLS_ERROR, J9NLS_GC_OPTIONS_SYSTEM_CONFIG_OPTION_NOT_SUPPORTED, "-XX:+UseLargePages"); + return false; + } + } else { + UDATA largePageSizeRequested = optionConfig->pageSizeRequested; +#if defined(J9ZOS390) + UDATA largePageFlagRequested = J9PORT_VMEM_PAGE_FLAG_PAGEABLE_PREFERABLE; +#else /* J9ZOS390 */ + UDATA largePageFlagRequested = J9PORT_VMEM_PAGE_FLAG_NOT_USED; +#endif + verifyLargePageSize(vm, largePageSizeRequested, largePageFlagRequested); + } + + return true; +} + /** * Find and consume -Xlp option(s) from the argument list. * * @param vm pointer to Java VM structure * - * @return false if the option(s) are not consumed properly, true on success. + * @return -1 if the option(s) are not consumed properly, + * -2 if no option was consumed, + * or the index of the right most option consumed. */ -static bool +static IDATA gcParseXlpOption(J9JavaVM *vm) { MM_GCExtensions *extensions = MM_GCExtensions::getExtensions(vm); - bool rc = false; + IDATA rc = -2; XlpErrorState xlpErrorState = XLP_NO_ERROR; XlpError xlpError = {NULL, /* xlpOptionErrorString */ 0, /* xlpOptionErrorStringSize */ @@ -587,16 +717,14 @@ gcParseXlpOption(J9JavaVM *vm) /* Parse -Xlp option. * -Xlp option enables large pages with the default large page size, but will not * override any -Xlp or -Xlp:objectheap:pagesize= option. + * + * -XX:+UseLargePages. Has Same behaviour as -Xlp. Check if it has been parsed. */ xlpIndex = option_set(vm, "-Xlp", EXACT_MATCH); if (-1 != xlpIndex) { - UDATA defaultLargePageSize = 0; - UDATA defaultLargePageFlags = J9PORT_VMEM_PAGE_FLAG_NOT_USED; - j9vmem_default_large_page_size_ex(0, &defaultLargePageSize, &defaultLargePageFlags); - if (0 != defaultLargePageSize) { - extensions->requestedPageSize = defaultLargePageSize; - extensions->requestedPageFlags = defaultLargePageFlags; - } else { + /* Keep track of most-right index to return */ + rc = xlpIndex; + if (!gcSetPreferredPageSize(vm)) { xlpErrorState = XLP_OPTION_NOT_SUPPORTED; xlpError.xlpOptionErrorString = "-Xlp"; /* Cannot report error message here, @@ -604,10 +732,13 @@ gcParseXlpOption(J9JavaVM *vm) */ } } - /* Parse -Xlp option. It overrides -Xlp option. */ xlpMemIndex = FIND_AND_CONSUME_ARG(EXACT_MEMORY_MATCH, "-Xlp", NULL); if (-1 != xlpMemIndex) { + + /* Keep track of most-right index to return */ + rc = xlpMemIndex; + /* Reset error state from parsing of previous -Xlp option */ xlpErrorState = XLP_NO_ERROR; @@ -652,7 +783,10 @@ gcParseXlpOption(J9JavaVM *vm) xlpObjectHeapIndex = FIND_AND_CONSUME_ARG(STARTSWITH_MATCH, "-Xlp:objectheap:", NULL); /* so if -Xlp:objectheap: is specified */ - if ((-1 != xlpObjectHeapIndex) && (xlpObjectHeapIndex > xlpMemIndex)) { + if (xlpObjectHeapIndex > xlpMemIndex) { + /* Keep track of most-right index to return */ + rc = xlpObjectHeapIndex; + /* * Parse sub options for -Xlp:objectheap: */ @@ -672,50 +806,7 @@ gcParseXlpOption(J9JavaVM *vm) /* If a valid -Xlp or -Xlp:objectheap:pagesize= is present, check if the requested page size is supported */ /* We don't need to check error state here - we did goto for all errors */ if ((-1 != xlpMemIndex) || (-1 != xlpObjectHeapIndex)) { - UDATA pageSize = requestedPageSize; - UDATA pageFlags = requestedPageFlags; - BOOLEAN isRequestedSizeSupported = FALSE; - - IDATA result = j9vmem_find_valid_page_size(0, &pageSize, &pageFlags, &isRequestedSizeSupported); - - /* - * j9vmem_find_valid_page_size happened to be changed to always return 0 - * However formally the function type still be IDATA so assert if it returns anything else - */ - Assert_MM_true(0 == result); - - extensions->requestedPageSize = pageSize; - extensions->requestedPageFlags = pageFlags; - - if (!isRequestedSizeSupported) { - /* Print a message indicating requested page size is not supported and a different page size will be used */ - const char *oldQualifier, *newQualifier; - const char *oldPageType = NULL; - const char *newPageType = NULL; - UDATA oldSize = requestedPageSize; - UDATA newSize = pageSize; - qualifiedSize(&oldSize, &oldQualifier); - qualifiedSize(&newSize, &newQualifier); - if (0 == (J9PORT_VMEM_PAGE_FLAG_NOT_USED & requestedPageFlags)) { - oldPageType = getPageTypeString(requestedPageFlags); - } - if (0 == (J9PORT_VMEM_PAGE_FLAG_NOT_USED & pageFlags)) { - newPageType = getPageTypeString(pageFlags); - } - if (NULL == oldPageType) { - if (NULL == newPageType) { - j9nls_printf(PORTLIB, J9NLS_INFO, J9NLS_GC_OPTIONS_LARGE_PAGE_SIZE_NOT_SUPPORTED, oldSize, oldQualifier, newSize, newQualifier); - } else { - j9nls_printf(PORTLIB, J9NLS_INFO, J9NLS_GC_OPTIONS_LARGE_PAGE_SIZE_NOT_SUPPORTED_WITH_NEW_PAGETYPE, oldSize, oldQualifier, newSize, newQualifier, newPageType); - } - } else { - if (NULL == newPageType) { - j9nls_printf(PORTLIB, J9NLS_INFO, J9NLS_GC_OPTIONS_LARGE_PAGE_SIZE_NOT_SUPPORTED_WITH_REQUESTED_PAGETYPE, oldSize, oldQualifier, oldPageType, newSize, newQualifier); - } else { - j9nls_printf(PORTLIB, J9NLS_INFO, J9NLS_GC_OPTIONS_LARGE_PAGE_SIZE_NOT_SUPPORTED_WITH_PAGETYPE, oldSize, oldQualifier, oldPageType, newSize, newQualifier, newPageType); - } - } - } + verifyLargePageSize(vm, requestedPageSize, requestedPageFlags); } /* @@ -775,7 +866,7 @@ gcParseXlpOption(J9JavaVM *vm) /* If error occurred during parsing of -Xlp options, report it here. */ if (XLP_NO_ERROR != xlpErrorState) { /* parsing failed, return false */ - rc = false; + rc = -1; switch(xlpErrorState) { case XLP_OPTION_NOT_SUPPORTED: @@ -817,8 +908,6 @@ gcParseXlpOption(J9JavaVM *vm) j9nls_printf(PORTLIB, J9NLS_ERROR, J9NLS_GC_OPTIONS_XLP_PARSING_ERROR); break; } - } else { - rc = true; } return rc; @@ -840,12 +929,19 @@ gcParseSovereignArguments(J9JavaVM *vm) #endif /* J9VM_GC_LARGE_OBJECT_AREA */ const char *optionFound = NULL; IDATA index = -1; + J9LargePageCompatibilityOptions *largePageOptionConfig = &(vm->largePageOption); PORT_ACCESS_FROM_JAVAVM(vm); - if (!gcParseXlpOption(vm)) { + IDATA xlpOptionIndex = gcParseXlpOption(vm); + if (-1 == xlpOptionIndex) { goto _error; } + /* Setup to handle additional objectheap arguments */ + if ((-1 != largePageOptionConfig->optionIndex) && (largePageOptionConfig->optionIndex > xlpOptionIndex) && (!gcProcessXXLargePageObjectHeapArguments(vm))) { + goto _error; + } + /* Check for explicit specification of GC policy */ gcParseXgcpolicy(extensions); diff --git a/runtime/oti/j9nonbuilder.h b/runtime/oti/j9nonbuilder.h index 621ae109c31..37d7d43a551 100644 --- a/runtime/oti/j9nonbuilder.h +++ b/runtime/oti/j9nonbuilder.h @@ -4755,6 +4755,13 @@ typedef struct J9VMRuntimeStateListener { UDATA idleTuningFlags; } J9VMRuntimeStateListener; +/* J9LargePageCompatibilityOptions contains the index of the large page option to be used. Size is the size requested if applicable. */ + +typedef struct J9LargePageCompatibilityOptions { + IDATA pageSizeRequested; + IDATA optionIndex; +} J9LargePageCompatibilityOptions; + /* Values for J9VMRuntimeStateListener.vmRuntimeState * These values are reflected in the Java class library code(RuntimeMXBean) */ @@ -5150,6 +5157,7 @@ typedef struct J9JavaVM { U_32 minimumReservedRatio; U_32 cancelAbsoluteThreshold; U_32 minimumLearningRatio; + J9LargePageCompatibilityOptions largePageOption; } J9JavaVM; #define J9VM_PHASE_NOT_STARTUP 2 diff --git a/runtime/oti/j9port.h b/runtime/oti/j9port.h index ca36371e478..8a41b46d7f9 100644 --- a/runtime/oti/j9port.h +++ b/runtime/oti/j9port.h @@ -740,6 +740,7 @@ typedef struct J9CacheInfoQuery { #define J9PORT_VMEM_ALLOC_DIR_BOTTOM_UP OMRPORT_VMEM_ALLOC_DIR_BOTTOM_UP #define J9PORT_VMEM_STRICT_ADDRESS OMRPORT_VMEM_STRICT_ADDRESS #define J9PORT_VMEM_PAGE_FLAG_PAGEABLE OMRPORT_VMEM_PAGE_FLAG_PAGEABLE +#define J9PORT_VMEM_PAGE_FLAG_PAGEABLE_PREFERABLE OMRPORT_VMEM_PAGE_FLAG_PAGEABLE_PREFERABLE #define J9PORT_VMEM_PAGE_FLAG_FIXED OMRPORT_VMEM_PAGE_FLAG_FIXED #define J9PORT_VMEM_PAGE_FLAG_NOT_USED OMRPORT_VMEM_PAGE_FLAG_NOT_USED #define J9PORT_VMEM_STRICT_PAGE_SIZE OMRPORT_VMEM_STRICT_PAGE_SIZE diff --git a/runtime/oti/jvminit.h b/runtime/oti/jvminit.h index c5e7ad00d65..fcc98a95fd9 100644 --- a/runtime/oti/jvminit.h +++ b/runtime/oti/jvminit.h @@ -515,6 +515,8 @@ enum INIT_STAGE { #define MAPOPT_XXONOUTOFMEMORYERROR_EQUALS "-XX:OnOutOfMemoryError=" #define MAPOPT_XXENABLEEXITONOUTOFMEMORYERROR "-XX:+ExitOnOutOfMemoryError" #define MAPOPT_XXDISABLEEXITONOUTOFMEMORYERROR "-XX:-ExitOnOutOfMemoryError" +#define MAPOPT_XXLARGEPAGESIZEINBYTES_EQUALS "-XX:LargePageSizeInBytes=" +#define MAPOPT_XXUSELARGEPAGES "-XX:+UseLargePages" #define MAPOPT_XXPARALLELCMSTHREADS_EQUALS "-XX:ParallelCMSThreads=" #define MAPOPT_XXCONCGCTHREADS_EQUALS "-XX:ConcGCThreads=" #define MAPOPT_XXPARALLELGCTHREADS_EQUALS "-XX:ParallelGCThreads=" diff --git a/runtime/vm/jvminit.c b/runtime/vm/jvminit.c index 3ee70fd1722..017172ee760 100644 --- a/runtime/vm/jvminit.c +++ b/runtime/vm/jvminit.c @@ -1871,7 +1871,35 @@ IDATA VMInitStages(J9JavaVM *vm, IDATA stage, void* reserved) { } } #endif /* !defined(WIN32) && !defined(J9ZTPF) */ + /* Parse options related to Large Pages */ + { + IDATA argIndexUseLargePages = FIND_AND_CONSUME_ARG(EXACT_MATCH, MAPOPT_XXUSELARGEPAGES, NULL); + IDATA argIndexLargePageSizeInBytes = FIND_AND_CONSUME_ARG(STARTSWITH_MATCH, MAPOPT_XXLARGEPAGESIZEINBYTES_EQUALS, NULL); + J9LargePageCompatibilityOptions *optionConfig = &(vm->largePageOption); + if (argIndexUseLargePages > argIndexLargePageSizeInBytes) { + optionConfig->optionIndex = argIndexUseLargePages; + optionConfig->pageSizeRequested = -1; + } + else if (-1 != argIndexLargePageSizeInBytes) { + UDATA requestedLargeCodePageSize = 0; + char *lpOption = MAPOPT_XXLARGEPAGESIZEINBYTES_EQUALS; + + optionConfig->optionIndex = argIndexLargePageSizeInBytes; + + /* Extract size argument */ + parseError = GET_MEMORY_VALUE(argIndexLargePageSizeInBytes, lpOption, requestedLargeCodePageSize); + if (OPTION_OK != parseError) { + parseErrorOption = MAPOPT_XXLARGEPAGESIZEINBYTES_EQUALS; + goto _memParseError; + } + + optionConfig->pageSizeRequested = requestedLargeCodePageSize; + } + else { + optionConfig->optionIndex = -1; + } + } #if defined(AIXPPC) /* Override the AIX soft limit on the data segment to avoid getting EAGAIN when creating a new thread, * which results in an OutOfMemoryException. Also provides compatibility with IBM Java 8.