/*
 * Written by Doug Lea with assistance from members of JCP JSR-166
 * Expert Group and released to the public domain, as explained at
 * http://creativecommons.org/publicdomain/zero/1.0/
 */


import java.util.concurrent.*;

public class CC2 {

    public static void main(String[] args) throws Exception {
        int n = 1 << 20;
        int steps = 1000;
        int nreps = 10;
        
        try {
            if (args.length > 0)
                n = Integer.parseInt(args[0]);
            if (args.length > 1)
                steps = Integer.parseInt(args[1]);
            if (args.length > 2)
                nreps = Integer.parseInt(args[2]);
        }

        catch (Exception e) {
            System.out.println("Usage: java CC2 <size> <steps> <reps>]");
            return;
        }
        
        //        new Driver(10, 256).invoke();
        //        new Driver(100, 1024).invoke();

        Driver driver = new Driver(n, steps);
        for (int rep = 0; rep < nreps; ++rep) {
            long startTime = System.nanoTime();
            driver.invoke();
            long time = System.nanoTime() - startTime;
            double secs = (time / (1000L * 1000L)) / 1000.0;

            System.out.println("Time: " + secs);
            driver.reinitialize();
            Thread.sleep(1000);
        }
        System.out.println(ForkJoinPool.commonPool());
    }

    static final class MTree extends CountedCompleter<Void> {
        final MTree q1, q2;
        int value;
        MTree(CountedCompleter<?> p, int n) { 
            super(p);
            int h = n >>> 1;
            if (h > 1) {
                q1 = new MTree(this, h);
                q2 = new MTree(this, n - h);
                setPendingCount(1);
            }
            else {
                q1 = null;
                q2 = null;
                value = ThreadLocalRandom.current().nextInt();
            }
        }

        public final void compute() {
            final MTree lt = q1, rt = q2;
            if (lt != null && rt != null) {
                lt.fork();
                rt.compute();
            }
            else {
                int r = value;
                r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift
                value = r;
                tryComplete();
            }
        }

        public final void onCompletion(CountedCompleter<?> caller) {
            final MTree lt = q1, rt = q2;
            if (lt != null && rt != null) {
                int v1 = lt.value, v2 = rt.value;
                value = (v1 >= v2) ? v1 : v2;
                setPendingCount(1); // reset
            }
        }

    }

    static final class Driver extends RecursiveAction {
        MTree root;
        final int size;
        final int steps;

        Driver(int size, int steps) {
            this.size = size;
            this.steps = steps;
            root = new MTree(null, size);
        }

        static void doCompute(MTree m, int s) {
            for (int i = 0; i < s; ++i) {
                m.setPendingCount(1);
                m.invoke();
                m.reinitialize();
            }
        }

        public void compute() {
            doCompute(root, steps);
            int d = root.value;
            if (d == 0)
                System.out.println("max after " + steps + " steps = " + d);
        }
    }


}
