Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Specify heap limits as percentage of total memory #1699

Merged
merged 1 commit into from
May 24, 2018

Conversation

ashu-mehra
Copy link
Contributor

@ashu-mehra ashu-mehra commented Apr 16, 2018

Add options for specifying heap limits in terms of percentage of
total memory available to the JVM.
Following options are added:

  1. -XX:MaxRAMPercentage=N where 0 <= N <= 100.0
    This option specifies maximum heap size. If -Xmx is specified, this
    option is ignored.
  2. -XX:InitialRAMPercentage=N where 0 <= N <= 100.0
    This option specifies initial heap size. If -Xms is specified, this
    option is ignored.

Closes: #1428

Signed-off-by: Ashutosh Mehra asmehra1@in.ibm.com

@pshipton
Copy link
Member

The description should contain -XX:MaxRAMPercentage instead of -XX:MaxRAMPercent, same for -XX:InitialRAMPercentage

@ashu-mehra
Copy link
Contributor Author

The description should contain -XX:MaxRAMPercentage instead of -XX:MaxRAMPercent, same for -XX:InitialRAMPercentage

Updated the comment, as well as the commit message.

@dmitripivkine
Copy link
Contributor

dmitripivkine commented Apr 16, 2018

Discussion question: Do we need full (signed) double parsing for this particular case? If we do it unsigned would be no underflow case to handle. If we need to have general double parsing I am ok with it

@dmitripivkine dmitripivkine requested review from DanHeidinga and removed request for amicic April 16, 2018 18:33
extensions->memoryMax = (usableMemory / 100) * maxRAMPercent;

/* Hack table to appear that -Xmx was specified */
memoryParameters[opt_Xmx] = index;
Copy link
Contributor

@dmitripivkine dmitripivkine Apr 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this solution. I believe the option should be parsed and stored in gc extensions. MemoryMax and initialMemorySize should be adjusted at startup properly. I would try to avoid any decisions in parse module.

extensions->initialMemorySize = (usableMemory / 100) * initialRAMPercent;

/* Hack table to appear that -Xms was specified */
memoryParameters[opt_Xms] = index;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the same as comment for MemoryMax

@ashu-mehra ashu-mehra force-pushed the add_gc_options_v3 branch 5 times, most recently from 4945ac1 to 127ca3c Compare April 24, 2018 11:20
@ashu-mehra
Copy link
Contributor Author

Do we need full (signed) double parsing for this particular case? If we do it unsigned would be no underflow case to handle. If we need to have general double parsing I am ok with it

I have updated the code to avoid signed parsing.

@dmitripivkine @DanHeidinga can you please review the changes.

@ashu-mehra ashu-mehra changed the title WIP Specify heap limits as percentage of total memory Specify heap limits as percentage of total memory Apr 24, 2018
@ashu-mehra
Copy link
Contributor Author

I have removed WIP from the subject line.

