1 /*
   2  * Copyright (c) 2016, 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 #include "precompiled.hpp"
  25 #include "gc/shared/collectorPolicy.hpp"
  26 #include "runtime/arguments.hpp"
  27 #include "runtime/globals_extension.hpp"
  28 #include "utilities/globalDefinitions.hpp"
  29 #include "utilities/macros.hpp"
  30 #include "unittest.hpp"
  31 
  32 class TestGenCollectorPolicy {
  33  public:
  34 
  35   class Executor {
  36    public:
  37     virtual void execute() = 0;
  38   };
  39 
  40   class UnaryExecutor : public Executor {
  41    protected:
  42     const size_t param;
  43    public:
  44     UnaryExecutor(size_t val) : param(val) { }
  45   };
  46 
  47   class BinaryExecutor : public Executor {
  48    protected:
  49     const size_t param1;
  50     const size_t param2;
  51    public:
  52     BinaryExecutor(size_t val1, size_t val2) : param1(val1), param2(val2) { }
  53   };
  54 
  55   class MinHeapSizeGuard {
  56    private:
  57     const size_t _stored_min_heap_size;
  58    public:
  59     MinHeapSizeGuard() : _stored_min_heap_size(Arguments::min_heap_size()) { }
  60     ~MinHeapSizeGuard() {
  61       Arguments::set_min_heap_size(_stored_min_heap_size);
  62     }
  63   };
  64 
  65   class TestWrapper {
  66    public:
  67     static void test(Executor* setter1, Executor* setter2, Executor* checker) {
  68       FLAG_GUARD(InitialHeapSize);
  69       FLAG_GUARD(MaxHeapSize);
  70       FLAG_GUARD(MaxNewSize);
  71       FLAG_GUARD(MinHeapDeltaBytes);
  72       FLAG_GUARD(NewSize);
  73       FLAG_GUARD(OldSize);
  74       MinHeapSizeGuard min_heap_size_guard;
  75 
  76       FLAG_SET_ERGO(size_t, InitialHeapSize, 100 * M);
  77       FLAG_SET_ERGO(size_t, OldSize, 4 * M);
  78       FLAG_SET_ERGO(size_t, NewSize, 1 * M);
  79       FLAG_SET_ERGO(size_t, MaxNewSize, 80 * M);
  80       Arguments::set_min_heap_size(40 * M);
  81 
  82       ASSERT_NO_FATAL_FAILURE(setter1->execute());
  83 
  84       if (setter2 != NULL) {
  85         ASSERT_NO_FATAL_FAILURE(setter2->execute());
  86       }
  87 
  88       ASSERT_NO_FATAL_FAILURE(checker->execute());
  89     }
  90     static void test(Executor* setter, Executor* checker) {
  91       test(setter, NULL, checker);
  92     }
  93   };
  94 
  95   class SetNewSizeErgo : public UnaryExecutor {
  96    public:
  97     SetNewSizeErgo(size_t param) : UnaryExecutor(param) { }
  98     void execute() {
  99       FLAG_SET_ERGO(size_t, NewSize, param);
 100     }
 101   };
 102 
 103   class CheckYoungMin : public UnaryExecutor {
 104    public:
 105     CheckYoungMin(size_t param) : UnaryExecutor(param) { }
 106     void execute() {
 107       MarkSweepPolicy msp;
 108       msp.initialize_all();
 109       ASSERT_LE(msp.min_young_size(), param);
 110     }
 111   };
 112 
 113   class CheckScaledYoungInitial : public Executor {
 114    public:
 115     void execute() {
 116       size_t initial_heap_size = InitialHeapSize;
 117       MarkSweepPolicy msp;
 118       msp.initialize_all();
 119 
 120       if (InitialHeapSize > initial_heap_size) {
 121         // InitialHeapSize was adapted by msp.initialize_all, e.g. due to alignment
 122         // caused by 64K page size.
 123         initial_heap_size = InitialHeapSize;
 124       }
 125 
 126       size_t expected = msp.scale_by_NewRatio_aligned(initial_heap_size);
 127       ASSERT_EQ(expected, msp.initial_young_size());
 128       ASSERT_EQ(expected, NewSize);
 129     }
 130   };
 131 
 132   class SetNewSizeCmd : public UnaryExecutor {
 133    public:
 134     SetNewSizeCmd(size_t param) : UnaryExecutor(param) { }
 135     void execute() {
 136       FLAG_SET_CMDLINE(size_t, NewSize, param);
 137     }
 138   };
 139 
 140   class CheckYoungInitial : public UnaryExecutor {
 141    public:
 142     CheckYoungInitial(size_t param) : UnaryExecutor(param) { }
 143     void execute() {
 144       MarkSweepPolicy msp;
 145       msp.initialize_all();
 146 
 147       ASSERT_EQ(param, msp.initial_young_size());
 148     }
 149   };
 150 
 151   class SetOldSizeCmd : public UnaryExecutor {
 152    public:
 153     SetOldSizeCmd(size_t param) : UnaryExecutor(param) { }
 154     void execute() {
 155       FLAG_SET_CMDLINE(size_t, OldSize, param);
 156     }
 157   };
 158 
 159   class SetMaxNewSizeCmd : public BinaryExecutor {
 160    public:
 161     SetMaxNewSizeCmd(size_t param1, size_t param2) : BinaryExecutor(param1, param2) { }
 162     void execute() {
 163       size_t heap_alignment = CollectorPolicy::compute_heap_alignment();
 164       size_t new_size_value = align_up(MaxHeapSize, heap_alignment)
 165               - param1 + param2;
 166       FLAG_SET_CMDLINE(size_t, MaxNewSize, new_size_value);
 167     }
 168   };
 169 
 170   class CheckOldMin : public UnaryExecutor {
 171    public:
 172     CheckOldMin(size_t param) : UnaryExecutor(param) { }
 173     void execute() {
 174       MarkSweepPolicy msp;
 175       msp.initialize_all();
 176       ASSERT_LE(msp.min_old_size(), param);
 177     }
 178   };
 179 
 180   class CheckOldInitial : public Executor {
 181    public:
 182     void execute() {
 183       size_t heap_alignment = CollectorPolicy::compute_heap_alignment();
 184 
 185       MarkSweepPolicy msp;
 186       msp.initialize_all();
 187 
 188       size_t expected_old_initial = align_up(InitialHeapSize, heap_alignment)
 189               - MaxNewSize;
 190 
 191       ASSERT_EQ(expected_old_initial, msp.initial_old_size());
 192     }
 193   };
 194 
 195   class CheckOldInitialMaxNewSize : public BinaryExecutor {
 196    public:
 197     CheckOldInitialMaxNewSize(size_t param1, size_t param2) : BinaryExecutor(param1, param2) { }
 198     void execute() {
 199       size_t heap_alignment = CollectorPolicy::compute_heap_alignment();
 200       size_t new_size_value = align_up(MaxHeapSize, heap_alignment)
 201               - param1 + param2;
 202 
 203       MarkSweepPolicy msp;
 204       msp.initialize_all();
 205 
 206       size_t expected_old_initial = align_up(MaxHeapSize, heap_alignment)
 207               - new_size_value;
 208 
 209       ASSERT_EQ(expected_old_initial, msp.initial_old_size());
 210     }
 211   };
 212 };
 213 
 214 
 215 // Testing that the NewSize flag is handled correct is hard because it
 216 // depends on so many other configurable variables. These tests only try to
 217 // verify that there are some basic rules for NewSize honored by the policies.
 218 
 219 // If NewSize has been ergonomically set, the collector policy
 220 // should use it for min
 221 TEST_VM(CollectorPolicy, young_min_ergo) {
 222   TestGenCollectorPolicy::SetNewSizeErgo setter(20 * M);
 223   TestGenCollectorPolicy::CheckYoungMin checker(20 * M);
 224 
 225   TestGenCollectorPolicy::TestWrapper::test(&setter, &checker);
 226 }
 227 
 228 // If NewSize has been ergonomically set, the collector policy
 229 // should use it for min but calculate the initial young size
 230 // using NewRatio.
 231 TEST_VM(CollectorPolicy, young_scaled_initial_ergo) {
 232   TestGenCollectorPolicy::SetNewSizeErgo setter(20 * M);
 233   TestGenCollectorPolicy::CheckScaledYoungInitial checker;
 234 
 235   TestGenCollectorPolicy::TestWrapper::test(&setter, &checker);
 236 }
 237 
 238 
 239 // Since a flag has been set with FLAG_SET_CMDLINE it
 240 // will be treated as it have been set on the command line for
 241 // the rest of the VM lifetime. This is an irreversible change and
 242 // could impact other tests so we use TEST_OTHER_VM
 243 TEST_OTHER_VM(CollectorPolicy, young_cmd) {
 244   // If NewSize is set on the command line, it should be used
 245   // for both min and initial young size if less than min heap.
 246   TestGenCollectorPolicy::SetNewSizeCmd setter(20 * M);
 247 
 248   TestGenCollectorPolicy::CheckYoungMin checker_min(20 * M);
 249   TestGenCollectorPolicy::TestWrapper::test(&setter, &checker_min);
 250 
 251   TestGenCollectorPolicy::CheckYoungInitial checker_initial(20 * M);
 252   TestGenCollectorPolicy::TestWrapper::test(&setter, &checker_initial);
 253 
 254   // If NewSize is set on command line, but is larger than the min
 255   // heap size, it should only be used for initial young size.
 256   TestGenCollectorPolicy::SetNewSizeCmd setter_large(80 * M);
 257   TestGenCollectorPolicy::CheckYoungInitial checker_large(80 * M);
 258   TestGenCollectorPolicy::TestWrapper::test(&setter_large, &checker_large);
 259 }
 260 
 261 // Since a flag has been set with FLAG_SET_CMDLINE it
 262 // will be treated as it have been set on the command line for
 263 // the rest of the VM lifetime. This is an irreversible change and
 264 // could impact other tests so we use TEST_OTHER_VM
 265 TEST_OTHER_VM(CollectorPolicy, old_cmd) {
 266   // If OldSize is set on the command line, it should be used
 267   // for both min and initial old size if less than min heap.
 268   TestGenCollectorPolicy::SetOldSizeCmd setter(20 * M);
 269 
 270   TestGenCollectorPolicy::CheckOldMin checker_min(20 * M);
 271   TestGenCollectorPolicy::TestWrapper::test(&setter, &checker_min);
 272 
 273   TestGenCollectorPolicy::CheckOldInitial checker_initial;
 274   TestGenCollectorPolicy::TestWrapper::test(&setter, &checker_initial);
 275 
 276   // If MaxNewSize is large, the maximum OldSize will be less than
 277   // what's requested on the command line and it should be reset
 278   // ergonomically.
 279   // We intentionally set MaxNewSize + OldSize > MaxHeapSize
 280   TestGenCollectorPolicy::SetOldSizeCmd setter_old_size(30 * M);
 281   TestGenCollectorPolicy::SetMaxNewSizeCmd setter_max_new_size(30 * M, 20 * M);
 282   TestGenCollectorPolicy::CheckOldInitialMaxNewSize checker_large(30 * M, 20 * M);
 283 
 284   TestGenCollectorPolicy::TestWrapper::test(&setter_old_size, &setter_max_new_size, &checker_large);
 285 }