1 /*
   2  * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include "precompiled.hpp"
  26 #include "gc/cms/jvmFlagConstraintsCMS.hpp"
  27 #include "gc/cms/concurrentMarkSweepGeneration.inline.hpp"
  28 #include "gc/shared/cardTableRS.hpp"
  29 #include "gc/shared/collectedHeap.hpp"
  30 #include "gc/shared/genCollectedHeap.hpp"
  31 #include "gc/shared/jvmFlagConstraintsGC.hpp"
  32 #include "memory/universe.hpp"
  33 #include "runtime/globals_extension.hpp"
  34 #include "utilities/globalDefinitions.hpp"
  35 
  36 static JVMFlag::Error ParallelGCThreadsAndCMSWorkQueueDrainThreshold(uint threads, uintx threshold, bool verbose) {
  37   // CMSWorkQueueDrainThreshold is verified to be less than max_juint
  38   if (UseConcMarkSweepGC && (threads > (uint)(max_jint / (uint)threshold))) {
  39     JVMFlag::printError(verbose,
  40                         "ParallelGCThreads (" UINT32_FORMAT ") or CMSWorkQueueDrainThreshold ("
  41                         UINTX_FORMAT ") is too large\n",
  42                         threads, threshold);
  43     return JVMFlag::VIOLATES_CONSTRAINT;
  44   }
  45   return JVMFlag::SUCCESS;
  46 }
  47 
  48 JVMFlag::Error ParallelGCThreadsConstraintFuncCMS(uint value, bool verbose) {
  49   // To avoid overflow at ParScanClosure::do_oop_work.
  50   if (UseConcMarkSweepGC && (value > (max_jint / 10))) {
  51     JVMFlag::printError(verbose,
  52                         "ParallelGCThreads (" UINT32_FORMAT ") must be "
  53                         "less than or equal to " UINT32_FORMAT " for CMS GC\n",
  54                         value, (max_jint / 10));
  55     return JVMFlag::VIOLATES_CONSTRAINT;
  56   }
  57   return ParallelGCThreadsAndCMSWorkQueueDrainThreshold(value, CMSWorkQueueDrainThreshold, verbose);
  58 }
  59 JVMFlag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose) {
  60   if (UseConcMarkSweepGC && (value > ((uintx)max_jint / (uintx)ParallelGCThreads))) {
  61     JVMFlag::printError(verbose,
  62                         "ParGCStridesPerThread (" UINTX_FORMAT ") must be "
  63                         "less than or equal to ergonomic maximum (" UINTX_FORMAT ")\n",
  64                         value, ((uintx)max_jint / (uintx)ParallelGCThreads));
  65     return JVMFlag::VIOLATES_CONSTRAINT;
  66   }
  67   return JVMFlag::SUCCESS;
  68 }
  69 
  70 JVMFlag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose) {
  71   if (UseConcMarkSweepGC) {
  72     // ParGCCardsPerStrideChunk should be compared with card table size.
  73     size_t heap_size = Universe::heap()->reserved_region().word_size();
  74     CardTableRS* ct = GenCollectedHeap::heap()->rem_set();
  75     size_t card_table_size = ct->cards_required(heap_size) - 1; // Valid card table size
  76 
  77     if ((size_t)value > card_table_size) {
  78       JVMFlag::printError(verbose,
  79                           "ParGCCardsPerStrideChunk (" INTX_FORMAT ") is too large for the heap size and "
  80                           "must be less than or equal to card table size (" SIZE_FORMAT ")\n",
  81                           value, card_table_size);
  82       return JVMFlag::VIOLATES_CONSTRAINT;
  83     }
  84 
  85     // ParGCCardsPerStrideChunk is used with n_strides(ParallelGCThreads*ParGCStridesPerThread)
  86     // from CardTableRS::process_stride(). Note that ParGCStridesPerThread is already checked
  87     // not to make an overflow with ParallelGCThreads from its constraint function.
  88     uintx n_strides = ParallelGCThreads * ParGCStridesPerThread;
  89     uintx ergo_max = max_uintx / n_strides;
  90     if ((uintx)value > ergo_max) {
  91       JVMFlag::printError(verbose,
  92                           "ParGCCardsPerStrideChunk (" INTX_FORMAT ") must be "
  93                           "less than or equal to ergonomic maximum (" UINTX_FORMAT ")\n",
  94                           value, ergo_max);
  95       return JVMFlag::VIOLATES_CONSTRAINT;
  96     }
  97   }
  98   return JVMFlag::SUCCESS;
  99 }
 100 
 101 JVMFlag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose) {
 102   JVMFlag::Error status = JVMFlag::SUCCESS;
 103 
 104   if (UseConcMarkSweepGC) {
 105     if (value > CMSOldPLABMax) {
 106       JVMFlag::printError(verbose,
 107                           "CMSOldPLABMin (" SIZE_FORMAT ") must be "
 108                           "less than or equal to CMSOldPLABMax (" SIZE_FORMAT ")\n",
 109                           value, CMSOldPLABMax);
 110       return JVMFlag::VIOLATES_CONSTRAINT;
 111     }
 112     status = MaxPLABSizeBounds("CMSOldPLABMin", value, verbose);
 113   }
 114   return status;
 115 }
 116 
 117 JVMFlag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose) {
 118   JVMFlag::Error status = JVMFlag::SUCCESS;
 119 
 120   if (UseConcMarkSweepGC) {
 121     status = MaxPLABSizeBounds("CMSOldPLABMax", value, verbose);
 122   }
 123   return status;
 124 }
 125 
 126 static JVMFlag::Error CMSReservedAreaConstraintFunc(const char* name, size_t value, bool verbose) {
 127   if (UseConcMarkSweepGC) {
 128     ConcurrentMarkSweepGeneration* cms = CMSHeap::heap()->old_gen();
 129     const size_t ergo_max = cms->cmsSpace()->max_flag_size_for_task_size();
 130     if (value > ergo_max) {
 131       JVMFlag::printError(verbose,
 132                           "%s (" SIZE_FORMAT ") must be "
 133                           "less than or equal to ergonomic maximum (" SIZE_FORMAT ") "
 134                           "which is based on the maximum size of the old generation of the Java heap\n",
 135                           name, value, ergo_max);
 136       return JVMFlag::VIOLATES_CONSTRAINT;
 137     }
 138   }
 139 
 140   return JVMFlag::SUCCESS;
 141 }
 142 
 143 JVMFlag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose) {
 144   JVMFlag::Error status = CMSReservedAreaConstraintFunc("CMSRescanMultiple", value, verbose);
 145 
 146   if (status == JVMFlag::SUCCESS && UseConcMarkSweepGC) {
 147     // CMSParRemarkTask::do_dirty_card_rescan_tasks requires CompactibleFreeListSpace::rescan_task_size()
 148     // to be aligned to CardTable::card_size * BitsPerWord.
 149     // Note that rescan_task_size() will be aligned if CMSRescanMultiple is a multiple of 'HeapWordSize'
 150     // because rescan_task_size() is CardTable::card_size / HeapWordSize * BitsPerWord.
 151     if (value % HeapWordSize != 0) {
 152       JVMFlag::printError(verbose,
 153                           "CMSRescanMultiple (" SIZE_FORMAT ") must be "
 154                           "a multiple of " SIZE_FORMAT "\n",
 155                           value, HeapWordSize);
 156       status = JVMFlag::VIOLATES_CONSTRAINT;
 157     }
 158   }
 159 
 160   return status;
 161 }
 162 
 163 JVMFlag::Error CMSConcMarkMultipleConstraintFunc(size_t value, bool verbose) {
 164   return CMSReservedAreaConstraintFunc("CMSConcMarkMultiple", value, verbose);
 165 }
 166 
 167 JVMFlag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose) {
 168   if (UseConcMarkSweepGC && (value <= CMSPrecleanNumerator)) {
 169     JVMFlag::printError(verbose,
 170                         "CMSPrecleanDenominator (" UINTX_FORMAT ") must be "
 171                         "strickly greater than CMSPrecleanNumerator (" UINTX_FORMAT ")\n",
 172                         value, CMSPrecleanNumerator);
 173     return JVMFlag::VIOLATES_CONSTRAINT;
 174   }
 175   return JVMFlag::SUCCESS;
 176 }
 177 
 178 JVMFlag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose) {
 179   if (UseConcMarkSweepGC && (value >= CMSPrecleanDenominator)) {
 180     JVMFlag::printError(verbose,
 181                         "CMSPrecleanNumerator (" UINTX_FORMAT ") must be "
 182                         "less than CMSPrecleanDenominator (" UINTX_FORMAT ")\n",
 183                         value, CMSPrecleanDenominator);
 184     return JVMFlag::VIOLATES_CONSTRAINT;
 185   }
 186   return JVMFlag::SUCCESS;
 187 }
 188 
 189 JVMFlag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose) {
 190   if (UseConcMarkSweepGC) {
 191     size_t max_capacity = CMSHeap::heap()->young_gen()->max_capacity();
 192     if (value > max_uintx - max_capacity) {
 193     JVMFlag::printError(verbose,
 194                         "CMSSamplingGrain (" UINTX_FORMAT ") must be "
 195                         "less than or equal to ergonomic maximum (" SIZE_FORMAT ")\n",
 196                         value, max_uintx - max_capacity);
 197     return JVMFlag::VIOLATES_CONSTRAINT;
 198     }
 199   }
 200   return JVMFlag::SUCCESS;
 201 }
 202 
 203 JVMFlag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose) {
 204   if (UseConcMarkSweepGC) {
 205     return ParallelGCThreadsAndCMSWorkQueueDrainThreshold(ParallelGCThreads, value, verbose);
 206   }
 207   return JVMFlag::SUCCESS;
 208 }
 209 
 210 JVMFlag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose) {
 211   // Skip for current default value.
 212   if (UseConcMarkSweepGC && FLAG_IS_CMDLINE(CMSBitMapYieldQuantum)) {
 213     // CMSBitMapYieldQuantum should be compared with mark bitmap size.
 214     ConcurrentMarkSweepGeneration* cms = CMSHeap::heap()->old_gen();
 215     size_t bitmap_size = cms->collector()->markBitMap()->sizeInWords();
 216 
 217     if (value > bitmap_size) {
 218       JVMFlag::printError(verbose,
 219                           "CMSBitMapYieldQuantum (" SIZE_FORMAT ") must "
 220                           "be less than or equal to bitmap size (" SIZE_FORMAT ") "
 221                           "whose size corresponds to the size of old generation of the Java heap\n",
 222                           value, bitmap_size);
 223       return JVMFlag::VIOLATES_CONSTRAINT;
 224     }
 225   }
 226   return JVMFlag::SUCCESS;
 227 }
 228 
 229 JVMFlag::Error OldPLABSizeConstraintFuncCMS(size_t value, bool verbose) {
 230   if (value == 0) {
 231     JVMFlag::printError(verbose,
 232                         "OldPLABSize (" SIZE_FORMAT ") must be greater than 0",
 233                         value);
 234     return JVMFlag::VIOLATES_CONSTRAINT;
 235   }
 236   // For CMS, OldPLABSize is the number of free blocks of a given size that are used when
 237   // replenishing the local per-worker free list caches.
 238   // For more details, please refer to Arguments::set_cms_and_parnew_gc_flags().
 239   return MaxPLABSizeBounds("OldPLABSize", value, verbose);
 240 }