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  /*
25  * @test TestIHOPErgo
26  * @bug 8148397
27  * @key stress
28  * @summary Test checks that behavior of Adaptive and Static IHOP at concurrent cycle initiation
29  * @requires vm.gc.G1
30  * @requires !vm.flightRecorder
31  * @requires vm.opt.ExplicitGCInvokesConcurrent != true
32  * @requires vm.opt.MaxGCPauseMillis == "null"
33  * @library /test/lib /
34  * @modules java.base/jdk.internal.misc
35  * @modules java.management
36  * @run driver/timeout=480 gc.g1.ihop.TestIHOPErgo
37  */
38 package gc.g1.ihop;
39 
40 import java.util.ArrayList;
41 import java.util.Collections;
42 import java.util.LinkedList;
43 import java.util.List;
44 
45 import jdk.test.lib.process.OutputAnalyzer;
46 import jdk.test.lib.process.ProcessTools;
47 
48 import gc.g1.ihop.lib.IhopUtils;
49 
50 /**
51  * The test starts the AppIHOP multiple times varying settings of MaxHeapSize.
52  * The test parses GC log from AppIHOP to check:
53  * - occupancy is not less than threshold for Adaptive and Static IHOP at
54  * concurrent cycle initiation
55  * - Adaptive IHOP prediction was started during AppIHOP executing
56  * - log contains ergonomic messages in log
57  */
58 public class TestIHOPErgo {
59 
60     // Common GC tune and logging options for test.
61     private final static String[] COMMON_OPTIONS = {
62         "-XX:+UnlockExperimentalVMOptions",
63         "-XX:G1MixedGCLiveThresholdPercent=100",
64         "-XX:G1HeapWastePercent=0",
65         "-XX:MaxGCPauseMillis=30000",
66         "-XX:G1MixedGCCountTarget=1",
67         "-XX:+UseG1GC",
68         "-XX:G1HeapRegionSize=1m",
69         "-XX:+G1UseAdaptiveIHOP",
70         "-Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug",
71         "-XX:+AlwaysTenure",
72         "-XX:G1AdaptiveIHOPNumInitialSamples=1",
73         "-XX:InitiatingHeapOccupancyPercent=30"
74     };
75 
main(String[] args)76     public static void main(String[] args) throws Throwable {
77 
78         // heap size MB, sleep time for allocator, true/false for adaptive/static
79         runTest(64, 0, false);
80         runTest(64, 100, false);
81         runTest(128, 100, false);
82         runTest(256, 50, false);
83         runTest(512, 30, false);
84         runTest(64, 50, true);
85         runTest(128, 200, true);
86         runTest(256, 100, true);
87         runTest(512, 50, true);
88     }
89 
90     /**
91      * Runs AppIHOP in separate VM and checks GC log.
92      *
93      * @param heapSize       heap size
94      * @param sleepTime      sleep time between memory allocations.
95      * @param isIhopAdaptive true forAdaptive IHOP, false for Static
96      *
97      * @throws Throwable
98      */
runTest(int heapSize, int sleepTime, boolean isIhopAdaptive)99     private static void runTest(int heapSize, int sleepTime, boolean isIhopAdaptive) throws Throwable {
100         System.out.println("IHOP test:");
101         System.out.println("  MaxHeapSize : " + heapSize);
102 
103         List<String> options = new ArrayList<>();
104         Collections.addAll(options,
105                 "-Dheap.size=" + heapSize,
106                 "-Dsleep.time=" + sleepTime,
107                 "-XX:MaxHeapSize=" + heapSize + "M",
108                 "-XX:NewSize=" + heapSize / 8 + "M",
109                 "-XX:MaxNewSize=" + heapSize / 8 + "M",
110                 "-XX:InitialHeapSize=" + heapSize + "M",
111                 "-XX:" + (isIhopAdaptive ? "+" : "-") + "G1UseAdaptiveIHOP"
112         );
113 
114         Collections.addAll(options, COMMON_OPTIONS);
115         options.add(AppIHOP.class.getName());
116         OutputAnalyzer out = executeTest(options);
117 
118         // Checks that log contains message which indicates that IHOP prediction is active
119         if (isIhopAdaptive) {
120             IhopUtils.checkAdaptiveIHOPWasActivated(out);
121         }
122         // Checks that log contains messages which indicates that VM initiates/checks heap occupancy
123         // and tries to start concurrent cycle.
124         IhopUtils.checkErgoMessagesExist(out);
125 
126         // Checks threshold and occupancy values
127         IhopUtils.checkIhopLogValues(out);
128     }
129 
executeTest(List<String> options)130     private static OutputAnalyzer executeTest(List<String> options) throws Throwable, RuntimeException {
131         OutputAnalyzer out = ProcessTools.executeTestJvm(options);
132         if (out.getExitValue() != 0) {
133             System.out.println(out.getOutput());
134             throw new RuntimeException("AppIHOP failed with exit code" + out.getExitValue());
135         }
136         return out;
137     }
138 
139     /**
140      * The AppIHOP fills 60% of heap and allocates and frees 30% of existing
141      * heap 'iterations' times to achieve IHOP activation. To be executed in
142      * separate VM. Expected properties:
143      * heap.size - heap size which is used to calculate amount of memory
144      *             to be allocated and freed
145      * sleep.time - short pause between filling each MB
146      */
147     public static class AppIHOP {
148 
149         public final static LinkedList<Object> GARBAGE = new LinkedList<>();
150 
151         private final int ITERATIONS = 10;
152         private final int OBJECT_SIZE = 100000;
153         // 60% of the heap will be filled before test cycles.
154         // 30% of the heap will be filled and freed during test cycle.
155         private final long HEAP_PREALLOC_PCT = 60;
156         private final long HEAP_ALLOC_PCT = 30;
157         private final long HEAP_SIZE;
158         // Amount of memory to be allocated before iterations start
159         private final long HEAP_PREALLOC_SIZE;
160         // Amount of memory to be allocated and freed during iterations
161         private final long HEAP_ALLOC_SIZE;
162         private final int SLEEP_TIME;
163 
main(String[] args)164         public static void main(String[] args) throws InterruptedException {
165             new AppIHOP().start();
166         }
167 
AppIHOP()168         AppIHOP() {
169             HEAP_SIZE = Integer.getInteger("heap.size") * 1024 * 1024;
170             SLEEP_TIME = Integer.getInteger("sleep.time");
171 
172             HEAP_PREALLOC_SIZE = HEAP_SIZE * HEAP_PREALLOC_PCT / 100;
173             HEAP_ALLOC_SIZE = HEAP_SIZE * HEAP_ALLOC_PCT / 100;
174         }
175 
start()176         public void start() throws InterruptedException {
177             fill(HEAP_PREALLOC_SIZE);
178             fillAndFree(HEAP_ALLOC_SIZE, ITERATIONS);
179         }
180 
181         /**
182          * Fills allocationSize bytes of garbage.
183          *
184          * @param allocationSize amount of garbage
185          */
fill(long allocationSize)186         private void fill(long allocationSize) {
187             long allocated = 0;
188             while (allocated < allocationSize) {
189                 GARBAGE.addFirst(new byte[OBJECT_SIZE]);
190                 allocated += OBJECT_SIZE;
191             }
192         }
193 
194         /**
195          * Allocates allocationSize bytes of garbage. Performs a short pauses
196          * during allocation. Frees allocated garbage.
197          *
198          * @param allocationSize amount of garbage per iteration
199          * @param iterations     iteration count
200          *
201          * @throws InterruptedException
202          */
fillAndFree(long allocationSize, int iterations)203         private void fillAndFree(long allocationSize, int iterations) throws InterruptedException {
204 
205             for (int i = 0; i < iterations; ++i) {
206                 System.out.println("Iteration:" + i);
207                 long allocated = 0;
208                 long counter = 0;
209                 while (allocated < allocationSize) {
210                     GARBAGE.addFirst(new byte[OBJECT_SIZE]);
211                     allocated += OBJECT_SIZE;
212                     counter += OBJECT_SIZE;
213                     if (counter > 1024 * 1024) {
214                         counter = 0;
215                         if (SLEEP_TIME != 0) {
216                             Thread.sleep(SLEEP_TIME);
217                         }
218                     }
219                 }
220                 long removed = 0;
221                 while (removed < allocationSize) {
222                     GARBAGE.removeLast();
223                     removed += OBJECT_SIZE;
224                 }
225             }
226         }
227     }
228 }
229