--- old/src/share/vm/gc/g1/g1_globals.hpp 2015-08-20 09:29:47.569088740 -0700 +++ new/src/share/vm/gc/g1/g1_globals.hpp 2015-08-20 09:29:47.465088743 -0700 @@ -26,6 +26,7 @@ #define SHARE_VM_GC_G1_G1_GLOBALS_HPP #include "runtime/globals.hpp" +#include // for DBL_MAX // // Defines all globals flags used by the garbage-first compiler. // @@ -61,6 +62,7 @@ "update buffer processing info " \ "(0 means do not periodically generate this info); " \ "it also requires -XX:+G1SummarizeRSetStats") \ + range(0, max_intx) \ \ diagnostic(bool, G1TraceConcRefinement, false, \ "Trace G1 concurrent refinement") \ @@ -71,7 +73,7 @@ product(double, G1ConcMarkStepDurationMillis, 10.0, \ "Target duration of individual concurrent marking steps " \ "in milliseconds.") \ - range(1.0, (double)max_uintx) \ + range(1.0, DBL_MAX) \ \ product(intx, G1RefProcDrainInterval, 10, \ "The number of discovered reference objects to process before " \ @@ -84,9 +86,11 @@ \ product(size_t, G1SATBBufferSize, 1*K, \ "Number of entries in an SATB log buffer.") \ + range(1, max_uintx) \ \ develop(intx, G1SATBProcessCompletedThreshold, 20, \ "Number of completed buffers that triggers log processing.") \ + range(0, max_jint) \ \ product(uintx, G1SATBBufferEnqueueingThresholdPercent, 60, \ "Before enqueueing them, each mutator thread tries to do some " \ @@ -109,26 +113,31 @@ \ product(size_t, G1UpdateBufferSize, 256, \ "Size of an update buffer") \ + range(1, 1*G) \ \ product(intx, G1ConcRefinementYellowZone, 0, \ "Number of enqueued update buffers that will " \ "trigger concurrent processing. Will be selected ergonomically " \ "by default.") \ + range(0, max_intx) \ \ product(intx, G1ConcRefinementRedZone, 0, \ "Maximum number of enqueued update buffers before mutator " \ "threads start processing new ones instead of enqueueing them. " \ "Will be selected ergonomically by default. Zero will disable " \ "concurrent processing.") \ + range(0, max_intx) \ \ product(intx, G1ConcRefinementGreenZone, 0, \ "The number of update buffers that are left in the queue by the " \ "concurrent processing threads. Will be selected ergonomically " \ "by default.") \ + range(0, max_intx) \ \ product(intx, G1ConcRefinementServiceIntervalMillis, 300, \ "The last concurrent refinement thread wakes up every " \ "specified number of milliseconds to do miscellaneous work.") \ + range(0, max_intx) \ \ product(intx, G1ConcRefinementThresholdStep, 0, \ "Each time the rset update queue increases by this amount " \ @@ -138,6 +147,7 @@ product(intx, G1RSetUpdatingPauseTimePercent, 10, \ "A target percentage of time that is allowed to be spend on " \ "process RS update buffers during the collection pause.") \ + range(0, 100) \ \ product(bool, G1UseAdaptiveConcRefinement, true, \ "Select green, yellow and red zones adaptively to meet the " \ @@ -153,18 +163,24 @@ \ develop(intx, G1RSetRegionEntriesBase, 256, \ "Max number of regions in a fine-grain table per MB.") \ + range(1, max_jint) \ \ product(intx, G1RSetRegionEntries, 0, \ "Max number of regions for which we keep bitmaps." \ "Will be set ergonomically by default") \ + range(0, max_jint) \ + constraint(G1RSetRegionEntriesConstraintFunc,AfterErgo) \ \ develop(intx, G1RSetSparseRegionEntriesBase, 4, \ "Max number of entries per region in a sparse table " \ "per MB.") \ + range(1, max_jint) \ \ product(intx, G1RSetSparseRegionEntries, 0, \ "Max number of entries per region in a sparse table." \ "Will be set ergonomically by default.") \ + range(0, max_jint) \ + constraint(G1RSetSparseRegionEntriesConstraintFunc,AfterErgo) \ \ develop(bool, G1RecordHRRSOops, false, \ "When true, record recent calls to rem set operations.") \ @@ -175,6 +191,7 @@ develop(intx, G1MaxVerifyFailures, -1, \ "The maximum number of verification failures to print. " \ "-1 means print all.") \ + range(-1, max_jint) \ \ develop(bool, G1ScrubRemSets, true, \ "When true, do RS scrubbing after cleanup.") \ @@ -188,11 +205,13 @@ develop(intx, G1YoungSurvRateNumRegionsSummary, 0, \ "the number of regions for which we'll print a surv rate " \ "summary.") \ + range(0, max_intx) \ + constraint(G1YoungSurvRateNumRegionsSummaryConstraintFunc,AfterErgo)\ \ product(uintx, G1ReservePercent, 10, \ "It determines the minimum reserve we should have in the heap " \ "to minimize the probability of promotion failure.") \ - range(0, 100) \ + range(0, 50) \ \ diagnostic(bool, G1PrintHeapRegions, false, \ "If set G1 will print information on which regions are being " \ @@ -210,10 +229,13 @@ \ product(size_t, G1HeapRegionSize, 0, \ "Size of the G1 regions.") \ + range(0, 32*M) \ + constraint(G1HeapRegionSizeConstraintFunc,AfterMemoryInit) \ \ product(uintx, G1ConcRefinementThreads, 0, \ "If non-0 is the number of parallel rem set update threads, " \ "otherwise the value is determined ergonomically.") \ + range(0, max_jint-1) \ \ develop(bool, G1VerifyCTCleanup, false, \ "Verify card table cleanup.") \ @@ -221,6 +243,7 @@ product(size_t, G1RSetScanBlockSize, 64, \ "Size of a work unit of cards claimed by a worker thread" \ "during RSet scanning.") \ + range(1, max_uintx) \ \ develop(uintx, G1SecondaryFreeListAppendLength, 5, \ "The number of regions we will add to the secondary free list " \ @@ -239,6 +262,7 @@ "The number of dummy regions G1 will allocate at the end of " \ "each evacuation pause in order to artificially fill up the " \ "heap and stress the marking implementation.") \ + range(0, 1000) \ \ develop(bool, G1ExitOnExpansionFailure, false, \ "Raise a fatal VM exit out of memory failure in the event " \ @@ -257,6 +281,7 @@ experimental(uintx, G1NewSizePercent, 5, \ "Percentage (0-100) of the heap size to use as default " \ "minimum young gen size.") \ + range(0, 100) \ constraint(G1NewSizePercentConstraintFunc,AfterErgo) \ \ experimental(uintx, G1MixedGCLiveThresholdPercent, 85, \ --- old/src/share/vm/runtime/arguments.cpp 2015-08-20 09:29:48.201088718 -0700 +++ new/src/share/vm/runtime/arguments.cpp 2015-08-20 09:29:48.089088722 -0700 @@ -581,8 +581,10 @@ } static bool set_fp_numeric_flag(char* name, char* value, Flag::Flags origin) { - double v; - if (sscanf(value, "%lf", &v) != 1) { + char* end; + errno = 0; + double v = strtod(value, &end); + if (errno != 0 || *end != 0) { return false; } @@ -716,9 +718,9 @@ return set_string_flag(name, value, origin); } -#define SIGNED_FP_NUMBER_RANGE "[-0123456789.]" +#define SIGNED_FP_NUMBER_RANGE "[-0123456789.eE+]" #define SIGNED_NUMBER_RANGE "[-0123456789]" -#define NUMBER_RANGE "[0123456789]" +#define NUMBER_RANGE "[0123456789eE+-]" char value[BUFLEN + 1]; char value2[BUFLEN + 1]; if (sscanf(arg, "%" XSTR(BUFLEN) NAME_RANGE "=" "%" XSTR(BUFLEN) SIGNED_NUMBER_RANGE "." "%" XSTR(BUFLEN) NUMBER_RANGE "%c", name, value, value2, &dummy) == 3) { --- old/src/share/vm/runtime/commandLineFlagConstraintList.cpp 2015-08-20 09:29:48.877088694 -0700 +++ new/src/share/vm/runtime/commandLineFlagConstraintList.cpp 2015-08-20 09:29:48.773088698 -0700 @@ -274,7 +274,7 @@ EMIT_CONSTRAINT_CHECK)); #endif // COMPILER2 -#ifndef INCLUDE_ALL_GCS +#if INCLUDE_ALL_GCS emit_constraint_no(NULL G1_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG, EMIT_CONSTRAINT_PD_DEVELOPER_FLAG, EMIT_CONSTRAINT_PRODUCT_FLAG, @@ -305,10 +305,7 @@ // Check constraints for specific constraint type. bool CommandLineFlagConstraintList::check_constraints(CommandLineFlagConstraint::ConstraintType type) { - // Skip if we already checked. - if (type < _validating_type) { - return true; - } + guarantee(type > _validating_type, "Constraint check is out of order."); _validating_type = type; bool status = true; --- old/src/share/vm/runtime/commandLineFlagConstraintList.hpp 2015-08-20 09:29:49.493088673 -0700 +++ new/src/share/vm/runtime/commandLineFlagConstraintList.hpp 2015-08-20 09:29:49.389088676 -0700 @@ -54,9 +54,9 @@ enum ConstraintType { // Will be validated during argument processing (Arguments::parse_argument). AtParse = 0, - // Will be validated by CommandLineFlags::check_constraints_of_after_ergo(). - AfterErgo = 1, - // Will be validated by CommandLineFlags::check_constraints_of_after_memory_init(). + // Will be validated by CommandLineFlagConstraintList::check_constraints(AfterErgo). + AfterErgo = 1, + // Will be validated by CommandLineFlagConstraintList::check_constraints(AfterMemoryInit). AfterMemoryInit = 2 }; --- old/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp 2015-08-20 09:29:50.153088650 -0700 +++ new/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp 2015-08-20 09:29:50.049088653 -0700 @@ -23,16 +23,19 @@ */ #include "precompiled.hpp" +#include "gc/shared/collectedHeap.hpp" +#include "gc/shared/collectorPolicy.hpp" +#include "gc/shared/threadLocalAllocBuffer.hpp" #include "runtime/arguments.hpp" #include "runtime/commandLineFlagConstraintsGC.hpp" #include "runtime/commandLineFlagRangeList.hpp" #include "runtime/globals.hpp" +#include "runtime/globals_extension.hpp" #include "utilities/defaultStream.hpp" #if INCLUDE_ALL_GCS #include "gc/g1/g1_globals.hpp" #include "gc/g1/heapRegionBounds.inline.hpp" -#include "gc/parallel/parallelScavengeHeap.hpp" #include "gc/shared/plab.hpp" #endif // INCLUDE_ALL_GCS #ifdef COMPILER1 @@ -42,6 +45,63 @@ #include "opto/c2_globals.hpp" #endif // COMPILER2 +#if INCLUDE_ALL_GCS +static Flag::Error ParallelGCThreadsAndCMSWorkQueueDrainThreshold(uint threads, uintx threshold, bool verbose) { + // CMSWorkQueueDrainThreshold is verified to be less than max_juint + if (UseConcMarkSweepGC && (threads > (uint)(max_jint / (uint)threshold))) { + CommandLineError::print(verbose, + "ParallelGCThreads (" UINT32_FORMAT ") or CMSWorkQueueDrainThreshold (" + UINTX_FORMAT ") is too large\n", + threads, threshold); + return Flag::VIOLATES_CONSTRAINT; + } + return Flag::SUCCESS; +} +#endif + +// As ParallelGCThreads differs among GC modes, we need constraint function. +Flag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose) { + Flag::Error status = Flag::SUCCESS; + +#if INCLUDE_ALL_GCS + // Parallel GC passes ParallelGCThreads when creating GrowableArray as 'int' type parameter. + // So can't exceed with "max_jint" + if (UseParallelGC && (value > (uint)max_jint)) { + CommandLineError::print(verbose, + "ParallelGCThreads (" UINT32_FORMAT ") must be less than or equal to " + UINT32_FORMAT " for Parallel GC\n", + value, max_jint); + return Flag::VIOLATES_CONSTRAINT; + } + // To avoid overflow at ParScanClosure::do_oop_work. + if (UseConcMarkSweepGC && (value > max_jint / 10)) { + CommandLineError::print(verbose, + "ParallelGCThreads (" UINT32_FORMAT ") must be less than or equal to " + UINT32_FORMAT " for CMS GC\n", + value, max_jint / 10); + return Flag::VIOLATES_CONSTRAINT; + } + status = ParallelGCThreadsAndCMSWorkQueueDrainThreshold(value, CMSWorkQueueDrainThreshold, verbose); +#endif + return status; +} + +// As ConcGCThreads should be smaller than ParallelGCThreads, +// we need constraint function. +Flag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose) { +#if INCLUDE_ALL_GCS + // CMS and G1 GCs use ConcGCThreads. + if ((UseConcMarkSweepGC || UseG1GC) && (value > ParallelGCThreads)) { + CommandLineError::print(verbose, + "ConcGCThreads (" UINT32_FORMAT ") must be less than or equal to " + "ParallelGCThreads (" UINT32_FORMAT ")\n", + value, ParallelGCThreads); + return Flag::VIOLATES_CONSTRAINT; + } +#endif + return Flag::SUCCESS; +} + static Flag::Error MinPLABSizeBounds(const char* name, size_t value, bool verbose) { #if INCLUDE_ALL_GCS if ((UseConcMarkSweepGC || UseG1GC) && (value < PLAB::min_size())) { @@ -60,7 +120,7 @@ if ((UseConcMarkSweepGC || UseG1GC) && (value > PLAB::max_size())) { CommandLineError::print(verbose, "%s (" SIZE_FORMAT ") must be " - "less than ergonomic PLAB maximum size (" SIZE_FORMAT ")\n", + "less than or equal to ergonomic PLAB maximum size (" SIZE_FORMAT ")\n", name, value, PLAB::min_size()); return Flag::VIOLATES_CONSTRAINT; } @@ -69,16 +129,40 @@ } static Flag::Error MinMaxPLABSizeBounds(const char* name, size_t value, bool verbose) { - if (MinPLABSizeBounds(name, value, verbose) == Flag::SUCCESS) { + Flag::Error status = MinPLABSizeBounds(name, value, verbose); + + if (status == Flag::SUCCESS) { return MaxPLABSizeBounds(name, value, verbose); } - return Flag::VIOLATES_CONSTRAINT; + return status; } Flag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose) { return MinMaxPLABSizeBounds("YoungPLABSize", value, verbose); } +Flag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose) { + Flag::Error status = Flag::SUCCESS; + +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC) { + if (value == 0) { + CommandLineError::print(verbose, + "OldPLABSize (" SIZE_FORMAT ") must be greater than 0", + value); + return Flag::VIOLATES_CONSTRAINT; + } + // For CMS, OldPLABSize is the number of free blocks of a given size that are used when + // replenishing the local per-worker free list caches. + // For more details, please refer to Arguments::set_cms_and_parnew_gc_flags(). + status = MaxPLABSizeBounds("OldPLABSize", value, verbose); + } else { + status = MinMaxPLABSizeBounds("OldPLABSize", value, verbose); + } +#endif + return status; +} + Flag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose) { if (value > MaxHeapFreeRatio) { CommandLineError::print(verbose, @@ -103,6 +187,22 @@ } } +static Flag::Error CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(size_t maxHeap, intx softRef, bool verbose) { + if ((softRef > 0) && (maxHeap / M > max_uintx / softRef)) { + CommandLineError::print(verbose, + "MaxHeapSize (" SIZE_FORMAT ") or SoftRefLRUPolicyMSPerMB " + "(" INTX_FORMAT ") is too large\n", + maxHeap, softRef); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose) { + return CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(MaxHeapSize, value, verbose); +} + Flag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) { if (value > MaxMetaspaceFreeRatio) { CommandLineError::print(verbose, @@ -127,45 +227,111 @@ } } -// GC workaround for "-XX:+UseConcMarkSweepGC" -// which sets InitialTenuringThreshold to 7 but leaves MaxTenuringThreshold remaining at 6 -// and therefore would invalidate the constraint -#define UseConcMarkSweepGCWorkaroundIfNeeded(initial, max) { \ - if ((initial == 7) && (max == 6)) { \ - return Flag::SUCCESS; \ - } \ +Flag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose) { +#if INCLUDE_ALL_GCS + // InitialTenuringThreshold is only used for ParallelGC. + if (UseParallelGC && (value > MaxTenuringThreshold)) { + CommandLineError::print(verbose, + "InitialTenuringThreshold (" UINTX_FORMAT ") must be " + "less than or equal to MaxTenuringThreshold (" UINTX_FORMAT ")\n", + value, MaxTenuringThreshold); + return Flag::VIOLATES_CONSTRAINT; + } +#endif + return Flag::SUCCESS; } -Flag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose) { - UseConcMarkSweepGCWorkaroundIfNeeded(value, MaxTenuringThreshold); +Flag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose) { +#if INCLUDE_ALL_GCS + // As only ParallelGC uses InitialTenuringThreshold, + // we don't need to compare InitialTenuringThreshold with MaxTenuringThreshold. + if (UseParallelGC && (value < InitialTenuringThreshold)) { + CommandLineError::print(verbose, + "MaxTenuringThreshold (" UINTX_FORMAT ") must be " + "greater than or equal to InitialTenuringThreshold (" UINTX_FORMAT ")\n", + value, InitialTenuringThreshold); + return Flag::VIOLATES_CONSTRAINT; + } +#endif + + // MaxTenuringThreshold=0 means NeverTenure=false && AlwaysTenure=true + if ((value == 0) && (NeverTenure || !AlwaysTenure)) { + CommandLineError::print(verbose, + "MaxTenuringThreshold (0) should match to NeverTenure=false " + "&& AlwaysTenure=true. But we have NeverTenure=%s " + "AlwaysTenure=%s\n", + NeverTenure ? "true" : "false", + AlwaysTenure ? "true" : "false"); + return Flag::VIOLATES_CONSTRAINT; + } + return Flag::SUCCESS; +} + +#if INCLUDE_ALL_GCS +Flag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; - if (value > MaxTenuringThreshold) { + // Default value of G1RSetRegionEntries=0 means will be set ergonomically. + // Minimum value is 1. + if (FLAG_IS_CMDLINE(G1RSetRegionEntries) && (value < 1)) { CommandLineError::print(verbose, - "InitialTenuringThreshold (" UINTX_FORMAT ") must be " - "less than or equal to MaxTenuringThreshold (" UINTX_FORMAT ")\n", - value, MaxTenuringThreshold); + "G1RSetRegionEntries (" INTX_FORMAT ") must be " + "greater than or equal to 1\n", + value); return Flag::VIOLATES_CONSTRAINT; } else { return Flag::SUCCESS; } } -Flag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose) { - UseConcMarkSweepGCWorkaroundIfNeeded(InitialTenuringThreshold, value); +Flag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; - if (value < InitialTenuringThreshold) { + // Default value of G1RSetSparseRegionEntries=0 means will be set ergonomically. + // Minimum value is 1. + if (FLAG_IS_CMDLINE(G1RSetSparseRegionEntries) && (value < 1)) { CommandLineError::print(verbose, - "MaxTenuringThreshold (" UINTX_FORMAT ") must be " - "greater than or equal to InitialTenuringThreshold (" UINTX_FORMAT ")\n", - value, InitialTenuringThreshold); + "G1RSetSparseRegionEntries (" INTX_FORMAT ") must be " + "greater than or equal to 1\n", + value); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error G1YoungSurvRateNumRegionsSummaryConstraintFunc(intx value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; + + if (value > (intx)HeapRegionBounds::target_number()) { + CommandLineError::print(verbose, + "G1YoungSurvRateNumRegionsSummary (" INTX_FORMAT ") must be less than " + "or equal to region amount (" SIZE_FORMAT ")\n", + value, HeapRegionBounds::target_number()); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; + + // Default value of G1HeapRegionSize=0 means will be set ergonomically. + if (FLAG_IS_CMDLINE(G1HeapRegionSize) && (value < HeapRegionBounds::min_size())) { + CommandLineError::print(verbose, + "G1HeapRegionSize (" SIZE_FORMAT ") must be greater than or " + "equal to ergonomic heap region minimum size\n", + value); return Flag::VIOLATES_CONSTRAINT; } else { return Flag::SUCCESS; } } -#if INCLUDE_ALL_GCS Flag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; + if (value > G1MaxNewSizePercent) { CommandLineError::print(verbose, "G1NewSizePercent (" UINTX_FORMAT ") must be " @@ -178,6 +344,8 @@ } Flag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; + if (value < G1NewSizePercent) { CommandLineError::print(verbose, "G1MaxNewSizePercent (" UINTX_FORMAT ") must be " @@ -188,39 +356,257 @@ return Flag::SUCCESS; } } - #endif // INCLUDE_ALL_GCS -Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose) { - if (value > CMSOldPLABMax) { +Flag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose) { +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC && (value > max_jint / ParallelGCThreads)) { CommandLineError::print(verbose, - "CMSOldPLABMin (" SIZE_FORMAT ") must be " - "less than or equal to CMSOldPLABMax (" SIZE_FORMAT ")\n", - value, CMSOldPLABMax); + "ParGCStridesPerThread (" UINTX_FORMAT ") must be " + "less than or equal to ergonomic maximum (" INT32_FORMAT ")\n", + value, max_jint / ParallelGCThreads); return Flag::VIOLATES_CONSTRAINT; - } else { - return Flag::SUCCESS; } +#endif + return Flag::SUCCESS; +} + +Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose) { + Flag::Error status = Flag::SUCCESS; + +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC) { + if (value > CMSOldPLABMax) { + CommandLineError::print(verbose, + "CMSOldPLABMin (" SIZE_FORMAT ") must be " + "less than or equal to CMSOldPLABMax (" SIZE_FORMAT ")\n", + value, CMSOldPLABMax); + return Flag::VIOLATES_CONSTRAINT; + } + status = MaxPLABSizeBounds("CMSOldPLABMin", value, verbose); + } +#endif + return status; +} + +Flag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose) { + Flag::Error status = Flag::SUCCESS; + +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC) { + status = MaxPLABSizeBounds("CMSOldPLABMax", value, verbose); + } +#endif + return status; } Flag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose) { - if (value <= CMSPrecleanNumerator) { +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC && (value <= CMSPrecleanNumerator)) { CommandLineError::print(verbose, "CMSPrecleanDenominator (" UINTX_FORMAT ") must be " "strickly greater than CMSPrecleanNumerator (" UINTX_FORMAT ")\n", value, CMSPrecleanNumerator); return Flag::VIOLATES_CONSTRAINT; - } else { - return Flag::SUCCESS; } +#endif + return Flag::SUCCESS; } Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose) { - if (value > (CMSPrecleanDenominator - 1)) { +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC && (value >= CMSPrecleanDenominator)) { CommandLineError::print(verbose, "CMSPrecleanNumerator (" UINTX_FORMAT ") must be " - "less than or equal to CMSPrecleanDenominator - 1 (" UINTX_FORMAT ")\n", - value, CMSPrecleanDenominator - 1); + "less than CMSPrecleanDenominator (" UINTX_FORMAT ")\n", + value, CMSPrecleanDenominator); + return Flag::VIOLATES_CONSTRAINT; + } +#endif + return Flag::SUCCESS; +} + +Flag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose) { +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC) { + return ParallelGCThreadsAndCMSWorkQueueDrainThreshold(ParallelGCThreads, value, verbose); + } +#endif + return Flag::SUCCESS; +} + +Flag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose) { +#if INCLUDE_ALL_GCS + if (UseG1GC && FLAG_IS_CMDLINE(MaxGCPauseMillis) && (value >= GCPauseIntervalMillis)) { + CommandLineError::print(verbose, + "MaxGCPauseMillis (" UINTX_FORMAT ") must be less than " + "GCPauseIntervalMillis (" UINTX_FORMAT ")\n", + value, GCPauseIntervalMillis); + return Flag::VIOLATES_CONSTRAINT; + } +#endif + + return Flag::SUCCESS; +} + +Flag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose) { +#if INCLUDE_ALL_GCS + if (UseG1GC) { + if (FLAG_IS_CMDLINE(GCPauseIntervalMillis)) { + if (value < 1) { + CommandLineError::print(verbose, + "GCPauseIntervalMillis (" UINTX_FORMAT ") must be greater than " + "or equal to 1\n", + value); + return Flag::VIOLATES_CONSTRAINT; + } + if (value <= MaxGCPauseMillis) { + CommandLineError::print(verbose, + "GCPauseIntervalMillis (" UINTX_FORMAT ") must be greater than " + "MaxGCPauseMillis (" UINTX_FORMAT ")\n", + value, MaxGCPauseMillis); + return Flag::VIOLATES_CONSTRAINT; + } + } + } +#endif + return Flag::SUCCESS; +} + +Flag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose) { + size_t aligned_max = (size_t)align_size_down(max_uintx/2, Metaspace::reserve_alignment_words()); + if (value > aligned_max) { + CommandLineError::print(verbose, + "InitialBootClassLoaderMetaspaceSize (" SIZE_FORMAT ") must be less than or equal to " + "aligned maximum value (" SIZE_FORMAT ")\n", + value, aligned_max); + return Flag::VIOLATES_CONSTRAINT; + } + return Flag::SUCCESS; +} + +static Flag::Error MaxSizeForHeapAlignment(const char* name, size_t value, bool verbose) { + // For G1 GC, we don't know until G1CollectorPolicy is created. + size_t heap_alignment; + +#if INCLUDE_ALL_GCS + if (UseG1GC) { + heap_alignment = HeapRegionBounds::max_size(); + } else +#endif + { + heap_alignment = CollectorPolicy::compute_heap_alignment(); + } + + // Not to overflow 'align_size_up(value, _heap_alignment) used from CollectorPolicy::initialize_flags()'. + size_t aligned_max = ((max_uintx - heap_alignment) & ~(heap_alignment-1)); + if (value > aligned_max) { + CommandLineError::print(verbose, + "%s (" SIZE_FORMAT ") must be less than or equal to " + "aligned maximum value (" SIZE_FORMAT ")\n", + name, value, aligned_max); + return Flag::VIOLATES_CONSTRAINT; + } + return Flag::SUCCESS; +} + +Flag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose) { + return MaxSizeForHeapAlignment("InitialHeapSize", value, verbose); +} + +Flag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose) { + Flag::Error status = MaxSizeForHeapAlignment("MaxHeapSize", value, verbose); + + if (status == Flag::SUCCESS) { + status = CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(value, SoftRefLRUPolicyMSPerMB, verbose); + } + return status; +} + +Flag::Error NewSizeConstraintFunc(size_t value, bool verbose) { +#ifdef _LP64 +#if INCLUDE_ALL_GCS + // Overflow would happen for uint type variable of YoungGenSizer::_min_desired_young_length + // when the value to be assigned exceeds uint range. + // i.e. result of '(uint)(NewSize / region size(1~32MB))' + // So maximum of NewSize should be 'max_juint * 1M' + if (UseG1GC && value > max_juint * 1 * M) { + CommandLineError::print(verbose, + "NewSize (" SIZE_FORMAT ") must be less than ergonomic maximum value\n", + value); + return Flag::VIOLATES_CONSTRAINT; + } +#endif // INCLUDE_ALL_GCS +#endif // _LP64 + return Flag::SUCCESS; +} + +Flag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose) { + // At least, alignment reserve area is needed. + if (value < ThreadLocalAllocBuffer::alignment_reserve_in_bytes()) { + CommandLineError::print(verbose, + "MinTLABSize (" SIZE_FORMAT ") must be greater than or equal to " + "reserved area in TLAB (" SIZE_FORMAT ")\n", + value, ThreadLocalAllocBuffer::alignment_reserve_in_bytes()); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error TLABSizeConstraintFunc(size_t value, bool verbose) { + // Skip for default value of zero which means set ergonomically. + if (FLAG_IS_CMDLINE(TLABSize)) { + if (value < MinTLABSize) { + CommandLineError::print(verbose, + "TLABSize (" SIZE_FORMAT ") must be greater than or equal to " + "MinTLABSize (" SIZE_FORMAT ")\n", + value, MinTLABSize); + return Flag::VIOLATES_CONSTRAINT; + } + if (value > ThreadLocalAllocBuffer::max_size() * HeapWordSize) { + CommandLineError::print(verbose, + "TLABSize (" SIZE_FORMAT ") must be less than or equal to " + "ergonomic TLAB maximum size (" SIZE_FORMAT ")\n", + value, ThreadLocalAllocBuffer::max_size() * HeapWordSize); + return Flag::VIOLATES_CONSTRAINT; + } + } + return Flag::SUCCESS; +} + +Flag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose) { + if (FLAG_IS_CMDLINE(SurvivorRatio) && + (value > MaxHeapSize / Universe::heap()->collector_policy()->space_alignment())) { + CommandLineError::print(verbose, + "SurvivorRatio (" UINTX_FORMAT ") must be less than or equal to " + "ergonomic SurvivorRatio maximum (" SIZE_FORMAT ")\n", + value, + MaxHeapSize / Universe::heap()->collector_policy()->space_alignment()); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose) { + if (value > MaxMetaspaceSize) { + CommandLineError::print(verbose, + "MetaspaceSize (" SIZE_FORMAT ") must be less than or equal to " + "MaxMetaspaceSize (" SIZE_FORMAT ")\n", + value, MaxMetaspaceSize); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose) { + if (value < MetaspaceSize) { + CommandLineError::print(verbose, + "MaxMetaspaceSize (" SIZE_FORMAT ") must be greater than or equal to " + "MetaspaceSize (" SIZE_FORMAT ")\n", + value, MaxMetaspaceSize); return Flag::VIOLATES_CONSTRAINT; } else { return Flag::SUCCESS; --- old/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp 2015-08-20 09:29:50.793088627 -0700 +++ new/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp 2015-08-20 09:29:50.689088631 -0700 @@ -34,27 +34,44 @@ * an appropriate error value. */ +Flag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose); +Flag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose); Flag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose); - +Flag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose); Flag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose); Flag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose); - +Flag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose); Flag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose); Flag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose); - Flag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose); Flag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose); #if INCLUDE_ALL_GCS +Flag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose); +Flag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose); +Flag::Error G1YoungSurvRateNumRegionsSummaryConstraintFunc(intx value, bool verbose); +Flag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose); Flag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose); Flag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose); #endif // INCLUDE_ALL_GCS +Flag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose); Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose); - +Flag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose); Flag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose); Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose); - +Flag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose); +Flag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose); +Flag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose); +Flag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose); +Flag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose); +Flag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose); +Flag::Error NewSizeConstraintFunc(size_t value, bool verbose); +Flag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose); +Flag::Error TLABSizeConstraintFunc(size_t value, bool verbose); +Flag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose); +Flag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose); +Flag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose); Flag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose); #endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSGC_HPP */ --- old/src/share/vm/runtime/globals.hpp 2015-08-20 09:29:51.469088604 -0700 +++ new/src/share/vm/runtime/globals.hpp 2015-08-20 09:29:51.321088609 -0700 @@ -26,6 +26,7 @@ #define SHARE_VM_RUNTIME_GLOBALS_HPP #include "utilities/debug.hpp" +#include // for DBL_MAX // use this for flags that are true per default in the tiered build // but false in non-tiered builds, and vice versa @@ -1551,6 +1552,7 @@ \ product(uint, ParallelGCThreads, 0, \ "Number of parallel threads parallel gc will use") \ + constraint(ParallelGCThreadsConstraintFunc,AfterErgo) \ \ diagnostic(bool, UseSemaphoreGCThreadsSynchronization, true, \ "Use semaphore synchronization for the GC Threads, " \ @@ -1582,14 +1584,7 @@ \ product(uint, ConcGCThreads, 0, \ "Number of threads concurrent gc will use") \ - \ - product(size_t, YoungPLABSize, 4096, \ - "Size of young gen promotion LAB's (in HeapWords)") \ - constraint(YoungPLABSizeConstraintFunc,AfterMemoryInit) \ - \ - product(size_t, OldPLABSize, 1024, \ - "Size of old gen promotion LAB's (in HeapWords), or Number \ - of blocks to attempt to claim when refilling CMS LAB's") \ + constraint(ConcGCThreadsConstraintFunc,AfterErgo) \ \ product(uintx, GCTaskTimeStampEntries, 200, \ "Number of time stamp entries per gc worker thread") \ @@ -1697,6 +1692,7 @@ "The number of strides per worker thread that we divide up the " \ "card table scanning work into") \ range(1, max_uintx) \ + constraint(ParGCStridesPerThreadConstraintFunc,AfterErgo) \ \ diagnostic(intx, ParGCCardsPerStrideChunk, 256, \ "The number of cards in each chunk of the parallel chunks used " \ @@ -1719,12 +1715,13 @@ "Maximum size of CMS gen promotion LAB caches per worker " \ "per block size") \ range(1, max_uintx) \ + constraint(CMSOldPLABMaxConstraintFunc,AfterMemoryInit) \ \ product(size_t, CMSOldPLABMin, 16, \ "Minimum size of CMS gen promotion LAB caches per worker " \ "per block size") \ range(1, max_uintx) \ - constraint(CMSOldPLABMinConstraintFunc,AfterErgo) \ + constraint(CMSOldPLABMinConstraintFunc,AfterMemoryInit) \ \ product(uintx, CMSOldPLABNumRefills, 4, \ "Nominal number of refills of CMS gen promotion LAB cache " \ @@ -1783,24 +1780,29 @@ product(double, FLSLargestBlockCoalesceProximity, 0.99, \ "CMS: the smaller the percentage the greater the coalescing " \ "force") \ + range(0.0, 1.0) \ \ product(double, CMSSmallCoalSurplusPercent, 1.05, \ "CMS: the factor by which to inflate estimated demand of small " \ "block sizes to prevent coalescing with an adjoining block") \ + range(0.0, DBL_MAX) \ \ product(double, CMSLargeCoalSurplusPercent, 0.95, \ "CMS: the factor by which to inflate estimated demand of large " \ "block sizes to prevent coalescing with an adjoining block") \ + range(0.0, DBL_MAX) \ \ product(double, CMSSmallSplitSurplusPercent, 1.10, \ "CMS: the factor by which to inflate estimated demand of small " \ "block sizes to prevent splitting to supply demand for smaller " \ "blocks") \ + range(0.0, DBL_MAX) \ \ product(double, CMSLargeSplitSurplusPercent, 1.00, \ "CMS: the factor by which to inflate estimated demand of large " \ "block sizes to prevent splitting to supply demand for smaller " \ "blocks") \ + range(0.0, DBL_MAX) \ \ product(bool, CMSExtrapolateSweep, false, \ "CMS: cushion for block demand during sweep") \ @@ -1828,9 +1830,11 @@ \ develop(intx, CMSDictionaryChoice, 0, \ "Use BinaryTreeDictionary as default in the CMS generation") \ + range(0, 2) \ \ product(uintx, CMSIndexedFreeListReplenish, 4, \ "Replenish an indexed free list with this number of chunks") \ + range(1, max_uintx) \ \ product(bool, CMSReplenishIntermediate, true, \ "Replenish all intermediate free-list caches") \ @@ -1845,14 +1849,15 @@ develop(bool, CMSOverflowEarlyRestoration, false, \ "Restore preserved marks early") \ \ - product(size_t, MarkStackSize, NOT_LP64(32*K) LP64_ONLY(4*M), \ - "Size of marking stack") \ - \ /* where does the range max value of (max_jint - 1) come from? */ \ product(size_t, MarkStackSizeMax, NOT_LP64(4*M) LP64_ONLY(512*M), \ "Maximum size of marking stack") \ range(1, (max_jint - 1)) \ \ + product(size_t, MarkStackSize, NOT_LP64(32*K) LP64_ONLY(4*M), \ + "Size of marking stack") \ + range(0, MarkStackSizeMax) \ + \ notproduct(bool, CMSMarkStackOverflowALot, false, \ "Simulate frequent marking stack / work queue overflow") \ \ @@ -1865,6 +1870,7 @@ \ product(intx, CMSMaxAbortablePrecleanTime, 5000, \ "Maximum time in abortable preclean (in milliseconds)") \ + range(0, max_intx) \ \ product(uintx, CMSAbortablePrecleanMinWorkPerIteration, 100, \ "Nominal minimum work per abortable preclean iteration") \ @@ -1872,6 +1878,7 @@ manageable(intx, CMSAbortablePrecleanWaitMillis, 100, \ "Time that we sleep between iterations when not given " \ "enough work per iteration") \ + range(0, max_intx) \ \ product(size_t, CMSRescanMultiple, 32, \ "Size (in cards) of CMS parallel rescan task") \ @@ -1978,6 +1985,8 @@ \ product(uintx, CMSWorkQueueDrainThreshold, 10, \ "Don't drain below this size per parallel worker/thief") \ + range(0, max_juint) \ + constraint(CMSWorkQueueDrainThresholdConstraintFunc,AfterErgo) \ \ manageable(intx, CMSWaitDuration, 2000, \ "Time in milliseconds that CMS thread waits for young GC") \ @@ -2234,9 +2243,11 @@ \ develop(intx, PSAdaptiveSizePolicyResizeVirtualSpaceAlot, -1, \ "Resize the virtual spaces of the young or old generations") \ + range(-1, 1) \ \ product(uintx, AdaptiveSizeThroughPutPolicy, 0, \ "Policy for changing generation size for throughput goals") \ + range(0, 1) \ \ develop(bool, PSAdjustTenuredGenForMinorPause, false, \ "Adjust tenured generation to achieve a minor pause goal") \ @@ -2308,9 +2319,12 @@ product(uintx, MaxGCPauseMillis, max_uintx, \ "Adaptive size policy maximum GC pause time goal in millisecond, "\ "or (G1 Only) the maximum GC time per MMU time slice") \ + range(1, max_uintx) \ + constraint(MaxGCPauseMillisConstraintFunc,AfterErgo) \ \ product(uintx, GCPauseIntervalMillis, 0, \ "Time slice for MMU specification") \ + constraint(GCPauseIntervalMillisConstraintFunc,AfterErgo) \ \ product(uintx, MaxGCMinorPauseMillis, max_uintx, \ "Adaptive size policy maximum GC minor pause time goal " \ @@ -2331,6 +2345,7 @@ \ product(uintx, MinSurvivorRatio, 3, \ "Minimum ratio of young generation/survivor space size") \ + range(3, max_uintx) \ \ product(uintx, InitialSurvivorRatio, 8, \ "Initial ratio of young generation/survivor space size") \ @@ -2354,6 +2369,7 @@ \ develop(uintx, AdaptiveSizePolicyGCTimeLimitThreshold, 5, \ "Number of consecutive collections before gc time limit fires") \ + range(1, max_uintx) \ \ product(bool, PrintAdaptiveSizePolicy, false, \ "Print information about AdaptiveSizePolicy") \ @@ -2453,6 +2469,7 @@ develop(intx, ConcGCYieldTimeout, 0, \ "If non-zero, assert that GC threads yield within this " \ "number of milliseconds") \ + range(0, max_intx) \ \ product(bool, PrintReferenceGC, false, \ "Print times spent handling reference objects during GC " \ @@ -2491,6 +2508,8 @@ product(size_t, InitialBootClassLoaderMetaspaceSize, \ NOT_LP64(2200*K) LP64_ONLY(4*M), \ "Initial size of the boot class loader data metaspace") \ + range(BytesPerWord, max_uintx) \ + constraint(InitialBootClassLoaderMetaspaceSizeConstraintFunc, AfterErgo)\ \ product(bool, TraceYoungGenTime, false, \ "Trace accumulated time for young collection") \ @@ -2567,6 +2586,7 @@ experimental(double, ObjectCountCutOffPercent, 0.5, \ "The percentage of the used heap that the instances of a class " \ "must occupy for the class to generate a trace event") \ + range(0.0, 100.0) \ \ /* GC log rotation setting */ \ \ @@ -3277,15 +3297,19 @@ /* gc parameters */ \ product(size_t, InitialHeapSize, 0, \ "Initial heap size (in bytes); zero means use ergonomics") \ + range(0, max_uintx) \ + constraint(InitialHeapSizeConstraintFunc,AfterErgo) \ \ product(size_t, MaxHeapSize, ScaleForWordSize(96*M), \ "Maximum heap size (in bytes)") \ + constraint(MaxHeapSizeConstraintFunc,AfterErgo) \ \ product(size_t, OldSize, ScaleForWordSize(4*M), \ "Initial tenured generation size (in bytes)") \ \ product(size_t, NewSize, ScaleForWordSize(1*M), \ "Initial new generation size (in bytes)") \ + constraint(NewSizeConstraintFunc,AfterErgo) \ \ product(size_t, MaxNewSize, max_uintx, \ "Maximum new generation size (in bytes), max_uintx means set " \ @@ -3295,12 +3319,23 @@ "Maximum size in bytes of objects allocated in DefNew " \ "generation; zero means no maximum") \ \ - product(size_t, TLABSize, 0, \ - "Starting TLAB size (in bytes); zero means set ergonomically") \ - \ product(size_t, MinTLABSize, 2*K, \ "Minimum allowed TLAB size (in bytes)") \ range(1, max_uintx) \ + constraint(MinTLABSizeConstraintFunc,AfterMemoryInit) \ + \ + product(size_t, TLABSize, 0, \ + "Starting TLAB size (in bytes); zero means set ergonomically") \ + constraint(TLABSizeConstraintFunc,AfterMemoryInit) \ + \ + product(size_t, YoungPLABSize, 4096, \ + "Size of young gen promotion LAB's (in HeapWords)") \ + constraint(YoungPLABSizeConstraintFunc,AfterMemoryInit) \ + \ + product(size_t, OldPLABSize, 1024, \ + "Size of old gen promotion LAB's (in HeapWords), or Number " \ + "of blocks to attempt to claim when refilling CMS LAB's") \ + constraint(OldPLABSizeConstraintFunc,AfterMemoryInit) \ \ product(uintx, TLABAllocationWeight, 35, \ "Allocation averaging weight") \ @@ -3321,9 +3356,12 @@ \ product(uintx, SurvivorRatio, 8, \ "Ratio of eden/survivor space size") \ + range(1, max_uintx-2) \ + constraint(SurvivorRatioConstraintFunc,AfterMemoryInit) \ \ product(uintx, NewRatio, 2, \ "Ratio of old/new generation sizes") \ + range(0, max_uintx-1) \ \ product_pd(size_t, NewSizeThreadIncrease, \ "Additional size added to desired new generation size per " \ @@ -3331,9 +3369,11 @@ \ product_pd(size_t, MetaspaceSize, \ "Initial size of Metaspaces (in bytes)") \ + constraint(MetaspaceSizeConstraintFunc,AfterErgo) \ \ product(size_t, MaxMetaspaceSize, max_uintx, \ "Maximum size of Metaspaces (in bytes)") \ + constraint(MaxMetaspaceSizeConstraintFunc,AfterErgo) \ \ product(size_t, CompressedClassSpaceSize, 1*G, \ "Maximum size of class area in Metaspace when compressed " \ @@ -3356,6 +3396,8 @@ \ product(intx, SoftRefLRUPolicyMSPerMB, 1000, \ "Number of milliseconds per MB of free space in the heap") \ + range(0, max_intx) \ + constraint(SoftRefLRUPolicyMSPerMBConstraintFunc,AfterMemoryInit) \ \ product(size_t, MinHeapDeltaBytes, ScaleForWordSize(128*K), \ "The minimum change in heap space due to GC (in bytes)") \ @@ -3387,6 +3429,7 @@ \ diagnostic(intx, VerifyGCLevel, 0, \ "Generation level at which to start +VerifyBefore/AfterGC") \ + range(0, 1) \ \ product(uintx, MaxTenuringThreshold, 15, \ "Maximum value for tenuring threshold") \ @@ -3445,6 +3488,7 @@ "before changing safepoint polling page to RO ") \ \ product(intx, SafepointSpinBeforeYield, 2000, "(Unstable)") \ + range(0, max_intx) \ \ product(bool, PSChunkLargeArrays, true, \ "Process large arrays in chunks") \ --- old/test/gc/arguments/TestG1HeapRegionSize.java 2015-08-20 09:29:52.181088579 -0700 +++ new/test/gc/arguments/TestG1HeapRegionSize.java 2015-08-20 09:29:52.073088583 -0700 @@ -27,40 +27,57 @@ * @bug 8021879 * @summary Verify that the flag G1HeapRegionSize is updated properly * @modules java.management/sun.management - * @run main/othervm -Xmx64m TestG1HeapRegionSize 1048576 - * @run main/othervm -XX:G1HeapRegionSize=2m -Xmx64m TestG1HeapRegionSize 2097152 - * @run main/othervm -XX:G1HeapRegionSize=3m -Xmx64m TestG1HeapRegionSize 2097152 - * @run main/othervm -XX:G1HeapRegionSize=64m -Xmx256m TestG1HeapRegionSize 33554432 + * @library /testlibrary + * @run main TestG1HeapRegionSize */ -import com.sun.management.HotSpotDiagnosticMXBean; -import com.sun.management.VMOption; -import java.lang.management.ManagementFactory; +import java.util.regex.Matcher; +import java.util.regex.Pattern; -public class TestG1HeapRegionSize { +import java.util.ArrayList; +import java.util.Arrays; - public static void main(String[] args) { - HotSpotDiagnosticMXBean diagnostic = - ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class); - - String expectedValue = getExpectedValue(args); - VMOption option = diagnostic.getVMOption("UseG1GC"); - if (option.getValue().equals("false")) { - System.out.println("Skipping this test. It is only a G1 test."); - return; - } +import jdk.test.lib.*; + +public class TestG1HeapRegionSize { - option = diagnostic.getVMOption("G1HeapRegionSize"); - if (!expectedValue.equals(option.getValue())) { - throw new RuntimeException("Wrong value for G1HeapRegionSize. Expected " + expectedValue + " but got " + option.getValue()); + private static void checkG1HeapRegionSize(String[] flags, int expectedValue, int exitValue) throws Exception { + ArrayList flagList = new ArrayList(); + flagList.addAll(Arrays.asList(flags)); + flagList.add("-XX:+UseG1GC"); + flagList.add("-XX:+PrintFlagsFinal"); + flagList.add("-version"); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(flagList.toArray(new String[0])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(exitValue); + + if (exitValue == 0) { + String stdout = output.getStdout(); + //System.out.println(stdout); + int flagValue = getFlagValue("G1HeapRegionSize", stdout); + if (flagValue != expectedValue) { + throw new RuntimeException("Wrong value for G1HeapRegionSize. Expected " + expectedValue + " but got " + flagValue); + } } } - private static String getExpectedValue(String[] args) { - if (args.length != 1) { - throw new RuntimeException("Wrong number of arguments. Expected 1 but got " + args.length); + private static int getFlagValue(String flag, String where) { + Matcher m = Pattern.compile(flag + "\\s+:?=\\s+\\d+").matcher(where); + if (!m.find()) { + throw new RuntimeException("Could not find value for flag " + flag + " in output string"); } - return args[0]; + String match = m.group(); + return Integer.parseInt(match.substring(match.lastIndexOf(" ") + 1, match.length())); } + public static void main(String args[]) throws Exception { + final int M = 1024 * 1024; + + checkG1HeapRegionSize(new String[] { "-Xmx64m" /* default is 1m */ }, 1*M, 0); + checkG1HeapRegionSize(new String[] { "-Xmx64m", "-XX:G1HeapRegionSize=2m" }, 2*M, 0); + checkG1HeapRegionSize(new String[] { "-Xmx64m", "-XX:G1HeapRegionSize=3m" }, 2*M, 0); + checkG1HeapRegionSize(new String[] { "-Xmx256m", "-XX:G1HeapRegionSize=32m" }, 32*M, 0); + checkG1HeapRegionSize(new String[] { "-Xmx256m", "-XX:G1HeapRegionSize=64m" }, 32*M, 1); + } } --- old/test/gc/arguments/TestHeapFreeRatio.java 2015-08-20 09:29:52.885088555 -0700 +++ new/test/gc/arguments/TestHeapFreeRatio.java 2015-08-20 09:29:52.781088558 -0700 @@ -72,7 +72,7 @@ output.shouldHaveExitValue(1); break; case COMBINATION_INVALID: - output.shouldContain("must be greater than or equal to MinHeapFreeRatio"); + output.shouldContain("must be less than or equal to MaxHeapFreeRatio"); output.shouldContain("Error"); output.shouldHaveExitValue(1); break; --- old/test/gc/arguments/TestInitialTenuringThreshold.java 2015-08-20 09:29:53.545088532 -0700 +++ new/test/gc/arguments/TestInitialTenuringThreshold.java 2015-08-20 09:29:53.441088535 -0700 @@ -39,6 +39,7 @@ public static void runWithThresholds(int initial, int max, boolean shouldfail) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UseParallelGC", "-XX:InitialTenuringThreshold=" + String.valueOf(initial), "-XX:MaxTenuringThreshold=" + String.valueOf(max), "-version" --- old/test/gc/arguments/TestObjectTenuringFlags.java 2015-08-20 09:29:54.245088507 -0700 +++ new/test/gc/arguments/TestObjectTenuringFlags.java 2015-08-20 09:29:54.105088512 -0700 @@ -157,7 +157,7 @@ if (tenuringFlags.length > 0) { Collections.addAll(vmOpts, tenuringFlags); } - Collections.addAll(vmOpts, "-XX:+PrintFlagsFinal", "-version"); + Collections.addAll(vmOpts, "-XX:+UseParallelGC", "-XX:+PrintFlagsFinal", "-version"); ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(vmOpts.toArray(new String[vmOpts.size()])); OutputAnalyzer output = new OutputAnalyzer(pb.start()); --- /dev/null 2015-08-19 11:52:37.744725272 -0700 +++ new/test/gc/arguments/TestG1ConcMarkStepDurationMillis.java 2015-08-20 09:29:54.769088489 -0700 @@ -0,0 +1,109 @@ +/* +* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 only, as +* published by the Free Software Foundation. +* +* This code is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* version 2 for more details (a copy is included in the LICENSE file that +* accompanied this code). +* +* You should have received a copy of the GNU General Public License version +* 2 along with this work; if not, write to the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +* +* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +* or visit www.oracle.com if you need additional information or have any +* questions. +*/ + +/* + * @test TestG1ConcMarkStepDurationMillis + * @key gc + * @summary Tests argument processing for double type flag, G1ConcMarkStepDurationMillis + * @library /testlibrary + * @modules java.base/sun.misc + * java.management + */ + +import jdk.test.lib.*; +import java.util.*; +import java.util.regex.*; + +public class TestG1ConcMarkStepDurationMillis { + + static final int PASS = 0; + static final int FAIL_IMPROPER_VALUE = 1; + static final int FAIL_OUT_RANGE = 2; + + static final String DOUBLE_1 = "1.0"; + static final String DOUBLE_MAX = "1.79e+308"; + + static final String DOUBLE_NEG_EXP = "1.0e-30"; + static final String NEG_DOUBLE_1 = "-1.0"; + + static final String DOUBLE_INF = "1.79e+309"; + static final String NEG_DOUBLE_INF = "-1.79e+309"; + static final String DOUBLE_NAN = "abe+309"; + static final String WRONG_DOUBLE_1 = "1.79e+308e"; + static final String WRONG_DOUBLE_2 = "1.79ee+308"; + + public static void main(String args[]) throws Exception { + // Pass cases + runG1ConcMarkStepDurationMillisTest(DOUBLE_1, PASS); + runG1ConcMarkStepDurationMillisTest(DOUBLE_MAX, PASS); + + // Fail cases: out of range + runG1ConcMarkStepDurationMillisTest(DOUBLE_NEG_EXP, FAIL_OUT_RANGE); + runG1ConcMarkStepDurationMillisTest(NEG_DOUBLE_1, FAIL_OUT_RANGE); + + // Fail cases: not double + runG1ConcMarkStepDurationMillisTest(DOUBLE_INF, FAIL_IMPROPER_VALUE); + runG1ConcMarkStepDurationMillisTest(NEG_DOUBLE_INF, FAIL_IMPROPER_VALUE); + runG1ConcMarkStepDurationMillisTest(DOUBLE_NAN, FAIL_IMPROPER_VALUE); + runG1ConcMarkStepDurationMillisTest(WRONG_DOUBLE_1, FAIL_IMPROPER_VALUE); + runG1ConcMarkStepDurationMillisTest(WRONG_DOUBLE_2, FAIL_IMPROPER_VALUE); + } + + private static void runG1ConcMarkStepDurationMillisTest(String expectedValue, int expectedResult) throws Exception { + List vmOpts = new ArrayList<>(); + + Collections.addAll(vmOpts, "-XX:+UseG1GC", "-XX:G1ConcMarkStepDurationMillis="+expectedValue, "-XX:+PrintFlagsFinal", "-version"); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(vmOpts.toArray(new String[vmOpts.size()])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + output.shouldHaveExitValue(expectedResult == PASS ? 0 : 1); + String stdout = output.getStdout(); + if (expectedResult == PASS) { + checkG1ConcMarkStepDurationMillisConsistency(stdout, expectedValue); + } else if (expectedResult == FAIL_IMPROPER_VALUE) { + output.shouldContain("Improperly specified VM option"); + } else if (expectedResult == FAIL_OUT_RANGE) { + output.shouldContain("outside the allowed range"); + } + } + + private static void checkG1ConcMarkStepDurationMillisConsistency(String output, String expectedValue) { + double actualValue = getDoubleValue("G1ConcMarkStepDurationMillis", output); + + if (Double.parseDouble(expectedValue) != actualValue) { + throw new RuntimeException( + "Actual G1ConcMarkStepDurationMillis(" + Double.toString(actualValue) + + ") is not equal to expected value(" + expectedValue + ")"); + } + } + + public static double getDoubleValue(String flag, String where) { + Matcher m = Pattern.compile(flag + "\\s+:?=\\s+\\d+").matcher(where); + if (!m.find()) { + throw new RuntimeException("Could not find value for flag " + flag + " in output string"); + } + String match = m.group(); + return Double.parseDouble(match.substring(match.lastIndexOf(" ") + 1, match.length())); + } +}