/*
 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

 /*
 * @test TestStressIHOPMultiThread
 * @bug 8148397
 * @key stress
 * @summary Stress test for IHOP
 * @requires vm.gc=="G1" | vm.gc=="null"
 * @run main/othervm/timeout=200 -Xmx128m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
 *              -XX:+UseG1GC -XX:G1HeapRegionSize=1m -XX:+G1UseAdaptiveIHOP
 *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread1.log
 *              -Dtimeout=2 -DheapUsageMinBound=30 -DheapUsageMaxBound=80
 *              -Dthreads=2 TestStressIHOPMultiThread
 * @run main/othervm/timeout=200 -Xmx256m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
 *              -XX:+UseG1GC -XX:G1HeapRegionSize=2m -XX:+G1UseAdaptiveIHOP
 *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread2.log
 *              -Dtimeout=2 -DheapUsageMinBound=60 -DheapUsageMaxBound=90
 *              -Dthreads=3 TestStressIHOPMultiThread
 * @run main/othervm/timeout=200 -Xmx256m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
 *              -XX:+UseG1GC -XX:G1HeapRegionSize=4m -XX:-G1UseAdaptiveIHOP
 *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread3.log
 *              -Dtimeout=2 -DheapUsageMinBound=40 -DheapUsageMaxBound=90
 *              -Dthreads=5 TestStressIHOPMultiThread
 * @run main/othervm/timeout=200 -Xmx128m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
 *              -XX:+UseG1GC -XX:G1HeapRegionSize=8m -XX:+G1UseAdaptiveIHOP
 *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread4.log
 *              -Dtimeout=2 -DheapUsageMinBound=20 -DheapUsageMaxBound=90
 *              -Dthreads=10 TestStressIHOPMultiThread
 * @run main/othervm/timeout=200 -Xmx512m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
 *              -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:+G1UseAdaptiveIHOP
 *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread5.log
 *              -Dtimeout=2 -DheapUsageMinBound=20 -DheapUsageMaxBound=90
 *              -Dthreads=17 TestStressIHOPMultiThread
 */

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * Stress test for Adaptive IHOP. Starts a number of threads that fill and free
 * specified amount of memory. Tests work with enabled IHOP logging.
 *
 */
public class TestStressIHOPMultiThread {

    public final static List<Object> GARBAGE = new LinkedList<>();

    private final long HEAP_SIZE;
    // Amount of memory to be allocated before iterations start
    private final long HEAP_PREALLOC_SIZE;
    // Amount of memory to be allocated and freed during iterations
    private final long HEAP_ALLOC_SIZE;
    private final int CHUNK_SIZE = 100000;

    private final int TIMEOUT;
    private final int THREADS;
    private final int HEAP_LOW_BOUND;
    private final int HEAP_HIGH_BOUND;

    private volatile boolean running = true;
    private final List<AllocationThread> threads;

    public static void main(String[] args) throws InterruptedException {
        new TestStressIHOPMultiThread().start();

    }

    TestStressIHOPMultiThread() {

        TIMEOUT = Integer.getInteger("timeout") * 60;
        THREADS = Integer.getInteger("threads");
        HEAP_LOW_BOUND = Integer.getInteger("heapUsageMinBound");
        HEAP_HIGH_BOUND = Integer.getInteger("heapUsageMaxBound");
        HEAP_SIZE = Runtime.getRuntime().maxMemory();

        HEAP_PREALLOC_SIZE = HEAP_SIZE * HEAP_LOW_BOUND / 100;
        HEAP_ALLOC_SIZE = HEAP_SIZE * (HEAP_HIGH_BOUND - HEAP_LOW_BOUND) / 100;

        threads = new ArrayList<>(THREADS);
    }

    public void start() throws InterruptedException {
        fill();
        createThreads();
        waitForStress();
        stressDone();
        waitForFinish();
    }

    /**
     * Fills HEAP_PREALLOC_SIZE bytes of garbage.
     */
    private void fill() {
        long allocated = 0;
        while (allocated < HEAP_PREALLOC_SIZE) {
            GARBAGE.add(new byte[CHUNK_SIZE]);
            allocated += CHUNK_SIZE;
        }
    }

    /**
     * Creates a number of threads which will fill and free amount of memory.
     */
    private void createThreads() {
        for (int i = 0; i < THREADS; ++i) {
            System.out.println("Create thread " + i);
            AllocationThread thread =new TestStressIHOPMultiThread.AllocationThread(i, HEAP_ALLOC_SIZE / THREADS);
            // Put reference to thread garbage into common garbage for avoiding possible optimization.
            GARBAGE.add(thread.getList());
            threads.add(thread);
        }
        threads.forEach(t -> t.start());
    }

    /**
     * Wait each thread for finishing
     */
    private void waitForFinish() {
        threads.forEach(thread -> {
            thread.silentJoin();
        });
    }

    private boolean isRunning() {
        return running;
    }

    private void stressDone() {
        running = false;
    }

    private void waitForStress() throws InterruptedException {
        Thread.sleep(TIMEOUT * 1000);
    }

    private class AllocationThread extends Thread {

        private final List<Object> garbage;

        private final long amountOfGarbage;
        private final int threadId;

        public AllocationThread(int id, long amount) {
            super("Thread " + id);
            threadId = id;
            amountOfGarbage = amount;
            garbage = new LinkedList<>();
        }

        /**
         * Returns list of garbage.
         * @return List with thread garbage.
         */
        public List<Object> getList(){
            return garbage;
        }

        @Override
        public void run() {
            System.out.println("Start the thread " + threadId);
            while (TestStressIHOPMultiThread.this.isRunning()) {
                allocate(amountOfGarbage);
                free();
            }
        }

        private void silentJoin() {
            System.out.println("Join the thread " + threadId);
            try {
                join();
            } catch (InterruptedException ie) {
                throw new RuntimeException(ie);
            }
        }

        /**
         * Allocates thread local garbage
         */
        private void allocate(long amount) {
            long allocated = 0;
            while (allocated < amount && TestStressIHOPMultiThread.this.isRunning()) {
                garbage.add(new byte[CHUNK_SIZE]);
                allocated += CHUNK_SIZE;
            }
        }

        /**
         * Frees thread local garbage
         */
        private void free() {
            garbage.clear();
        }
    }
}
