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 TestStressIHOPMultiThread
26 * @bug 8148397
27 * @key stress
28 * @summary Stress test for IHOP
29 * @requires vm.gc.G1
30 * @run main/othervm/timeout=200 -Xmx128m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
31 *              -XX:+UseG1GC -XX:G1HeapRegionSize=1m -XX:+G1UseAdaptiveIHOP
32 *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread1.log
33 *              -Dtimeout=2 -DheapUsageMinBound=30 -DheapUsageMaxBound=80
34 *              -Dthreads=2 TestStressIHOPMultiThread
35 * @run main/othervm/timeout=200 -Xmx256m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
36 *              -XX:+UseG1GC -XX:G1HeapRegionSize=2m -XX:+G1UseAdaptiveIHOP
37 *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread2.log
38 *              -Dtimeout=2 -DheapUsageMinBound=60 -DheapUsageMaxBound=90
39 *              -Dthreads=3 TestStressIHOPMultiThread
40 * @run main/othervm/timeout=200 -Xmx256m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
41 *              -XX:+UseG1GC -XX:G1HeapRegionSize=4m -XX:-G1UseAdaptiveIHOP
42 *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread3.log
43 *              -Dtimeout=2 -DheapUsageMinBound=40 -DheapUsageMaxBound=90
44 *              -Dthreads=5 TestStressIHOPMultiThread
45 * @run main/othervm/timeout=200 -Xmx128m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
46 *              -XX:+UseG1GC -XX:G1HeapRegionSize=8m -XX:+G1UseAdaptiveIHOP
47 *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread4.log
48 *              -Dtimeout=2 -DheapUsageMinBound=20 -DheapUsageMaxBound=90
49 *              -Dthreads=10 TestStressIHOPMultiThread
50 * @run main/othervm/timeout=200 -Xmx512m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
51 *              -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:+G1UseAdaptiveIHOP
52 *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread5.log
53 *              -Dtimeout=2 -DheapUsageMinBound=20 -DheapUsageMaxBound=90
54 *              -Dthreads=17 TestStressIHOPMultiThread
55 */
56
57import java.util.ArrayList;
58import java.util.LinkedList;
59import java.util.List;
60
61/**
62 * Stress test for Adaptive IHOP. Starts a number of threads that fill and free
63 * specified amount of memory. Tests work with enabled IHOP logging.
64 *
65 */
66public class TestStressIHOPMultiThread {
67
68    public final static List<Object> GARBAGE = new LinkedList<>();
69
70    private final long HEAP_SIZE;
71    // Amount of memory to be allocated before iterations start
72    private final long HEAP_PREALLOC_SIZE;
73    // Amount of memory to be allocated and freed during iterations
74    private final long HEAP_ALLOC_SIZE;
75    private final int CHUNK_SIZE = 100000;
76
77    private final int TIMEOUT;
78    private final int THREADS;
79    private final int HEAP_LOW_BOUND;
80    private final int HEAP_HIGH_BOUND;
81
82    private volatile boolean running = true;
83    private final List<AllocationThread> threads;
84
85    public static void main(String[] args) throws InterruptedException {
86        new TestStressIHOPMultiThread().start();
87
88    }
89
90    TestStressIHOPMultiThread() {
91
92        TIMEOUT = Integer.getInteger("timeout") * 60;
93        THREADS = Integer.getInteger("threads");
94        HEAP_LOW_BOUND = Integer.getInteger("heapUsageMinBound");
95        HEAP_HIGH_BOUND = Integer.getInteger("heapUsageMaxBound");
96        HEAP_SIZE = Runtime.getRuntime().maxMemory();
97
98        HEAP_PREALLOC_SIZE = HEAP_SIZE * HEAP_LOW_BOUND / 100;
99        HEAP_ALLOC_SIZE = HEAP_SIZE * (HEAP_HIGH_BOUND - HEAP_LOW_BOUND) / 100;
100
101        threads = new ArrayList<>(THREADS);
102    }
103
104    public void start() throws InterruptedException {
105        fill();
106        createThreads();
107        waitForStress();
108        stressDone();
109        waitForFinish();
110    }
111
112    /**
113     * Fills HEAP_PREALLOC_SIZE bytes of garbage.
114     */
115    private void fill() {
116        long allocated = 0;
117        while (allocated < HEAP_PREALLOC_SIZE) {
118            GARBAGE.add(new byte[CHUNK_SIZE]);
119            allocated += CHUNK_SIZE;
120        }
121    }
122
123    /**
124     * Creates a number of threads which will fill and free amount of memory.
125     */
126    private void createThreads() {
127        for (int i = 0; i < THREADS; ++i) {
128            System.out.println("Create thread " + i);
129            AllocationThread thread =new TestStressIHOPMultiThread.AllocationThread(i, HEAP_ALLOC_SIZE / THREADS);
130            // Put reference to thread garbage into common garbage for avoiding possible optimization.
131            GARBAGE.add(thread.getList());
132            threads.add(thread);
133        }
134        threads.forEach(t -> t.start());
135    }
136
137    /**
138     * Wait each thread for finishing
139     */
140    private void waitForFinish() {
141        threads.forEach(thread -> {
142            thread.silentJoin();
143        });
144    }
145
146    private boolean isRunning() {
147        return running;
148    }
149
150    private void stressDone() {
151        running = false;
152    }
153
154    private void waitForStress() throws InterruptedException {
155        Thread.sleep(TIMEOUT * 1000);
156    }
157
158    private class AllocationThread extends Thread {
159
160        private final List<Object> garbage;
161
162        private final long amountOfGarbage;
163        private final int threadId;
164
165        public AllocationThread(int id, long amount) {
166            super("Thread " + id);
167            threadId = id;
168            amountOfGarbage = amount;
169            garbage = new LinkedList<>();
170        }
171
172        /**
173         * Returns list of garbage.
174         * @return List with thread garbage.
175         */
176        public List<Object> getList(){
177            return garbage;
178        }
179
180        @Override
181        public void run() {
182            System.out.println("Start the thread " + threadId);
183            while (TestStressIHOPMultiThread.this.isRunning()) {
184                allocate(amountOfGarbage);
185                free();
186            }
187        }
188
189        private void silentJoin() {
190            System.out.println("Join the thread " + threadId);
191            try {
192                join();
193            } catch (InterruptedException ie) {
194                throw new RuntimeException(ie);
195            }
196        }
197
198        /**
199         * Allocates thread local garbage
200         */
201        private void allocate(long amount) {
202            long allocated = 0;
203            while (allocated < amount && TestStressIHOPMultiThread.this.isRunning()) {
204                garbage.add(new byte[CHUNK_SIZE]);
205                allocated += CHUNK_SIZE;
206            }
207        }
208
209        /**
210         * Frees thread local garbage
211         */
212        private void free() {
213            garbage.clear();
214        }
215    }
216}
217