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