adjustXmxXmsUsingRAMPercent(MM_GCExtensions *extensions, IDATA *memoryParameters)
{
OMRPORT_ACCESS_FROM_OMRVM(extensions->getOmrVM());
uint64_t usableMemory = omrsysinfo_get_addressable_physical_memory();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is called already in MM_GCExtensions::computeDefaultMaxHeap. In my opinion you should integrate handling of maxRAMPercent and initialRAMPercent in that code. Please not modify memoryParameters[opt_Xms] and memoryParameters[opt_Xmx]. Let them keep original command line option values if any.

Copy link
Contributor Author

@ashu-mehra ashu-mehra Apr 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion you should integrate handling of maxRAMPercent and initialRAMPercent in that code.

But computeDefaultMaxHeap() is called even before we parse gc options in gcParseCommandLineAndInitializeWithValues().

Please not modify memoryParameters[opt_Xms] and memoryParameters[opt_Xmx].

Reason for modifying memoryParameters[opt_Xms] is the code in gcInitializeCalculatedValues() which sets initialMemorySize to default value if memoryParameters[opt_Xms] is not set.
So If I set initialMemorySize using initialRAMPercentage but don't update memoryParameters[opt_Xms], it will get overwritten to default value in gcInitializeCalculatedValues().

Copy link
Contributor

@dmitripivkine dmitripivkine Apr 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I see. What if we call omrsysinfo_get_addressable_physical_memory() once in MM_GCExtensionsBase before computeDefaultMaxHeap() and store it there. So there would be no need to call it again. Use stored value in MM_GCExtensionsBase::computeDefaultMaxHeap() and MM_GCExtensions::computeDefaultMaxHeap() implementations as well as here.
Modification of memoryParameters for opt_Xms and opt_Xmx is not my preferable way (it is a hack). However considering complicate messy logic in mminit.c related with memory parameters adjustments (needs to be cleaned up obviously but not in this PR) I would except this. Do we need to create adjustXmxXmsUsingRAMPercent() function? I would just add these two "if" statements directly instead (as far as there is no other consumers for this logic).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, we should store omrsysinfo_get_addressable_physical_memory() in a MM_GCExtensionsBase.

memoryParameters[opt_maxRAMPercent] = index;
if (memoryParameters[opt_maxRAMPercent] != -1) {
if (extensions->maxRAMPercent > 100) {
result = OPTION_OVERFLOW;
Copy link
Contributor

@dmitripivkine dmitripivkine Apr 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we create something like J9NLS_GC_OPTIONS_DOUBLE_OUT_OF_RANGE (using existing J9NLS_GC_OPTIONS_INTEGER_OUT_OF_RANGE as example)? It would be more informative


*result = strtod(*scan_start, &endPtr);
if (ERANGE == errno) {
if (0.0 == *result) {
Copy link
Contributor

@dmitripivkine dmitripivkine May 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can not do it according spec: http://www.cplusplus.com/reference/cstdlib/strtod/
in case of ERANGE if return is not equal +/- HUGE_VAL (not overflow) this is underflow. The output value in this case is "value whose magnitude is no greater than the smallest normalized positive number" (not necessarily 0.0). If you want to handle it as zero *result should be set 0.0 before return with rc 0.

Copy link
Contributor Author

@ashu-mehra ashu-mehra May 10, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per man page of strtod:
If the correct value would cause overflow, plus or minus HUGE_VAL (HUGE_VALF, HUGE_VALL) is returned (according to the sign of the value), and ERANGE is stored in errno. If the correct value would cause underflow, zero is returned and ERANGE is stored in errno.
Based on that I consider it as underflow if *return is 0.0.

Copy link
Contributor

@dmitripivkine dmitripivkine May 10, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From: http://pubs.opengroup.org/onlinepubs/9699919799/functions/strtod.html
The Open Group Base Specifications Issue 7, 2018 edition
IEEE Std 1003.1-2017 (Revision of IEEE Std 1003.1-2008)

"If the correct value would cause an underflow, a value whose magnitude is no greater than the smallest normalized positive number in the return type shall be returned and errno set to [ERANGE]."

if ((-1 == memoryParameterTable[opt_Xms]) && (-1 != memoryParameterTable[opt_initialRAMPercent])) {
extensions->initialMemorySize = (uintptr_t)(((double)extensions->usablePhysicalMemory / 100.0) * extensions->initialRAMPercent);
/* Update memory parameter table to appear that -Xms was specified */
memoryParameterTable[opt_Xms] = memoryParameterTable[opt_initialRAMPercent];
Copy link
Contributor

@dmitripivkine dmitripivkine May 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means that in case of error related to out-of-range case (<1m for example) output message would mention -Xms option. This fact should be documented at least. Ideally error message should refer to real option whatever it is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about updating the message to say " -Xmx (as set by -XX:InitialRAMPercentage)" when -XX:MaxRAMPercentage is being used to set max heap size. Some examples of updated messages:

  • Option too large: -Xmx (as set by -XX:InitialRAMPercentage) is too large
  • -Xmx (as set by -XX:InitialRAMPercentage) too small, must be at least 1 Mbytes

I can add a function that returns "-Xmx" or "-Xmx (as set by -XX:InitialRAMPercentage) " based on the option being used:

const char *
displayXmsOrInitialRAMPercentage(IDATA* memoryParameters)
{
        if ((-1 == memoryParameters[opt_initialRAMPercent])
                && (memoryParameters[opt_Xms] == memoryParameters[opt_initialRAMPercent])
        ) {
                return "-Xms (as set by -XX:InitialRAMPercentage)";
        } else {
                return "-Xms";
        }
}

and we can use this function wherever we are currently displaying "-Xmx".
Does that look fine?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, something like this

if ((-1 == memoryParameterTable[opt_Xmx]) && (-1 != memoryParameterTable[opt_maxRAMPercent])) {
extensions->memoryMax = (uintptr_t)(((double)extensions->usablePhysicalMemory / 100.0) * extensions->maxRAMPercent);
/* Update memory parameter table to appear that -Xmx was specified */
memoryParameterTable[opt_Xmx] = memoryParameterTable[opt_maxRAMPercent];
Copy link
Contributor

@dmitripivkine dmitripivkine May 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means that in case of error related to out-of-range case output message would mention -Xmx option. This fact should be documented at least. Ideally error message should refer to real option whatever it is.

@ashu-mehra ashu-mehra force-pushed the add_gc_options_v3 branch 2 times, most recently from 5f992ca to 0ea5491 Compare May 10, 2018 17:52
@ashu-mehra
Copy link
Contributor Author

@dmitripivkine I updated the code as suggested. Can you please review it.

option = MAPPING_MAPNAME(j9vm_args, element);
}

return j9vm_args->actualVMArgs->options[element].optionString + strlen(option);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is check for (NULL == option) missed there? I believe strlen(NULL) will crash, is not it?
getOptionValue() can return NULL in this case and caller might check it to return OPTION_ERROR

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added check for (NULL == option).
The current users of getOptionValue() don't need to check for NULL return value as we already ensure that optionName is not NULL.

if (*valuesBuffer) {
scanStart = &(j9vm_args->actualVMArgs->options[element].optionString[ strlen(*valuesBuffer) ]);
} else {
return OPTION_ERROR;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reviewers: this "else" is not necessary because of check lines 363-364, it is removed in new code

Copy link
Contributor

@dmitripivkine dmitripivkine left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me

@dmitripivkine
Copy link
Contributor

@DanHeidinga Would you please do final review?

@dmitripivkine dmitripivkine removed the request for review from amicic May 14, 2018 18:34
@dmitripivkine
Copy link
Contributor

Also this feature should be documented.

@dmitripivkine
Copy link
Contributor

Note: Currently Java 8 does not take the amount of RAM to consideration to calculate -Xmx default. It is applicable for Java 9 and higher. The -XX:MaxRAMPercentage option however is applicable for Java 8 so it introduces a way to set -Xmx as a percentage of machine's RAM.

if (ERANGE == errno) {
if ((HUGE_VAL == *result) || (-HUGE_VAL == *result)) {
/* overflow */
return 2;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this return OPTION_OVERFLOW instead of a magic number? Also, please add this to the function comment.

}
} else if ((0.0 == *result) && (endPtr == *scan_start)) {
/* no conversion */
return 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this return OPTION_MALFORMED? Also worth documenting in the function comment.

@@ -629,6 +639,23 @@ optionValueOperations(J9PortLibrary *portLibrary, J9VMInitArgs* j9vm_args, IDATA
return OPTION_OK;
}

static char *
getOptionValue(J9VMInitArgs* j9vm_args, IDATA element, const char *optionName)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getOptionValue -> getStartOfOption? startOfOptionValue? I'm not a fan of this function name but the alternatives I've suggested aren't great either.

Copy link
Contributor Author

@ashu-mehra ashu-mehra May 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due to lack of a better name, lets go with getStartOfOptionValue.

option = MAPPING_MAPNAME(j9vm_args, element);
}

if (NULL != option) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be a trace assert that option is not null? A null optionName with no mapping is a programming error.

Add options for specifying heap limits in terms of percentage of
total memory available to the JVM.
Following options are added:
1. -XX:MaxRAMPercentage=N where 0 <= N <= 100.0
This option specifies maximum heap size. If -Xmx is specified, this
option is ignored.
2. -XX:InitialRAMPercentage=N where 0 <= N <= 100.0
This option specifies initial heap size. If -Xms is specified, this
option is ignored.

Closes: eclipse-openj9#1428

Signed-off-by: Ashutosh Mehra <asmehra1@in.ibm.com>
@ashu-mehra
Copy link
Contributor Author

@DanHeidinga Updated the changes as suggested.

Copy link
Member

@DanHeidinga DanHeidinga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@DanHeidinga
Copy link
Member

Jenkins test sanity plinux jdk8

@DanHeidinga
Copy link
Member

Jenkins test sanity xlinux jdk8

@DanHeidinga
Copy link
Member

Looks like the CI server is having issues. Once we can build this it can be merged

@DanHeidinga
Copy link
Member

jenkins test sanity xlinux jdk8

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants