/*
 * 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.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;

public class FJManySmallSubmissions {
    static final long NPS = (1000L * 1000 * 1000);
    //    static final ForkJoinPool fjp = new ForkJoinPool();
    static final ForkJoinPool fjp = ForkJoinPool.commonPool();

    public static void main(String[] args) throws Exception {
        int ntasks = 1 << 18;
        int nbuf = 256;
        int nc = 8;
        int arg = 1;
        int reps = 20;
        Client[] cs = new Client[nc];
        for (int k = 0; k < reps; ++k) {
            for (int i = 0; i < nc; ++i)
                cs[i] = new Client(ntasks, arg, nbuf);
            long last = System.nanoTime();
            for (int i = 0; i < nc; ++i)
                cs[i].start();
            int r = 0;
            for (int i = 0; i < nc; ++i) {
                Client t = cs[i];
                t.join();
                r += t.result;
            }
            double elapsed = elapsedTime(last);
            System.out.printf("time:  %7.3f  ", elapsed);
            System.out.println(fjp);
            if (r < ntasks * nc * arg)
                throw new Error();
        }
        /*
        for (int i = 0; i < 100; ++i) { // check stability
            Thread.sleep(1000);
            System.out.println(fjp);
        }
        */
    }

    static double elapsedTime(long startTime) {
        return (double)(System.nanoTime() - startTime) / NPS;
    }

    static final class Task extends RecursiveAction {
        final int number;
        int result;
        Task(int n)  { number = n; }
        public void compute() {
            int n = number;
            if (n <= 1)
                result = n;
            else {
                int k = n >>> 1;
                Task rt = new Task(k);
                rt.fork();
                Task lt = new Task(n - k);
                lt.compute();
                rt.join();
                result = lt.result + rt.result;
            }
        }
    }

    static final class Client extends Thread {
        final int ntasks;
        final int arg;
        final int nbuf;
        volatile int result;
        Client(int ntasks, int arg, int nbuf) {
            this.ntasks = ntasks;
            this.arg = arg;
            this.nbuf = nbuf;
        }
        public void run() {
            Task[] buf = new Task[nbuf];
            int n = ntasks;
            int a = arg;
            while (n > 0) {
                for (int i = 0; i < nbuf; ++i)
                    (buf[i] = new Task(a + (i & 1))).fork();
                int r = 0;
                for (int i = 0; i < nbuf; ++i) {
                    Task t = buf[i];
                    t.join();
                    r += t.result;
                }
                result += r;
                n -= nbuf;
            }
        }
    }
}

