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   return JVMFlag::SUCCESS;
 140 }
 141 
 142 JVMFlag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose) {
 143   JVMFlag::Error status = CMSReservedAreaConstraintFunc("CMSRescanMultiple", value, verbose);
 144 
 145   if (status == JVMFlag::SUCCESS && UseConcMarkSweepGC) {
 146     // CMSParRemarkTask::do_dirty_card_rescan_tasks requires CompactibleFreeListSpace::rescan_task_size()
 147     // to be aligned to CardTable::card_size * BitsPerWord.
 148     // Note that rescan_task_size() will be aligned if CMSRescanMultiple is a multiple of 'HeapWordSize'
 149     // because rescan_task_size() is CardTable::card_size / HeapWordSize * BitsPerWord.
 150     if (value % HeapWordSize != 0) {
 151       JVMFlag::printError(verbose,
 152                           "CMSRescanMultiple (" SIZE_FORMAT ") must be "
 153                           "a multiple of " INT32_FORMAT "\n",
 154                           value, HeapWordSize);
 155       status = JVMFlag::VIOLATES_CONSTRAINT;
 156     }
 157   }
 158   return status;
 159 }
 160 
 161 JVMFlag::Error CMSConcMarkMultipleConstraintFunc(size_t value, bool verbose) {
 162   return CMSReservedAreaConstraintFunc("CMSConcMarkMultiple", value, verbose);
 163 }
 164 
 165 JVMFlag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose) {
 166   if (UseConcMarkSweepGC && (value <= CMSPrecleanNumerator)) {
 167     JVMFlag::printError(verbose,
 168                         "CMSPrecleanDenominator (" UINTX_FORMAT ") must be "
 169                         "strickly greater than CMSPrecleanNumerator (" UINTX_FORMAT ")\n",
 170                         value, CMSPrecleanNumerator);
 171     return JVMFlag::VIOLATES_CONSTRAINT;
 172   }
 173   return JVMFlag::SUCCESS;
 174 }
 175 
 176 JVMFlag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose) {
 177   if (UseConcMarkSweepGC && (value >= CMSPrecleanDenominator)) {
 178     JVMFlag::printError(verbose,
 179                         "CMSPrecleanNumerator (" UINTX_FORMAT ") must be "
 180                         "less than CMSPrecleanDenominator (" UINTX_FORMAT ")\n",
 181                         value, CMSPrecleanDenominator);
 182     return JVMFlag::VIOLATES_CONSTRAINT;
 183   }
 184   return JVMFlag::SUCCESS;
 185 }
 186 
 187 JVMFlag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose) {
 188   if (UseConcMarkSweepGC) {
 189     size_t max_capacity = CMSHeap::heap()->young_gen()->max_capacity();
 190     if (value > max_uintx - max_capacity) {
 191     JVMFlag::printError(verbose,
 192                         "CMSSamplingGrain (" UINTX_FORMAT ") must be "
 193                         "less than or equal to ergonomic maximum (" SIZE_FORMAT ")\n",
 194                         value, max_uintx - max_capacity);
 195     return JVMFlag::VIOLATES_CONSTRAINT;
 196     }
 197   }
 198   return JVMFlag::SUCCESS;
 199 }
 200 
 201 JVMFlag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose) {
 202   if (UseConcMarkSweepGC) {
 203     return ParallelGCThreadsAndCMSWorkQueueDrainThreshold(ParallelGCThreads, value, verbose);
 204   }
 205   return JVMFlag::SUCCESS;
 206 }
 207 
 208 JVMFlag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose) {
 209   // Skip for current default value.
 210   if (UseConcMarkSweepGC && FLAG_IS_CMDLINE(CMSBitMapYieldQuantum)) {
 211     // CMSBitMapYieldQuantum should be compared with mark bitmap size.
 212     ConcurrentMarkSweepGeneration* cms = CMSHeap::heap()->old_gen();
 213     size_t bitmap_size = cms->collector()->markBitMap()->sizeInWords();
 214 
 215     if (value > bitmap_size) {
 216       JVMFlag::printError(verbose,
 217                           "CMSBitMapYieldQuantum (" SIZE_FORMAT ") must "
 218                           "be less than or equal to bitmap size (" SIZE_FORMAT ") "
 219                           "whose size corresponds to the size of old generation of the Java heap\n",
 220                           value, bitmap_size);
 221       return JVMFlag::VIOLATES_CONSTRAINT;
 222     }
 223   }
 224   return JVMFlag::SUCCESS;
 225 }
 226 
 227 JVMFlag::Error OldPLABSizeConstraintFuncCMS(size_t value, bool verbose) {
 228   if (value == 0) {
 229     JVMFlag::printError(verbose,
 230                         "OldPLABSize (" SIZE_FORMAT ") must be greater than 0",
 231                         value);
 232     return JVMFlag::VIOLATES_CONSTRAINT;
 233   }
 234   // For CMS, OldPLABSize is the number of free blocks of a given size that are used when
 235   // replenishing the local per-worker free list caches.
 236   // For more details, please refer to Arguments::set_cms_and_parnew_gc_flags().
 237   return MaxPLABSizeBounds("OldPLABSize", value, verbose);
 238 }